Drop GLcontext typedef and use struct gl_context instead
[mesa.git] / src / mesa / drivers / dri / common / vblank.c
index 094950d36268a6e2821f3bae854591a02f3fd195..cb98dd0b3a38a8396cb64b0d6652e610c55e700d 100644 (file)
  *    Ian Romanick <idr@us.ibm.com>
  */
 
-#include "glheader.h"
+#include "main/glheader.h"
 #include "xf86drm.h"
-#include "mtypes.h"
-#include "macros.h"
-#include "dd.h"
+#include "main/mtypes.h"
+#include "main/macros.h"
+#include "main/dd.h"
 #include "vblank.h"
 #include "xmlpool.h"
 
+static unsigned int msc_to_vblank(__DRIdrawable * dPriv, int64_t msc)
+{
+   return (unsigned int)(msc - dPriv->msc_base + dPriv->vblank_base);
+}
+
+static int64_t vblank_to_msc(__DRIdrawable * dPriv, unsigned int vblank)
+{
+   return (int64_t)(vblank - dPriv->vblank_base + dPriv->msc_base);
+}
+
 
 /****************************************************************************/
 /**
@@ -41,7 +51,7 @@
  *
  * Stores the 64-bit count of vertical refreshes since some (arbitrary)
  * point in time in \c count.  Unless the value wraps around, which it
- * may, it will never decrease.
+ * may, it will never decrease for a given drawable.
  *
  * \warning This function is called from \c glXGetVideoSyncSGI, which expects
  * a \c count of type \c unsigned (32-bit), and \c glXGetSyncValuesOML, which 
  * currently always returns a \c sequence of type \c unsigned.
  *
  * \param priv   Pointer to the DRI screen private struct.
+ * \param dPriv  Pointer to the DRI drawable private struct
  * \param count  Storage to hold MSC counter.
  * \return       Zero is returned on success.  A negative errno value
  *               is returned on failure.
  */
-int driGetMSC32( __DRIscreenPrivate * priv, int64_t * count )
+int driDrawableGetMSC32( __DRIscreen * priv,
+                        __DRIdrawable * dPriv,
+                        int64_t * count)
 {
    drmVBlank vbl;
    int ret;
@@ -62,14 +75,21 @@ int driGetMSC32( __DRIscreenPrivate * priv, int64_t * count )
 
    vbl.request.type = DRM_VBLANK_RELATIVE;
    vbl.request.sequence = 0;
+   if ( dPriv && dPriv->vblFlags & VBLANK_FLAG_SECONDARY )
+      vbl.request.type |= DRM_VBLANK_SECONDARY;
 
    ret = drmWaitVBlank( priv->fd, &vbl );
-   *count = (int64_t)vbl.reply.sequence;
+
+   if (dPriv) {
+      *count = vblank_to_msc(dPriv, vbl.reply.sequence);
+   } else {
+      /* Old driver (no knowledge of drawable MSC callback) */
+      *count = vbl.reply.sequence;
+   }
 
    return ret;
 }
 
-
 /****************************************************************************/
 /**
  * Wait for a specified refresh count.  This implements most of the
@@ -102,7 +122,7 @@ int driGetMSC32( __DRIscreenPrivate * priv, int64_t * count )
  * \return            Zero on success or \c GLX_BAD_CONTEXT on failure.
  */
 
-int driWaitForMSC32( __DRIdrawablePrivate *priv,
+int driWaitForMSC32( __DRIdrawable *priv,
                     int64_t target_msc, int64_t divisor, int64_t remainder,
                     int64_t * msc )
 {
@@ -110,9 +130,8 @@ int driWaitForMSC32( __DRIdrawablePrivate *priv,
 
 
    if ( divisor != 0 ) {
-      unsigned int target = (unsigned int)target_msc;
-      unsigned int next = target;
-      unsigned int r;
+      int64_t next = target_msc;
+      int64_t r;
       int dont_wait = (target_msc == 0);
 
       do {
@@ -122,7 +141,9 @@ int driWaitForMSC32( __DRIdrawablePrivate *priv,
           */
          vbl.request.type = dont_wait ? DRM_VBLANK_RELATIVE :
                                         DRM_VBLANK_ABSOLUTE;
-         vbl.request.sequence = next;
+         vbl.request.sequence = next ? msc_to_vblank(priv, next) : 0;
+        if ( priv->vblFlags & VBLANK_FLAG_SECONDARY )
+           vbl.request.type |= DRM_VBLANK_SECONDARY;
 
         if ( drmWaitVBlank( priv->driScreenPriv->fd, &vbl ) != 0 ) {
            /* FIXME: This doesn't seem like the right thing to return here.
@@ -130,9 +151,11 @@ int driWaitForMSC32( __DRIdrawablePrivate *priv,
            return GLX_BAD_CONTEXT;
         }
 
-         dont_wait = 0;
-         if (target_msc != 0 && vbl.reply.sequence == target)
+        *msc = vblank_to_msc(priv, vbl.reply.sequence);
+
+         if (!dont_wait && *msc == next)
             break;
+         dont_wait = 0;
 
          /* Assuming the wait-done test fails, the next refresh to wait for
           * will be one that satisfies (MSC % divisor) == remainder.  The
@@ -141,11 +164,12 @@ int driWaitForMSC32( __DRIdrawablePrivate *priv,
           * If this refresh has already happened, we add divisor to obtain 
           * the next refresh after the current one that will satisfy it.
           */
-         r = (vbl.reply.sequence % (unsigned int)divisor);
-         next = (vbl.reply.sequence - r + (unsigned int)remainder);
-         if (next <= vbl.reply.sequence) next += (unsigned int)divisor;
+         r = ((uint64_t)*msc % divisor);
+         next = (*msc - r + remainder);
+         if (next <= *msc)
+           next += divisor;
 
-      } while ( r != (unsigned int)remainder );
+      } while (r != remainder);
    }
    else {
       /* If the \c divisor is zero, just wait until the MSC is greater
@@ -153,7 +177,10 @@ int driWaitForMSC32( __DRIdrawablePrivate *priv,
        */
 
       vbl.request.type = DRM_VBLANK_ABSOLUTE;
-      vbl.request.sequence = target_msc;
+      vbl.request.sequence = target_msc ? msc_to_vblank(priv, target_msc) : 0;
+
+      if ( priv->vblFlags & VBLANK_FLAG_SECONDARY )
+        vbl.request.type |= DRM_VBLANK_SECONDARY;
 
       if ( drmWaitVBlank( priv->driScreenPriv->fd, &vbl ) != 0 ) {
         /* FIXME: This doesn't seem like the right thing to return here.
@@ -162,8 +189,8 @@ int driWaitForMSC32( __DRIdrawablePrivate *priv,
       }
    }
 
-   *msc  = (target_msc & 0xffffffff00000000LL);
-   *msc |= vbl.reply.sequence;
+   *msc = vblank_to_msc(priv, vbl.reply.sequence);
+
    if ( *msc < target_msc ) {
       *msc += 0x0000000100000000LL;
    }
@@ -214,7 +241,7 @@ GLuint driGetDefaultVBlankFlags( const driOptionCache *optionCache )
  * the first time the \c drmWaitVBlank fails.  If \c drmWaitVBlank is
  * successful, \c vbl_seq will be set the sequence value in the reply.
  *
- * \param vbl      Pointer to drmVBlank packet desribing how to wait.
+ * \param vbl      Pointer to drmVBlank packet describing how to wait.
  * \param vbl_seq  Location to store the current refresh counter.
  * \param fd       File descriptor use to call into the DRM.
  * \return         Zero on success or -1 on failure.
@@ -232,8 +259,8 @@ static int do_wait( drmVBlank * vbl, GLuint * vbl_seq, int fd )
       if ( first_time ) {
         fprintf(stderr, 
                 "%s: drmWaitVBlank returned %d, IRQs don't seem to be"
-                " working correctly.\nTry running with LIBGL_THROTTLE_REFRESH"
-                " and LIBL_SYNC_REFRESH unset.\n", __FUNCTION__, ret);
+                " working correctly.\nTry adjusting the vblank_mode"
+                " configuration parameter.\n", __FUNCTION__, ret);
         first_time = GL_FALSE;
       }
 
@@ -245,22 +272,44 @@ static int do_wait( drmVBlank * vbl, GLuint * vbl_seq, int fd )
 }
 
 
+/****************************************************************************/
+/**
+ * Returns the default swap interval of the given drawable.
+ */
+
+static unsigned
+driGetDefaultVBlankInterval( const  __DRIdrawable *priv )
+{
+   if ( (priv->vblFlags & (VBLANK_FLAG_THROTTLE | VBLANK_FLAG_SYNC)) != 0 ) {
+      return 1;
+   }
+   else {
+      return 0;
+   }
+}
+
+
 /****************************************************************************/
 /**
  * Sets the default swap interval when the drawable is first bound to a
  * direct rendering context.
  */
 
-void driDrawableInitVBlank( __DRIdrawablePrivate *priv, GLuint flags,
-                           GLuint *vbl_seq )
+void driDrawableInitVBlank( __DRIdrawable *priv )
 {
-   if ( priv->pdraw->swap_interval == (unsigned)-1 ) {
+   if ( priv->swap_interval == (unsigned)-1 &&
+       !( priv->vblFlags & VBLANK_FLAG_NO_IRQ ) ) {
       /* Get current vertical blank sequence */
-      drmVBlank vbl = { .request={ .type = DRM_VBLANK_RELATIVE, .sequence = 0 } };
-      do_wait( &vbl, vbl_seq, priv->driScreenPriv->fd );
-
-      priv->pdraw->swap_interval = (flags & (VBLANK_FLAG_THROTTLE |
-                                            VBLANK_FLAG_SYNC)) != 0 ? 1 : 0;
+      drmVBlank vbl;
+      vbl.request.type = DRM_VBLANK_RELATIVE;
+      if ( priv->vblFlags & VBLANK_FLAG_SECONDARY )
+        vbl.request.type |= DRM_VBLANK_SECONDARY;
+      vbl.request.sequence = 0;
+      do_wait( &vbl, &priv->vblSeq, priv->driScreenPriv->fd );
+      priv->vblank_base = priv->vblSeq;
+
+      priv->swap_interval = driGetDefaultVBlankInterval( priv );
    }
 }
 
@@ -271,21 +320,17 @@ void driDrawableInitVBlank( __DRIdrawablePrivate *priv, GLuint flags,
  */
 
 unsigned
-driGetVBlankInterval( const  __DRIdrawablePrivate *priv, GLuint flags )
+driGetVBlankInterval( const  __DRIdrawable *priv )
 {
-   if ( (flags & VBLANK_FLAG_INTERVAL) != 0 ) {
+   if ( (priv->vblFlags & VBLANK_FLAG_INTERVAL) != 0 ) {
       /* this must have been initialized when the drawable was first bound
        * to a direct rendering context. */
-      assert ( priv->pdraw->swap_interval != (unsigned)-1 );
+      assert ( priv->swap_interval != (unsigned)-1 );
 
-      return priv->pdraw->swap_interval;
-   }
-   else if ( (flags & (VBLANK_FLAG_THROTTLE | VBLANK_FLAG_SYNC)) != 0 ) {
-      return 1;
-   }
-   else {
-      return 0;
+      return priv->swap_interval;
    }
+   else 
+      return driGetDefaultVBlankInterval( priv );
 }
 
 
@@ -295,18 +340,17 @@ driGetVBlankInterval( const  __DRIdrawablePrivate *priv, GLuint flags )
  */
 
 void
-driGetCurrentVBlank( const  __DRIdrawablePrivate *priv, GLuint flags,
-                    GLuint *vbl_seq )
+driGetCurrentVBlank( __DRIdrawable *priv )
 {
    drmVBlank vbl;
 
    vbl.request.type = DRM_VBLANK_RELATIVE;
-   if ( flags & VBLANK_FLAG_SECONDARY ) {
+   if ( priv->vblFlags & VBLANK_FLAG_SECONDARY ) {
       vbl.request.type |= DRM_VBLANK_SECONDARY;
    }
    vbl.request.sequence = 0;
 
-   (void) do_wait( &vbl, vbl_seq, priv->driScreenPriv->fd );
+   (void) do_wait( &vbl, &priv->vblSeq, priv->driScreenPriv->fd );
 }
 
 
@@ -314,19 +358,15 @@ driGetCurrentVBlank( const  __DRIdrawablePrivate *priv, GLuint flags,
 /**
  * Waits for the vertical blank for use with glXSwapBuffers.
  * 
- * \param vbl_seq  Vertical blank sequence number (MSC) after the last buffer
- *                 swap.  Updated after this wait.
- * \param flags    \c VBLANK_FLAG bits that control how long to wait.
  * \param missed_deadline  Set to \c GL_TRUE if the MSC after waiting is later
- *                 than the "target" based on \c flags.  The idea is that if
- *                 \c missed_deadline is set, then the application is not 
- *                 achieving its desired framerate.
+ *                 than the "target" based on \c priv->vblFlags.  The idea is
+ *                 that if \c missed_deadline is set, then the application is
+ *                 not achieving its desired framerate.
  * \return         Zero on success, -1 on error.
  */
 
 int
-driWaitForVBlank( const  __DRIdrawablePrivate *priv, GLuint * vbl_seq,
-                 GLuint flags, GLboolean * missed_deadline )
+driWaitForVBlank( __DRIdrawable *priv, GLboolean * missed_deadline )
 {
    drmVBlank vbl;
    unsigned   original_seq;
@@ -335,10 +375,10 @@ driWaitForVBlank( const  __DRIdrawablePrivate *priv, GLuint * vbl_seq,
    unsigned   diff;
 
    *missed_deadline = GL_FALSE;
-   if ( (flags & (VBLANK_FLAG_INTERVAL |
-                 VBLANK_FLAG_THROTTLE |
-                 VBLANK_FLAG_SYNC)) == 0 ||
-       (flags & VBLANK_FLAG_NO_IRQ) != 0 ) {
+   if ( (priv->vblFlags & (VBLANK_FLAG_INTERVAL |
+                          VBLANK_FLAG_THROTTLE |
+                          VBLANK_FLAG_SYNC)) == 0 ||
+       (priv->vblFlags & VBLANK_FLAG_NO_IRQ) != 0 ) {
       return 0;
    }
 
@@ -349,44 +389,45 @@ driWaitForVBlank( const  __DRIdrawablePrivate *priv, GLuint * vbl_seq,
     *
     * VBLANK_FLAG_INTERVAL and VBLANK_FLAG_THROTTLE mean to wait for at
     * least one vertical blank since the last wait.  Since do_wait modifies
-    * vbl_seq, we have to save the original value of vbl_seq for the
+    * priv->vblSeq, we have to save the original value of priv->vblSeq for the
     * VBLANK_FLAG_INTERVAL / VBLANK_FLAG_THROTTLE calculation later.
     */
 
-   original_seq = *vbl_seq;
-   interval = driGetVBlankInterval(priv, flags);
+   original_seq = priv->vblSeq;
+   interval = driGetVBlankInterval(priv);
    deadline = original_seq + interval;
 
    vbl.request.type = DRM_VBLANK_RELATIVE;
-   if ( flags & VBLANK_FLAG_SECONDARY ) {
+   if ( priv->vblFlags & VBLANK_FLAG_SECONDARY ) {
       vbl.request.type |= DRM_VBLANK_SECONDARY;
    }
-   vbl.request.sequence = ((flags & VBLANK_FLAG_SYNC) != 0) ? 1 : 0;
+   vbl.request.sequence = ((priv->vblFlags & VBLANK_FLAG_SYNC) != 0) ? 1 : 0;
 
-   if ( do_wait( & vbl, vbl_seq, priv->driScreenPriv->fd ) != 0 ) {
+   if ( do_wait( & vbl, &priv->vblSeq, priv->driScreenPriv->fd ) != 0 ) {
       return -1;
    }
 
-   diff = *vbl_seq - deadline;
+   diff = priv->vblSeq - deadline;
 
    /* No need to wait again if we've already reached the target */
    if (diff <= (1 << 23)) {
-      *missed_deadline = (flags & VBLANK_FLAG_SYNC) ? (diff > 0) : GL_TRUE;
+      *missed_deadline = (priv->vblFlags & VBLANK_FLAG_SYNC) ? (diff > 0) :
+                        GL_TRUE;
       return 0;
    }
 
    /* Wait until the target vertical blank. */
    vbl.request.type = DRM_VBLANK_ABSOLUTE;
-   if ( flags & VBLANK_FLAG_SECONDARY ) {
+   if ( priv->vblFlags & VBLANK_FLAG_SECONDARY ) {
       vbl.request.type |= DRM_VBLANK_SECONDARY;
    }
    vbl.request.sequence = deadline;
 
-   if ( do_wait( & vbl, vbl_seq, priv->driScreenPriv->fd ) != 0 ) {
+   if ( do_wait( & vbl, &priv->vblSeq, priv->driScreenPriv->fd ) != 0 ) {
       return -1;
    }
 
-   diff = *vbl_seq - deadline;
+   diff = priv->vblSeq - deadline;
    *missed_deadline = diff > 0 && diff <= (1 << 23);
 
    return 0;