i915: Attempt to schedule buffer swap on target vertical blank when possible.
authorMichel Dänzer <michel@daenzer.net>
Thu, 28 Sep 2006 14:07:12 +0000 (14:07 +0000)
committerMichel Dänzer <michel@daenzer.net>
Thu, 28 Sep 2006 14:07:12 +0000 (14:07 +0000)
This has some advantages over the traditional way of first waiting for the
target vertical blank and then emitting the buffer swap, e.g.

* glXSwapBuffers returns immediately, only the next time the driver needs the
  hardware lock will it block until the target vertical blank. This should
  allow applications that don't intermix rendering and other processing to
  start processing for the next frame right away.
* It's less likely to produce tearing.

src/mesa/drivers/dri/i915/intel_batchbuffer.c
src/mesa/drivers/dri/i915/intel_context.h

index dd754c67d448fe191a98b008df223cafa7baf5fb..8b1c1c5b9802f42086a4428c70e8b1b4df897f67 100644 (file)
@@ -368,6 +368,7 @@ void intelCopyBuffer( const __DRIdrawablePrivate *dPriv,
                      const drm_clip_rect_t      *rect)
 {
    intelContextPtr intel;
+   const intelScreenPrivate *intelScreen;
    GLboolean   missed_target;
    int64_t ust;
 
@@ -382,97 +383,130 @@ void intelCopyBuffer( const __DRIdrawablePrivate *dPriv,
 
    intelFlush( &intel->ctx );
    
-   intelWaitForFrameCompletion( intel );
-   LOCK_HARDWARE( intel );
-
-   if (!rect)
-   {
-       UNLOCK_HARDWARE( intel );
-       driWaitForVBlank( dPriv, &intel->vbl_seq, intel->vblank_flags, & missed_target );
-       LOCK_HARDWARE( intel );
-   }
-   {
-      const intelScreenPrivate *intelScreen = intel->intelScreen;
-      const __DRIdrawablePrivate *dPriv = intel->driDrawable;
-      const int nbox = dPriv->numClipRects;
-      const drm_clip_rect_t *pbox = dPriv->pClipRects;
-      drm_clip_rect_t box;
-      const int cpp = intelScreen->cpp;
-      const int pitch = intelScreen->front.pitch; /* in bytes */
-      int i;
-      GLuint CMD, BR13;
-      BATCH_LOCALS;
-
-      switch(cpp) {
-      case 2: 
-        BR13 = (pitch) | (0xCC << 16) | (1<<24);
-        CMD = XY_SRC_COPY_BLT_CMD;
-        break;
-      case 4:
-        BR13 = (pitch) | (0xCC << 16) | (1<<24) | (1<<25);
-        CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
-               XY_SRC_COPY_BLT_WRITE_RGB);
-        break;
-      default:
-        BR13 = (pitch) | (0xCC << 16) | (1<<24);
-        CMD = XY_SRC_COPY_BLT_CMD;
-        break;
+   intelScreen = intel->intelScreen;
+
+   if (!rect && !intel->swap_scheduled && intelScreen->drmMinor >= 6 &&
+       !(intel->vblank_flags & VBLANK_FLAG_NO_IRQ) &&
+       intelScreen->current_rotation == 0) {
+      unsigned int interval = driGetVBlankInterval(dPriv, intel->vblank_flags);
+      unsigned int target;
+      drm_i915_vblank_swap_t swap;
+
+      swap.drawable = dPriv->hHWDrawable;
+      swap.seqtype = DRM_VBLANK_ABSOLUTE;
+      target = swap.sequence = intel->vbl_seq + interval;
+
+      if (intel->vblank_flags & VBLANK_FLAG_SYNC) {
+        swap.seqtype |= DRM_VBLANK_NEXTONMISS;
+      } else if (interval == 0) {
+        goto noschedule;
       }
-   
-      if (0) 
-        intel_draw_performance_boxes( intel );
 
-      for (i = 0 ; i < nbox; i++, pbox++) 
-      {
-        if (pbox->x1 > pbox->x2 ||
-            pbox->y1 > pbox->y2 ||
-            pbox->x2 > intelScreen->width ||
-            pbox->y2 > intelScreen->height) {
-            _mesa_warning(&intel->ctx, "Bad cliprect in intelCopyBuffer()");
-           continue;
-         }
+      if (!drmCommandWriteRead(intel->driFd, DRM_I915_VBLANK_SWAP, &swap,
+                              sizeof(swap))) {
+        intel->swap_scheduled = 1;
+        intel->vbl_seq = swap.sequence;
+        swap.sequence -= target;
+        missed_target = swap.sequence > 0 && swap.sequence <= (1 << 23);
+      }
+   } else {
+      intel->swap_scheduled = 0;
+   }
+noschedule:
 
-        box = *pbox;
+   if (!intel->swap_scheduled) {
+      intelWaitForFrameCompletion( intel );
+      LOCK_HARDWARE( intel );
 
-        if (rect)
-        {
-            if (rect->x1 > box.x1)
-                box.x1 = rect->x1;
-            if (rect->y1 > box.y1)
-                box.y1 = rect->y1;
-            if (rect->x2 < box.x2)
-                box.x2 = rect->x2;
-            if (rect->y2 < box.y2)
-                box.y2 = rect->y2;
-
-            if (box.x1 > box.x2 || box.y1 > box.y2)
-                continue;
+      if (!rect)
+      {
+        UNLOCK_HARDWARE( intel );
+        driWaitForVBlank( dPriv, &intel->vbl_seq, intel->vblank_flags, & missed_target );
+        LOCK_HARDWARE( intel );
+      }
+      {
+        const intelScreenPrivate *intelScreen = intel->intelScreen;
+        const __DRIdrawablePrivate *dPriv = intel->driDrawable;
+        const int nbox = dPriv->numClipRects;
+        const drm_clip_rect_t *pbox = dPriv->pClipRects;
+        drm_clip_rect_t box;
+        const int cpp = intelScreen->cpp;
+        const int pitch = intelScreen->front.pitch; /* in bytes */
+        int i;
+        GLuint CMD, BR13;
+        BATCH_LOCALS;
+
+        switch(cpp) {
+        case 2: 
+           BR13 = (pitch) | (0xCC << 16) | (1<<24);
+           CMD = XY_SRC_COPY_BLT_CMD;
+           break;
+        case 4:
+           BR13 = (pitch) | (0xCC << 16) | (1<<24) | (1<<25);
+           CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
+                  XY_SRC_COPY_BLT_WRITE_RGB);
+           break;
+        default:
+           BR13 = (pitch) | (0xCC << 16) | (1<<24);
+           CMD = XY_SRC_COPY_BLT_CMD;
+           break;
         }
+   
+        if (0) 
+           intel_draw_performance_boxes( intel );
 
-        BEGIN_BATCH( 8);
-        OUT_BATCH( CMD );
-        OUT_BATCH( BR13 );
-        OUT_BATCH( (box.y1 << 16) | box.x1 );
-        OUT_BATCH( (box.y2 << 16) | box.x2 );
+        for (i = 0 ; i < nbox; i++, pbox++) 
+        {
+           if (pbox->x1 > pbox->x2 ||
+               pbox->y1 > pbox->y2 ||
+               pbox->x2 > intelScreen->width ||
+               pbox->y2 > intelScreen->height) {
+              _mesa_warning(&intel->ctx, "Bad cliprect in intelCopyBuffer()");
+              continue;
+           }
+
+           box = *pbox;
+
+           if (rect)
+           {
+              if (rect->x1 > box.x1)
+                 box.x1 = rect->x1;
+              if (rect->y1 > box.y1)
+                 box.y1 = rect->y1;
+              if (rect->x2 < box.x2)
+                 box.x2 = rect->x2;
+              if (rect->y2 < box.y2)
+                 box.y2 = rect->y2;
+
+              if (box.x1 > box.x2 || box.y1 > box.y2)
+                 continue;
+           }
+
+           BEGIN_BATCH( 8);
+           OUT_BATCH( CMD );
+           OUT_BATCH( BR13 );
+           OUT_BATCH( (box.y1 << 16) | box.x1 );
+           OUT_BATCH( (box.y2 << 16) | box.x2 );
 
-        if (intel->sarea->pf_current_page == 0) 
-           OUT_BATCH( intelScreen->front.offset );
-        else
-           OUT_BATCH( intelScreen->back.offset );                      
+           if (intel->sarea->pf_current_page == 0) 
+              OUT_BATCH( intelScreen->front.offset );
+           else
+              OUT_BATCH( intelScreen->back.offset );                   
 
-        OUT_BATCH( (box.y1 << 16) | box.x1 );
-        OUT_BATCH( BR13 & 0xffff );
+           OUT_BATCH( (box.y1 << 16) | box.x1 );
+           OUT_BATCH( BR13 & 0xffff );
 
-        if (intel->sarea->pf_current_page == 0) 
-           OUT_BATCH( intelScreen->back.offset );                      
-        else
-           OUT_BATCH( intelScreen->front.offset );
+           if (intel->sarea->pf_current_page == 0) 
+              OUT_BATCH( intelScreen->back.offset );                   
+           else
+              OUT_BATCH( intelScreen->front.offset );
 
-        ADVANCE_BATCH();
+           ADVANCE_BATCH();
+        }
       }
+      intelFlushBatchLocked( intel, GL_TRUE, GL_TRUE, GL_TRUE );
+      UNLOCK_HARDWARE( intel );
    }
-   intelFlushBatchLocked( intel, GL_TRUE, GL_TRUE, GL_TRUE );
-   UNLOCK_HARDWARE( intel );
 
    if (!rect)
    {
index 0ca8ff268de4aac8ee2eabbecb333d580017ceba..6cd6272053f032a38e0d44085a43f96c247b22bb 100644 (file)
@@ -261,6 +261,8 @@ struct intel_context
 
    GLuint swap_count;
    GLuint swap_missed_count;
+
+   GLuint swap_scheduled;
 };
 
 
@@ -321,6 +323,13 @@ do {                                                       \
     char __ret=0;                                      \
     DEBUG_CHECK_LOCK();                                        \
     assert(!(intel)->locked);                          \
+    if ((intel)->swap_scheduled) {                     \
+        drmVBlank vbl;                                 \
+        vbl.request.type = DRM_VBLANK_ABSOLUTE;                \
+        vbl.request.sequence = (intel)->vbl_seq;       \
+        drmWaitVBlank((intel)->driFd, &vbl);           \
+        (intel)->swap_scheduled = 0;                   \
+    }                                                  \
     DRM_CAS((intel)->driHwLock, (intel)->hHWContext,   \
         (DRM_LOCK_HELD|(intel)->hHWContext), __ret);   \
     if (__ret)                                         \