mesa: Branch 'master' - 16 commits

Michel Daenzer daenzer at kemper.freedesktop.org
Fri Mar 9 23:29:59 UTC 2007


 src/mesa/drivers/dri/i915tex/intel_blit.c         |  261 +++++-----------
 src/mesa/drivers/dri/i915tex/intel_buffers.c      |  352 ++++++++++++++++++----
 src/mesa/drivers/dri/i915tex/intel_buffers.h      |    3 
 src/mesa/drivers/dri/i915tex/intel_context.c      |   78 +++-
 src/mesa/drivers/dri/i915tex/intel_context.h      |   14 
 src/mesa/drivers/dri/i915tex/intel_fbo.c          |   46 ++
 src/mesa/drivers/dri/i915tex/intel_fbo.h          |   35 ++
 src/mesa/drivers/dri/i915tex/intel_reg.h          |    4 
 src/mesa/drivers/dri/i915tex/intel_screen.c       |  111 +++++-
 src/mesa/drivers/dri/i915tex/intel_screen.h       |    2 
 src/mesa/drivers/dri/i915tex/intel_tris.c         |    2 
 src/mesa/drivers/dri/i915tex/server/i830_common.h |    6 
 12 files changed, 609 insertions(+), 305 deletions(-)

New commits:
diff-tree 30b914e2ca28cd44eed57b34353e641793b38a6d (from parents)
Merge: f9f79c8d770e696249bd98c68b563f887562c974 6e0878becfbf211e5bbd141cd3441dfbdb206cc8
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Sat Mar 10 00:19:17 2007 +0100

    Merge branch 'i915tex-pageflip'

diff-tree 6e0878becfbf211e5bbd141cd3441dfbdb206cc8 (from bb0760ca4f1759eb3c237045f464da4ad60eef83)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Fri Mar 9 20:00:13 2007 +0100

    i915tex: Wait for pending scheduled flips before switching vsync pipe.
    
    This avoids hangs when the vblank sequence numbers are not in sync between
    pipes, in particular when they run at different refresh rates.

diff --git a/src/mesa/drivers/dri/i915tex/intel_buffers.c b/src/mesa/drivers/dri/i915tex/intel_buffers.c
index 174f3c6..1643957 100644
--- a/src/mesa/drivers/dri/i915tex/intel_buffers.c
+++ b/src/mesa/drivers/dri/i915tex/intel_buffers.c
@@ -300,8 +300,27 @@ intelWindowMoved(struct intel_context *i
       }
 
       if (flags != intel_fb->vblank_flags) {
+	 drmVBlank vbl;
+	 int i;
+
+	 vbl.request.type = DRM_VBLANK_ABSOLUTE;
+
+	 if ( intel_fb->vblank_flags & VBLANK_FLAG_SECONDARY ) {
+	    vbl.request.type |= DRM_VBLANK_SECONDARY;
+	 }
+
+	 for (i = 0; i < intel_fb->pf_num_pages; i++) {
+	    vbl.request.sequence = intel_fb->color_rb[i]->vbl_pending;
+	    drmWaitVBlank(intel->driFd, &vbl);
+	 }
+
 	 intel_fb->vblank_flags = flags;
 	 driGetCurrentVBlank(dPriv, intel_fb->vblank_flags, &intel_fb->vbl_seq);
+	 intel_fb->vbl_waited = intel_fb->vbl_seq;
+
+	 for (i = 0; i < intel_fb->pf_num_pages; i++) {
+	    intel_fb->color_rb[i]->vbl_pending = intel_fb->vbl_waited;
+	 }
       }
    } else {
       intel_fb->vblank_flags &= ~VBLANK_FLAG_SECONDARY;
diff-tree bb0760ca4f1759eb3c237045f464da4ad60eef83 (from 36b4e25da34691dffd6b147c8cf3d2598ec11ac7)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Fri Mar 9 19:56:55 2007 +0100

    i915tex: Set intel_fb->vbl_waited to current instead of what we aimed for.

diff --git a/src/mesa/drivers/dri/i915tex/intel_context.c b/src/mesa/drivers/dri/i915tex/intel_context.c
index b8515fe..5c2cdf0 100644
--- a/src/mesa/drivers/dri/i915tex/intel_context.c
+++ b/src/mesa/drivers/dri/i915tex/intel_context.c
@@ -730,7 +730,7 @@ void LOCK_HARDWARE( struct intel_context
 
 	vbl.request.sequence = intel_rb->vbl_pending;
 	drmWaitVBlank(intel->driFd, &vbl);
-	intel_fb->vbl_waited = intel_rb->vbl_pending;
+	intel_fb->vbl_waited = vbl.reply.sequence;
     }
 
     DRM_CAS(intel->driHwLock, intel->hHWContext,
diff-tree 36b4e25da34691dffd6b147c8cf3d2598ec11ac7 (from 81536789d2d2d92c687e9037cbb6f86b633ef839)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Fri Mar 9 17:52:29 2007 +0100

    i915tex: Sync pages between pipes immediately again.
    
    This should be safe now that we no longer use the MI_WAIT_FOR_EVENT instruction
    incorrectly and should also work correctly with applications that render to the
    front buffer.

diff --git a/src/mesa/drivers/dri/i915tex/intel_buffers.c b/src/mesa/drivers/dri/i915tex/intel_buffers.c
index 35236ed..174f3c6 100644
--- a/src/mesa/drivers/dri/i915tex/intel_buffers.c
+++ b/src/mesa/drivers/dri/i915tex/intel_buffers.c
@@ -257,6 +257,8 @@ intelWindowMoved(struct intel_context *i
 	 if (pf_pipes == 0x3 &&	pf_pipes != intel_fb->pf_pipes &&
 	     (intel->sarea->pf_current_page & 0x3) !=
 	     (((intel->sarea->pf_current_page) >> 2) & 0x3)) {
+	    drm_i915_flip_t flip;
+
 	    if (intel_fb->pf_current_page ==
 		(intel->sarea->pf_current_page & 0x3)) {
 	       /* XXX: This is ugly, but emitting two flips 'in a row' can cause
@@ -265,13 +267,21 @@ intelWindowMoved(struct intel_context *i
                intel->sarea->pf_current_page =
 		  intel->sarea->pf_current_page & 0x3;
 	       intel->sarea->pf_current_page |=
-		  intel->sarea->pf_current_page << 2;
+		  ((intel_fb->pf_current_page + intel_fb->pf_num_pages - 1) %
+		   intel_fb->pf_num_pages) << 2;
+
+	       flip.pipes = 0x2;
 	    } else {
                intel->sarea->pf_current_page =
 		  intel->sarea->pf_current_page & (0x3 << 2);
 	       intel->sarea->pf_current_page |=
-		  intel->sarea->pf_current_page >> 2;
+		  (intel_fb->pf_current_page + intel_fb->pf_num_pages - 1) %
+		  intel_fb->pf_num_pages;
+
+	       flip.pipes = 0x1;
 	    }
+
+	    drmCommandWrite(intel->driFd, DRM_I915_FLIP, &flip, sizeof(flip));
 	 }
 
 	 intel_fb->pf_pipes = pf_pipes;
diff-tree 81536789d2d2d92c687e9037cbb6f86b633ef839 (from fb3410297bb21a0eeda4d32698c2612f4e3cf40e)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Fri Mar 9 17:41:04 2007 +0100

    i915tex: Do not wait for pending flips on both pipes at the same time.
    
    The MI_WAIT_FOR_EVENT instruction does not support waiting for several events
    at once, so this should fix the lockups with page flipping when both pipes are
    enabled.

diff --git a/src/mesa/drivers/dri/i915tex/intel_buffers.c b/src/mesa/drivers/dri/i915tex/intel_buffers.c
index 9f1b25e..35236ed 100644
--- a/src/mesa/drivers/dri/i915tex/intel_buffers.c
+++ b/src/mesa/drivers/dri/i915tex/intel_buffers.c
@@ -662,20 +662,15 @@ intel_wait_flips(struct intel_context *i
 			     BUFFER_BACK_LEFT);
 
    if (intel_fb->Base.Name == 0 && intel_rb->pf_pending == intel_fb->pf_seq) {
-      GLuint mi_wait = MI_WAIT_FOR_EVENT;
       GLint pf_pipes = intel_fb->pf_pipes;
       BATCH_LOCALS;
 
-      if (pf_pipes & 0x1)
-	mi_wait |= MI_WAIT_FOR_PLANE_A_FLIP;
-
-      if (pf_pipes & 0x2)
-	mi_wait |= MI_WAIT_FOR_PLANE_B_FLIP;
-
       /* Wait for pending flips to take effect */
       BEGIN_BATCH(2, batch_flags);
-      OUT_BATCH(mi_wait);
-      OUT_BATCH(0);
+      OUT_BATCH(pf_pipes & 0x1 ? (MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP)
+		: 0);
+      OUT_BATCH(pf_pipes & 0x2 ? (MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_B_FLIP)
+		: 0);
       ADVANCE_BATCH();
 
       intel_rb->pf_pending--;
diff-tree fb3410297bb21a0eeda4d32698c2612f4e3cf40e (from 0609b6afa8117893d7b36468158ac6ec2f5642bc)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Wed Mar 7 18:01:39 2007 +0100

    i915tex: Set framebuffer size to match window before calling _mesa_make_current.
    
    Fixes issues with apps that don't call glViewport by default.

diff --git a/src/mesa/drivers/dri/i915tex/intel_context.c b/src/mesa/drivers/dri/i915tex/intel_context.c
index b1352a7..b8515fe 100644
--- a/src/mesa/drivers/dri/i915tex/intel_context.c
+++ b/src/mesa/drivers/dri/i915tex/intel_context.c
@@ -580,6 +580,16 @@ intelMakeCurrent(__DRIcontextPrivate * d
          }
       }
 
+      /* set GLframebuffer size to match window, if needed */
+      if (intel_fb->Base.Width != driDrawPriv->w) {
+         _mesa_resize_framebuffer(&intel->ctx, &intel_fb->Base,
+                                  driDrawPriv->w, driDrawPriv->h);
+      }         
+      if (readFb->Width != driReadPriv->w) {
+         _mesa_resize_framebuffer(&intel->ctx, readFb,
+                                  driReadPriv->w, driReadPriv->h);
+      }         
+
       _mesa_make_current(&intel->ctx, &intel_fb->Base, readFb);
 
       /* The drawbuffer won't always be updated by _mesa_make_current: 
@@ -599,16 +609,6 @@ intelMakeCurrent(__DRIcontextPrivate * d
 
 	 intel_draw_buffer(&intel->ctx, &intel_fb->Base);
       }
-
-      /* set initial GLframebuffer size to match window, if needed */
-      if (&intel_fb->Base.Width == 0 && driDrawPriv->w) {
-         _mesa_resize_framebuffer(&intel->ctx, &intel_fb->Base,
-                                  driDrawPriv->w, driDrawPriv->h);
-      }         
-      if (readFb->Width == 0 && driReadPriv->w) {
-         _mesa_resize_framebuffer(&intel->ctx, readFb,
-                                  driReadPriv->w, driReadPriv->h);
-      }         
    }
    else {
       _mesa_make_current(NULL, NULL, NULL);
diff-tree 0609b6afa8117893d7b36468158ac6ec2f5642bc (from 3c578455e103664e6f93a7792999da7c06dd9a3f)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Wed Feb 28 17:46:07 2007 +0100

    i915tex: Sync pages differently when crossing pipe borders.
    
    Don't flip (up to twice) immediately but just arrange things such that the
    pages will be in sync on both pipes on the next flip.

diff --git a/src/mesa/drivers/dri/i915tex/intel_buffers.c b/src/mesa/drivers/dri/i915tex/intel_buffers.c
index 5eb2a8e..9f1b25e 100644
--- a/src/mesa/drivers/dri/i915tex/intel_buffers.c
+++ b/src/mesa/drivers/dri/i915tex/intel_buffers.c
@@ -253,19 +253,25 @@ intelWindowMoved(struct intel_context *i
 			 pf_active ? "" : "in");
 
       if (pf_active) {
-	 int i;
-
 	 /* Sync pages between pipes if we're flipping on both at the same time */
-	 for (i = 0; i < 2 && pf_pipes != intel_fb->pf_pipes &&
-		intel_fb->pf_pipes == 0x3 &&
-		(intel->sarea->pf_current_page & 0x3) !=
-		((intel->sarea->pf_current_page) >> 2 & 0x3); i++) {
-	    drm_i915_flip_t flip;
-
-	    flip.pipes = (intel_fb->pf_current_page ==
-			  (intel->sarea->pf_current_page & 0x3)) ? 0x2 : 0x1;
-
-	    drmCommandWrite(intel->driFd, DRM_I915_FLIP, &flip, sizeof(flip));
+	 if (pf_pipes == 0x3 &&	pf_pipes != intel_fb->pf_pipes &&
+	     (intel->sarea->pf_current_page & 0x3) !=
+	     (((intel->sarea->pf_current_page) >> 2) & 0x3)) {
+	    if (intel_fb->pf_current_page ==
+		(intel->sarea->pf_current_page & 0x3)) {
+	       /* XXX: This is ugly, but emitting two flips 'in a row' can cause
+		* lockups for unknown reasons.
+		*/
+               intel->sarea->pf_current_page =
+		  intel->sarea->pf_current_page & 0x3;
+	       intel->sarea->pf_current_page |=
+		  intel->sarea->pf_current_page << 2;
+	    } else {
+               intel->sarea->pf_current_page =
+		  intel->sarea->pf_current_page & (0x3 << 2);
+	       intel->sarea->pf_current_page |=
+		  intel->sarea->pf_current_page >> 2;
+	    }
 	 }
 
 	 intel_fb->pf_pipes = pf_pipes;
diff-tree 3c578455e103664e6f93a7792999da7c06dd9a3f (from edf676cc5af26d8f82625a94788d4f27c464ab38)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Wed Feb 28 17:42:54 2007 +0100

    i915tex: Check that intel_rb is valid before trying to add it to an fbo.

diff --git a/src/mesa/drivers/dri/i915tex/intel_fbo.c b/src/mesa/drivers/dri/i915tex/intel_fbo.c
index ad07845..8d43055 100644
--- a/src/mesa/drivers/dri/i915tex/intel_fbo.c
+++ b/src/mesa/drivers/dri/i915tex/intel_fbo.c
@@ -81,14 +81,16 @@ intel_flip_renderbuffers(struct intel_fr
    int current_page = intel_fb->pf_current_page;
    int next_page = (current_page + 1) % intel_fb->pf_num_pages;
 
-   if (intel_fb->Base.Attachment[BUFFER_FRONT_LEFT].Renderbuffer !=
+   if (intel_fb->color_rb[current_page] &&
+       intel_fb->Base.Attachment[BUFFER_FRONT_LEFT].Renderbuffer !=
        &intel_fb->color_rb[current_page]->Base) {
       _mesa_remove_renderbuffer(&intel_fb->Base, BUFFER_FRONT_LEFT);
       _mesa_add_renderbuffer(&intel_fb->Base, BUFFER_FRONT_LEFT,
 			     &intel_fb->color_rb[current_page]->Base);
    }
 
-   if (intel_fb->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer !=
+   if (intel_fb->color_rb[next_page] &&
+       intel_fb->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer !=
        &intel_fb->color_rb[next_page]->Base) {
       _mesa_remove_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT);
       _mesa_add_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT,
diff-tree edf676cc5af26d8f82625a94788d4f27c464ab38 (from 641c966e3de192eba17c693f00d6654742c72eb6)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Wed Feb 28 16:05:49 2007 +0100

    i915tex: Also update intel_rb->vbl_pending when scheduled swap is not a flip.

diff --git a/src/mesa/drivers/dri/i915tex/intel_buffers.c b/src/mesa/drivers/dri/i915tex/intel_buffers.c
index 8054d98..5eb2a8e 100644
--- a/src/mesa/drivers/dri/i915tex/intel_buffers.c
+++ b/src/mesa/drivers/dri/i915tex/intel_buffers.c
@@ -815,12 +815,12 @@ intelScheduleSwap(const __DRIdrawablePri
       swap.sequence -= target;
       *missed_target = swap.sequence > 0 && swap.sequence <= (1 << 23);
 
-      if (swap.seqtype & DRM_VBLANK_FLIP) {
+      intel_get_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT)->vbl_pending =
 	 intel_get_renderbuffer(&intel_fb->Base,
 				BUFFER_FRONT_LEFT)->vbl_pending =
-	    intel_get_renderbuffer(&intel_fb->Base,
-				   BUFFER_BACK_LEFT)->vbl_pending = intel_fb->vbl_seq;
+	 intel_fb->vbl_seq;
 
+      if (swap.seqtype & DRM_VBLANK_FLIP) {
 	 intel_flip_renderbuffers(intel_fb);
 	 intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
       }
diff-tree 641c966e3de192eba17c693f00d6654742c72eb6 (from e33a9d689415e00bded306699abdf93b96c0b9ad)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Thu Feb 22 17:24:09 2007 +0100

    i915tex: Schedule flips when possible.
    
    Also move vsync related state from context to window, so it's possible to
    schedule several flips ahead of time with triple buffering.

diff --git a/src/mesa/drivers/dri/i915tex/intel_blit.c b/src/mesa/drivers/dri/i915tex/intel_blit.c
index 640c73e..dbe4ba2 100644
--- a/src/mesa/drivers/dri/i915tex/intel_blit.c
+++ b/src/mesa/drivers/dri/i915tex/intel_blit.c
@@ -55,8 +55,6 @@ intelCopyBuffer(const __DRIdrawablePriva
 
    struct intel_context *intel;
    const intelScreenPrivate *intelScreen;
-   GLboolean missed_target;
-   int64_t ust;
 
    DBG("%s\n", __FUNCTION__);
 
@@ -68,41 +66,6 @@ intelCopyBuffer(const __DRIdrawablePriva
 
    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 ( intel->vblank_flags & VBLANK_FLAG_SECONDARY ) {
-	 swap.seqtype |= DRM_VBLANK_SECONDARY;
-      }
-
-      intel_batchbuffer_flush(intel->batch);
-
-      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:
-  
    if (intel->last_swap_fence) {
       driFenceFinish(intel->last_swap_fence, DRM_FENCE_TYPE_EXE, GL_TRUE);
       driFenceUnReference(intel->last_swap_fence);
@@ -111,108 +74,88 @@ noschedule:
    intel->last_swap_fence = intel->first_swap_fence;
    intel->first_swap_fence = NULL;
 
-   if (!intel->swap_scheduled) {
-      if (!rect) {
-	 driWaitForVBlank(dPriv, &intel->vbl_seq, intel->vblank_flags,
-			  &missed_target);
-      }
-
-
-      /* The LOCK_HARDWARE is required for the cliprects.  Buffer offsets
-       * should work regardless.
-       */
-      LOCK_HARDWARE(intel);
-
-      if (dPriv && dPriv->numClipRects) {
-	 const intelScreenPrivate *intelScreen = intel->intelScreen;
-	 struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
-	 const struct intel_region *frontRegion
-	    = intel_get_rb_region(&intel_fb->Base, BUFFER_FRONT_LEFT);
-	 const struct intel_region *backRegion
-	    = intel_get_rb_region(&intel_fb->Base, BUFFER_BACK_LEFT);
-	 const int nbox = dPriv->numClipRects;
-	 const drm_clip_rect_t *pbox = dPriv->pClipRects;
-	 const int pitch = frontRegion->pitch;
-	 const int cpp = frontRegion->cpp;
-	 int BR13, CMD;
-	 int i;
-
-	 ASSERT(intel_fb);
-	 ASSERT(intel_fb->Base.Name == 0);    /* Not a user-created FBO */
-	 ASSERT(frontRegion);
-	 ASSERT(backRegion);
-	 ASSERT(frontRegion->pitch == backRegion->pitch);
-	 ASSERT(frontRegion->cpp == backRegion->cpp);
-
-	 if (cpp == 2) {
-	    BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24);
-	    CMD = XY_SRC_COPY_BLT_CMD;
-	 }
-	 else {
-	    BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24) | (1 << 25);
-	    CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
-		   XY_SRC_COPY_BLT_WRITE_RGB);
-	 }
+   /* The LOCK_HARDWARE is required for the cliprects.  Buffer offsets
+    * should work regardless.
+    */
+   LOCK_HARDWARE(intel);
 
-	 for (i = 0; i < nbox; i++, pbox++) {
-	    drm_clip_rect_t box;
+   if (dPriv && dPriv->numClipRects) {
+      struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
+      const struct intel_region *frontRegion
+	 = intel_get_rb_region(&intel_fb->Base, BUFFER_FRONT_LEFT);
+      const struct intel_region *backRegion
+	 = intel_get_rb_region(&intel_fb->Base, BUFFER_BACK_LEFT);
+      const int nbox = dPriv->numClipRects;
+      const drm_clip_rect_t *pbox = dPriv->pClipRects;
+      const int pitch = frontRegion->pitch;
+      const int cpp = frontRegion->cpp;
+      int BR13, CMD;
+      int i;
 
-	    if (pbox->x1 > pbox->x2 ||
-		pbox->y1 > pbox->y2 ||
-		pbox->x2 > intelScreen->width || pbox->y2 > intelScreen->height)
-	       continue;
+      ASSERT(intel_fb);
+      ASSERT(intel_fb->Base.Name == 0);    /* Not a user-created FBO */
+      ASSERT(frontRegion);
+      ASSERT(backRegion);
+      ASSERT(frontRegion->pitch == backRegion->pitch);
+      ASSERT(frontRegion->cpp == backRegion->cpp);
+
+      if (cpp == 2) {
+	 BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24);
+	 CMD = XY_SRC_COPY_BLT_CMD;
+      }
+      else {
+	 BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24) | (1 << 25);
+	 CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
+		XY_SRC_COPY_BLT_WRITE_RGB);
+      }
 
-	    box = *pbox;
+      for (i = 0; i < nbox; i++, pbox++) {
+	 drm_clip_rect_t box;
 
-	    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, INTEL_BATCH_NO_CLIPRECTS);
-	    OUT_BATCH(CMD);
-	    OUT_BATCH(BR13);
-	    OUT_BATCH((pbox->y1 << 16) | pbox->x1);
-	    OUT_BATCH((pbox->y2 << 16) | pbox->x2);
-
-	    OUT_RELOC(frontRegion->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
-		      DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, 0);
-	    OUT_BATCH((pbox->y1 << 16) | pbox->x1);
-	    OUT_BATCH(BR13 & 0xffff);
-	    OUT_RELOC(backRegion->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ,
-		      DRM_BO_MASK_MEM | DRM_BO_FLAG_READ, 0);
+	 if (pbox->x1 > pbox->x2 ||
+	     pbox->y1 > pbox->y2 ||
+	     pbox->x2 > intelScreen->width || pbox->y2 > intelScreen->height)
+	    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;
 
-	    ADVANCE_BATCH();
+	    if (box.x1 > box.x2 || box.y1 > box.y2)
+	       continue;
 	 }
 
-	 if (intel->first_swap_fence)
-	    driFenceUnReference(intel->first_swap_fence);
-	 intel->first_swap_fence = intel_batchbuffer_flush(intel->batch);
-	 driFenceReference(intel->first_swap_fence);
-      }
-
-      UNLOCK_HARDWARE(intel);
-   }
+	 BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS);
+	 OUT_BATCH(CMD);
+	 OUT_BATCH(BR13);
+	 OUT_BATCH((pbox->y1 << 16) | pbox->x1);
+	 OUT_BATCH((pbox->y2 << 16) | pbox->x2);
+
+	 OUT_RELOC(frontRegion->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
+		   DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, 0);
+	 OUT_BATCH((pbox->y1 << 16) | pbox->x1);
+	 OUT_BATCH(BR13 & 0xffff);
+	 OUT_RELOC(backRegion->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ,
+		   DRM_BO_MASK_MEM | DRM_BO_FLAG_READ, 0);
 
-   if (!rect) {
-      intel->swap_count++;
-      (*dri_interface->getUST) (&ust);
-      if (missed_target) {
-         intel->swap_missed_count++;
-         intel->swap_missed_ust = ust - intel->swap_ust;
+	 ADVANCE_BATCH();
       }
 
-      intel->swap_ust = ust;
+      if (intel->first_swap_fence)
+	 driFenceUnReference(intel->first_swap_fence);
+      intel->first_swap_fence = intel_batchbuffer_flush(intel->batch);
+      driFenceReference(intel->first_swap_fence);
    }
+
+   UNLOCK_HARDWARE(intel);
 }
 
 
diff --git a/src/mesa/drivers/dri/i915tex/intel_buffers.c b/src/mesa/drivers/dri/i915tex/intel_buffers.c
index 7db5ccf..8054d98 100644
--- a/src/mesa/drivers/dri/i915tex/intel_buffers.c
+++ b/src/mesa/drivers/dri/i915tex/intel_buffers.c
@@ -226,7 +226,7 @@ intelWindowMoved(struct intel_context *i
 				     .y2 = sarea->pipeB_y + sarea->pipeB_h };
       GLint areaA = driIntersectArea( drw_rect, pipeA_rect );
       GLint areaB = driIntersectArea( drw_rect, pipeB_rect );
-      GLuint flags = intel->vblank_flags;
+      GLuint flags = intel_fb->vblank_flags;
       GLboolean pf_active;
       GLint pf_pipes;
 
@@ -278,17 +278,17 @@ intelWindowMoved(struct intel_context *i
       /* Update vblank info
        */
       if (areaB > areaA || (areaA == areaB && areaB > 0)) {
-	 flags = intel->vblank_flags | VBLANK_FLAG_SECONDARY;
+	 flags = intel_fb->vblank_flags | VBLANK_FLAG_SECONDARY;
       } else {
-	 flags = intel->vblank_flags & ~VBLANK_FLAG_SECONDARY;
+	 flags = intel_fb->vblank_flags & ~VBLANK_FLAG_SECONDARY;
       }
 
-      if (flags != intel->vblank_flags) {
-	 intel->vblank_flags = flags;
-	 driGetCurrentVBlank(dPriv, intel->vblank_flags, &intel->vbl_seq);
+      if (flags != intel_fb->vblank_flags) {
+	 intel_fb->vblank_flags = flags;
+	 driGetCurrentVBlank(dPriv, intel_fb->vblank_flags, &intel_fb->vbl_seq);
       }
    } else {
-      intel->vblank_flags &= ~VBLANK_FLAG_SECONDARY;
+      intel_fb->vblank_flags &= ~VBLANK_FLAG_SECONDARY;
    }
 
    /* Update Mesa's notion of window size */
@@ -683,7 +683,6 @@ static GLboolean
 intelPageFlip(const __DRIdrawablePrivate * dPriv)
 {
    struct intel_context *intel;
-   GLboolean missed_target;
    int ret;
    struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
 
@@ -701,13 +700,6 @@ intelPageFlip(const __DRIdrawablePrivate
 
    intelFlush(&intel->ctx);
 
-   driWaitForVBlank(dPriv, &intel->vbl_seq, intel->vblank_flags, &missed_target);
-
-   if (missed_target) {
-      intel->swap_missed_count++;
-      (void)(*dri_interface->getUST) (&intel->swap_missed_ust);
-   }
-
    ret = 0;
 
    LOCK_HARDWARE(intel);
@@ -772,6 +764,83 @@ intelSwapBuffers(__DRIdrawablePrivate * 
 #else
 /* Trunk version:
  */
+
+static GLboolean
+intelScheduleSwap(const __DRIdrawablePrivate * dPriv, GLboolean *missed_target)
+{
+   struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
+   unsigned int interval = driGetVBlankInterval(dPriv, intel_fb->vblank_flags);
+   struct intel_context *intel =
+      intelScreenContext(dPriv->driScreenPriv->private);
+   const intelScreenPrivate *intelScreen = intel->intelScreen;
+   unsigned int target;
+   drm_i915_vblank_swap_t swap;
+   GLboolean ret;
+
+   if ((intel_fb->vblank_flags & VBLANK_FLAG_NO_IRQ) ||
+       intelScreen->current_rotation != 0 ||
+       intelScreen->drmMinor < (intel_fb->pf_active ? 9 : 6))
+      return GL_FALSE;
+
+   swap.seqtype = DRM_VBLANK_ABSOLUTE;
+
+   if (intel_fb->vblank_flags & VBLANK_FLAG_SYNC) {
+      swap.seqtype |= DRM_VBLANK_NEXTONMISS;
+   } else if (interval == 0) {
+      return GL_FALSE;
+   }
+
+   swap.drawable = dPriv->hHWDrawable;
+   target = swap.sequence = intel_fb->vbl_seq + interval;
+
+   if ( intel_fb->vblank_flags & VBLANK_FLAG_SECONDARY ) {
+      swap.seqtype |= DRM_VBLANK_SECONDARY;
+   }
+
+   LOCK_HARDWARE(intel);
+
+   intel_batchbuffer_flush(intel->batch);
+
+   if ( intel_fb->pf_active ) {
+      swap.seqtype |= DRM_VBLANK_FLIP;
+
+      intel_fb->pf_current_page = (((intel->sarea->pf_current_page >>
+				     (intel_fb->pf_pipes & 0x2)) & 0x3) + 1) %
+				  intel_fb->pf_num_pages;
+   }
+
+   if (!drmCommandWriteRead(intel->driFd, DRM_I915_VBLANK_SWAP, &swap,
+			    sizeof(swap))) {
+      intel_fb->vbl_seq = swap.sequence;
+      swap.sequence -= target;
+      *missed_target = swap.sequence > 0 && swap.sequence <= (1 << 23);
+
+      if (swap.seqtype & DRM_VBLANK_FLIP) {
+	 intel_get_renderbuffer(&intel_fb->Base,
+				BUFFER_FRONT_LEFT)->vbl_pending =
+	    intel_get_renderbuffer(&intel_fb->Base,
+				   BUFFER_BACK_LEFT)->vbl_pending = intel_fb->vbl_seq;
+
+	 intel_flip_renderbuffers(intel_fb);
+	 intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
+      }
+
+      ret = GL_TRUE;
+   } else {
+      if (swap.seqtype & DRM_VBLANK_FLIP) {
+	 intel_fb->pf_current_page = ((intel->sarea->pf_current_page >>
+					(intel_fb->pf_pipes & 0x2)) & 0x3) %
+				     intel_fb->pf_num_pages;
+      }
+
+      ret = GL_FALSE;
+   }
+
+   UNLOCK_HARDWARE(intel);
+
+   return ret;
+}
+  
 void
 intelSwapBuffers(__DRIdrawablePrivate * dPriv)
 {
@@ -786,13 +855,34 @@ intelSwapBuffers(__DRIdrawablePrivate * 
 
       if (ctx->Visual.doubleBufferMode) {
          intelScreenPrivate *screen = intel->intelScreen;
-         _mesa_notifySwapBuffers(ctx);  /* flush pending rendering comands */
-         if (screen->current_rotation != 0 || !intelPageFlip(dPriv)) {
-            intelCopyBuffer(dPriv, NULL);
-         }
-         if (screen->current_rotation != 0) {
-            intelRotateWindow(intel, dPriv, BUFFER_BIT_FRONT_LEFT);
-         }
+	 GLboolean missed_target;
+	 struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
+	 int64_t ust;
+         
+	 _mesa_notifySwapBuffers(ctx);  /* flush pending rendering comands */
+
+         if (screen->current_rotation != 0 ||
+	     !intelScheduleSwap(dPriv, &missed_target)) {
+	    driWaitForVBlank(dPriv, &intel_fb->vbl_seq, intel_fb->vblank_flags,
+			     &missed_target);
+
+	    if (screen->current_rotation != 0 || !intelPageFlip(dPriv)) {
+	       intelCopyBuffer(dPriv, NULL);
+	    }
+
+	    if (screen->current_rotation != 0) {
+	       intelRotateWindow(intel, dPriv, BUFFER_BIT_FRONT_LEFT);
+	    }
+	 }
+
+	 intel_fb->swap_count++;
+	 (*dri_interface->getUST) (&ust);
+	 if (missed_target) {
+	    intel_fb->swap_missed_count++;
+	    intel_fb->swap_missed_ust = ust - intel_fb->swap_ust;
+	 }
+
+	 intel_fb->swap_ust = ust;
       }
    }
    else {
diff --git a/src/mesa/drivers/dri/i915tex/intel_context.c b/src/mesa/drivers/dri/i915tex/intel_context.c
index 649fe54..b1352a7 100644
--- a/src/mesa/drivers/dri/i915tex/intel_context.c
+++ b/src/mesa/drivers/dri/i915tex/intel_context.c
@@ -443,10 +443,6 @@ intelInitContext(struct intel_context *i
 
    intel->do_usleeps = (fthrottle_mode == DRI_CONF_FTHROTTLE_USLEEPS);
 
-   intel->vblank_flags = (intel->intelScreen->irq_active != 0)
-      ? driGetDefaultVBlankFlags(&intel->optionCache) : VBLANK_FLAG_NO_IRQ;
-
-   (*dri_interface->getUST) (&intel->swap_ust);
    _math_matrix_ctr(&intel->ViewportMatrix);
 
    /* Disable imaging extension until convolution is working in
@@ -591,7 +587,12 @@ intelMakeCurrent(__DRIcontextPrivate * d
       if (intel->ctx.DrawBuffer == &intel_fb->Base) {
 
 	 if (intel->driDrawable != driDrawPriv) {
-	    driDrawableInitVBlank(driDrawPriv, intel->vblank_flags, &intel->vbl_seq);	    
+	    intel_fb->vblank_flags = (intel->intelScreen->irq_active != 0)
+	       ? driGetDefaultVBlankFlags(&intel->optionCache)
+	       : VBLANK_FLAG_NO_IRQ;
+	    (*dri_interface->getUST) (&intel_fb->swap_ust);
+	    driDrawableInitVBlank(driDrawPriv, intel_fb->vblank_flags,
+				  &intel_fb->vbl_seq);
 	    intel->driDrawable = driDrawPriv;
 	    intelWindowMoved(intel);
 	 }
@@ -702,19 +703,34 @@ intelContendedLock(struct intel_context 
 void LOCK_HARDWARE( struct intel_context *intel )
 {
     char __ret=0;
-
+    struct intel_framebuffer *intel_fb = NULL;
+    struct intel_renderbuffer *intel_rb = NULL;
     _glthread_LOCK_MUTEX(lockMutex);
     assert(!intel->locked);
 
-    if (intel->swap_scheduled) {
+    if (intel->driDrawable) {
+       intel_fb = intel->driDrawable->driverPrivate;
+
+       if (intel_fb)
+	  intel_rb =
+	     intel_get_renderbuffer(&intel_fb->Base,
+				    intel_fb->Base._ColorDrawBufferMask[0] ==
+				    BUFFER_BIT_FRONT_LEFT ? BUFFER_FRONT_LEFT :
+				    BUFFER_BACK_LEFT);
+    }
+
+    if (intel_rb && (intel_fb->vbl_waited - intel_rb->vbl_pending) > (1<<23)) {
 	drmVBlank vbl;
+
 	vbl.request.type = DRM_VBLANK_ABSOLUTE;
-	if ( intel->vblank_flags & VBLANK_FLAG_SECONDARY ) {
+
+	if ( intel_fb->vblank_flags & VBLANK_FLAG_SECONDARY ) {
 	    vbl.request.type |= DRM_VBLANK_SECONDARY;
 	}
-	vbl.request.sequence = intel->vbl_seq;
+
+	vbl.request.sequence = intel_rb->vbl_pending;
 	drmWaitVBlank(intel->driFd, &vbl);
-	intel->swap_scheduled = 0;
+	intel_fb->vbl_waited = intel_rb->vbl_pending;
     }
 
     DRM_CAS(intel->driHwLock, intel->hHWContext,
diff --git a/src/mesa/drivers/dri/i915tex/intel_context.h b/src/mesa/drivers/dri/i915tex/intel_context.h
index 8f78597..44c20af 100644
--- a/src/mesa/drivers/dri/i915tex/intel_context.h
+++ b/src/mesa/drivers/dri/i915tex/intel_context.h
@@ -274,19 +274,6 @@ struct intel_context
     */
    driOptionCache optionCache;
 
-   /* VBI
-    */
-   GLuint vbl_seq;
-   GLuint vblank_flags;
-
-   int64_t swap_ust;
-   int64_t swap_missed_ust;
-
-   GLuint swap_count;
-   GLuint swap_missed_count;
-
-   GLuint swap_scheduled;
-
   /* Rotation. Need to match that of the
    * current screen.
    */
diff --git a/src/mesa/drivers/dri/i915tex/intel_fbo.h b/src/mesa/drivers/dri/i915tex/intel_fbo.h
index 0446d68..963f5e7 100644
--- a/src/mesa/drivers/dri/i915tex/intel_fbo.h
+++ b/src/mesa/drivers/dri/i915tex/intel_fbo.h
@@ -47,6 +47,18 @@ struct intel_framebuffer
    GLint pf_pipes;
    GLint pf_current_page;
    GLint pf_num_pages;
+
+   /* VBI
+    */
+   GLuint vbl_seq;
+   GLuint vblank_flags;
+   GLuint vbl_waited;
+
+   int64_t swap_ust;
+   int64_t swap_missed_ust;
+
+   GLuint swap_count;
+   GLuint swap_missed_count;
 };
 
 
@@ -68,6 +80,8 @@ struct intel_renderbuffer
    GLuint PairedStencil; /**< only used if this is a stencil renderbuffer */
 
    GLuint pf_pending;  /**< sequence number of pending flip */
+
+   GLuint vbl_pending;   /**< vblank sequence number of pending flip */
 };
 
 
diff --git a/src/mesa/drivers/dri/i915tex/intel_screen.c b/src/mesa/drivers/dri/i915tex/intel_screen.c
index 4763d14..86a3d79 100644
--- a/src/mesa/drivers/dri/i915tex/intel_screen.c
+++ b/src/mesa/drivers/dri/i915tex/intel_screen.c
@@ -679,21 +679,20 @@ intelDestroyBuffer(__DRIdrawablePrivate 
 static int
 intelGetSwapInfo(__DRIdrawablePrivate * dPriv, __DRIswapInfo * sInfo)
 {
-   struct intel_context *intel;
+   struct intel_framebuffer *intel_fb;
 
-   if ((dPriv == NULL) || (dPriv->driContextPriv == NULL)
-       || (dPriv->driContextPriv->driverPrivate == NULL)
+   if ((dPriv == NULL) || (dPriv->driverPrivate == NULL)
        || (sInfo == NULL)) {
       return -1;
    }
 
-   intel = dPriv->driContextPriv->driverPrivate;
-   sInfo->swap_count = intel->swap_count;
-   sInfo->swap_ust = intel->swap_ust;
-   sInfo->swap_missed_count = intel->swap_missed_count;
+   intel_fb = dPriv->driverPrivate;
+   sInfo->swap_count = intel_fb->swap_count;
+   sInfo->swap_ust = intel_fb->swap_ust;
+   sInfo->swap_missed_count = intel_fb->swap_missed_count;
 
    sInfo->swap_missed_usage = (sInfo->swap_missed_count != 0)
-      ? driCalculateSwapUsage(dPriv, 0, intel->swap_missed_ust)
+      ? driCalculateSwapUsage(dPriv, 0, intel_fb->swap_missed_ust)
       : 0.0;
 
    return 0;
diff-tree e33a9d689415e00bded306699abdf93b96c0b9ad (from 356bf9563ed145de5ba4a14c9f23c379293f273a)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Tue Feb 20 19:14:23 2007 +0100

    i915tex: Triple buffering support, only effective with page flipping so far.
    
    Pending flips are tracked per renderbuffer and the colour renderbuffer
    attachments of window framebuffer objects are rotated on flips to avoid
    stalling the pipeline for pending flips unnecessarily.

diff --git a/src/mesa/drivers/dri/i915tex/intel_buffers.c b/src/mesa/drivers/dri/i915tex/intel_buffers.c
index ec2150d..7db5ccf 100644
--- a/src/mesa/drivers/dri/i915tex/intel_buffers.c
+++ b/src/mesa/drivers/dri/i915tex/intel_buffers.c
@@ -214,10 +214,6 @@ intelWindowMoved(struct intel_context *i
       }
    }
 
-   /* Update Mesa's notion of window size */
-   driUpdateFramebufferSize(ctx, dPriv);
-   intel_fb->Base.Initialized = GL_TRUE; /* XXX remove someday */
-
    if (intel->intelScreen->driScrnPriv->ddxMinor >= 7) {
       drmI830Sarea *sarea = intel->sarea;
       drm_clip_rect_t drw_rect = { .x1 = dPriv->x, .x2 = dPriv->x + dPriv->w,
@@ -247,7 +243,9 @@ intelWindowMoved(struct intel_context *i
       intel_fb->pf_current_page = (intel->sarea->pf_current_page >>
 				   (intel_fb->pf_pipes & 0x2)) & 0x3;
 
-      pf_active = (pf_pipes & intel->sarea->pf_active) == pf_pipes;
+      intel_fb->pf_num_pages = intel->intelScreen->third.handle ? 3 : 2;
+
+      pf_active = pf_pipes && (pf_pipes & intel->sarea->pf_active) == pf_pipes;
 
       if (INTEL_DEBUG & DEBUG_LOCK)
 	 if (pf_active != intel_fb->pf_active)
@@ -255,9 +253,13 @@ intelWindowMoved(struct intel_context *i
 			 pf_active ? "" : "in");
 
       if (pf_active) {
-	 if (pf_pipes != intel_fb->pf_pipes && intel_fb->pf_pipes == 0x3 &&
-	     (intel->sarea->pf_current_page & 0x3) !=
-	     ((intel->sarea->pf_current_page) >> 2 & 0x3)) {
+	 int i;
+
+	 /* Sync pages between pipes if we're flipping on both at the same time */
+	 for (i = 0; i < 2 && pf_pipes != intel_fb->pf_pipes &&
+		intel_fb->pf_pipes == 0x3 &&
+		(intel->sarea->pf_current_page & 0x3) !=
+		((intel->sarea->pf_current_page) >> 2 & 0x3); i++) {
 	    drm_i915_flip_t flip;
 
 	    flip.pipes = (intel_fb->pf_current_page ==
@@ -270,7 +272,7 @@ intelWindowMoved(struct intel_context *i
       }
 
       intel_fb->pf_active = pf_active;
-      driFlipRenderbuffers(intel->ctx.WinSysDrawBuffer, intel_fb->pf_current_page);
+      intel_flip_renderbuffers(intel_fb);
       intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
 
       /* Update vblank info
@@ -289,6 +291,10 @@ intelWindowMoved(struct intel_context *i
       intel->vblank_flags &= ~VBLANK_FLAG_SECONDARY;
    }
 
+   /* Update Mesa's notion of window size */
+   driUpdateFramebufferSize(ctx, dPriv);
+   intel_fb->Base.Initialized = GL_TRUE; /* XXX remove someday */
+
    /* Update hardware scissor */
    ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
                        ctx->Scissor.Width, ctx->Scissor.Height);
@@ -472,12 +478,12 @@ intelRotateWindow(struct intel_context *
    intel_fb = dPriv->driverPrivate;
 
    if ((srcBuf == BUFFER_BIT_BACK_LEFT && !intel_fb->pf_active)) {
-      src = intel->intelScreen->back_region;
+      src = intel_get_rb_region(&intel_fb->Base, BUFFER_BACK_LEFT);
       clipRects = dPriv->pBackClipRects;
       numClipRects = dPriv->numBackClipRects;
    }
    else {
-      src = intel->intelScreen->front_region;
+      src = intel_get_rb_region(&intel_fb->Base, BUFFER_FRONT_LEFT);
       clipRects = dPriv->pClipRects;
       numClipRects = dPriv->numClipRects;
    }
@@ -643,8 +649,13 @@ intel_wait_flips(struct intel_context *i
 {
    struct intel_framebuffer *intel_fb =
       (struct intel_framebuffer *) intel->ctx.DrawBuffer;
+   struct intel_renderbuffer *intel_rb =
+      intel_get_renderbuffer(&intel_fb->Base,
+			     intel_fb->Base._ColorDrawBufferMask[0] ==
+			     BUFFER_BIT_FRONT_LEFT ? BUFFER_FRONT_LEFT :
+			     BUFFER_BACK_LEFT);
 
-   if (intel_fb->Base.Name == 0 && intel_fb->flip_pending) {
+   if (intel_fb->Base.Name == 0 && intel_rb->pf_pending == intel_fb->pf_seq) {
       GLuint mi_wait = MI_WAIT_FOR_EVENT;
       GLint pf_pipes = intel_fb->pf_pipes;
       BATCH_LOCALS;
@@ -661,7 +672,7 @@ intel_wait_flips(struct intel_context *i
       OUT_BATCH(0);
       ADVANCE_BATCH();
 
-      intel_fb->flip_pending = GL_FALSE;
+      intel_rb->pf_pending--;
    }
 }
 
@@ -721,10 +732,14 @@ intelPageFlip(const __DRIdrawablePrivate
    intel_fb->pf_current_page = (intel->sarea->pf_current_page >>
 				(intel_fb->pf_pipes & 0x2)) & 0x3;
 
-   driFlipRenderbuffers(intel->ctx.WinSysDrawBuffer, intel_fb->pf_current_page);
-   intel_draw_buffer(&intel->ctx, &intel_fb->Base);
+   if (dPriv->numClipRects != 0) {
+      intel_get_renderbuffer(&intel_fb->Base, BUFFER_FRONT_LEFT)->pf_pending =
+      intel_get_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT)->pf_pending =
+	 ++intel_fb->pf_seq;
+   }
 
-   intel_fb->flip_pending = dPriv->numClipRects != 0;
+   intel_flip_renderbuffers(intel_fb);
+   intel_draw_buffer(&intel->ctx, &intel_fb->Base);
 
    return GL_TRUE;
 }
diff --git a/src/mesa/drivers/dri/i915tex/intel_context.c b/src/mesa/drivers/dri/i915tex/intel_context.c
index 8d90489..649fe54 100644
--- a/src/mesa/drivers/dri/i915tex/intel_context.c
+++ b/src/mesa/drivers/dri/i915tex/intel_context.c
@@ -551,27 +551,30 @@ intelMakeCurrent(__DRIcontextPrivate * d
    if (driContextPriv) {
       struct intel_context *intel =
          (struct intel_context *) driContextPriv->driverPrivate;
-      GLframebuffer *drawFb = (GLframebuffer *) driDrawPriv->driverPrivate;
+      struct intel_framebuffer *intel_fb =
+	 (struct intel_framebuffer *) driDrawPriv->driverPrivate;
       GLframebuffer *readFb = (GLframebuffer *) driReadPriv->driverPrivate;
 
 
       /* XXX FBO temporary fix-ups! */
       /* if the renderbuffers don't have regions, init them from the context */
       {
-         struct intel_renderbuffer *irbFront
-            = intel_get_renderbuffer(drawFb, BUFFER_FRONT_LEFT);
-         struct intel_renderbuffer *irbBack
-            = intel_get_renderbuffer(drawFb, BUFFER_BACK_LEFT);
          struct intel_renderbuffer *irbDepth
-            = intel_get_renderbuffer(drawFb, BUFFER_DEPTH);
+            = intel_get_renderbuffer(&intel_fb->Base, BUFFER_DEPTH);
          struct intel_renderbuffer *irbStencil
-            = intel_get_renderbuffer(drawFb, BUFFER_STENCIL);
+            = intel_get_renderbuffer(&intel_fb->Base, BUFFER_STENCIL);
 
-         if (irbFront && !irbFront->region) {
-            intel_region_reference(&irbFront->region, intel->intelScreen->front_region);
+         if (intel_fb->color_rb[0] && !intel_fb->color_rb[0]->region) {
+            intel_region_reference(&intel_fb->color_rb[0]->region,
+				   intel->intelScreen->front_region);
          }
-         if (irbBack && !irbBack->region) {
-            intel_region_reference(&irbBack->region, intel->intelScreen->back_region);
+         if (intel_fb->color_rb[1] && !intel_fb->color_rb[1]->region) {
+            intel_region_reference(&intel_fb->color_rb[1]->region,
+				   intel->intelScreen->back_region);
+         }
+         if (intel_fb->color_rb[2] && !intel_fb->color_rb[2]->region) {
+            intel_region_reference(&intel_fb->color_rb[2]->region,
+				   intel->intelScreen->third_region);
          }
          if (irbDepth && !irbDepth->region) {
             intel_region_reference(&irbDepth->region, intel->intelScreen->depth_region);
@@ -581,21 +584,11 @@ intelMakeCurrent(__DRIcontextPrivate * d
          }
       }
 
-      /* set initial GLframebuffer size to match window, if needed */
-      if (drawFb->Width == 0 && driDrawPriv->w) {
-         _mesa_resize_framebuffer(&intel->ctx, drawFb,
-                                  driDrawPriv->w, driDrawPriv->h);
-      }         
-      if (readFb->Width == 0 && driReadPriv->w) {
-         _mesa_resize_framebuffer(&intel->ctx, readFb,
-                                  driReadPriv->w, driReadPriv->h);
-      }         
-
-      _mesa_make_current(&intel->ctx, drawFb, readFb);
+      _mesa_make_current(&intel->ctx, &intel_fb->Base, readFb);
 
       /* The drawbuffer won't always be updated by _mesa_make_current: 
        */
-      if (intel->ctx.DrawBuffer == drawFb) {
+      if (intel->ctx.DrawBuffer == &intel_fb->Base) {
 
 	 if (intel->driDrawable != driDrawPriv) {
 	    driDrawableInitVBlank(driDrawPriv, intel->vblank_flags, &intel->vbl_seq);	    
@@ -603,8 +596,18 @@ intelMakeCurrent(__DRIcontextPrivate * d
 	    intelWindowMoved(intel);
 	 }
 
-	 intel_draw_buffer(&intel->ctx, drawFb);
+	 intel_draw_buffer(&intel->ctx, &intel_fb->Base);
       }
+
+      /* set initial GLframebuffer size to match window, if needed */
+      if (&intel_fb->Base.Width == 0 && driDrawPriv->w) {
+         _mesa_resize_framebuffer(&intel->ctx, &intel_fb->Base,
+                                  driDrawPriv->w, driDrawPriv->h);
+      }         
+      if (readFb->Width == 0 && driReadPriv->w) {
+         _mesa_resize_framebuffer(&intel->ctx, readFb,
+                                  driReadPriv->w, driReadPriv->h);
+      }         
    }
    else {
       _mesa_make_current(NULL, NULL, NULL);
diff --git a/src/mesa/drivers/dri/i915tex/intel_fbo.c b/src/mesa/drivers/dri/i915tex/intel_fbo.c
index 104cf1d..ad07845 100644
--- a/src/mesa/drivers/dri/i915tex/intel_fbo.c
+++ b/src/mesa/drivers/dri/i915tex/intel_fbo.c
@@ -71,22 +71,29 @@ intel_renderbuffer(struct gl_renderbuffe
 struct intel_renderbuffer *
 intel_get_renderbuffer(struct gl_framebuffer *fb, GLuint attIndex)
 {
-   if (fb->Name == 0) {
-      struct intel_framebuffer *intel_fb = (struct intel_framebuffer*)fb;
+   return intel_renderbuffer(fb->Attachment[attIndex].Renderbuffer);
+}
 
-      if (intel_fb->pf_current_page) {
-	 switch (attIndex) {
-	 case BUFFER_BACK_LEFT:
-	    attIndex = BUFFER_FRONT_LEFT;
-	    break;
-	 case BUFFER_FRONT_LEFT:
-	    attIndex = BUFFER_BACK_LEFT;
-	    break;
-	 }
-      }
-   }
 
-   return intel_renderbuffer(fb->Attachment[attIndex].Renderbuffer);
+void
+intel_flip_renderbuffers(struct intel_framebuffer *intel_fb)
+{
+   int current_page = intel_fb->pf_current_page;
+   int next_page = (current_page + 1) % intel_fb->pf_num_pages;
+
+   if (intel_fb->Base.Attachment[BUFFER_FRONT_LEFT].Renderbuffer !=
+       &intel_fb->color_rb[current_page]->Base) {
+      _mesa_remove_renderbuffer(&intel_fb->Base, BUFFER_FRONT_LEFT);
+      _mesa_add_renderbuffer(&intel_fb->Base, BUFFER_FRONT_LEFT,
+			     &intel_fb->color_rb[current_page]->Base);
+   }
+
+   if (intel_fb->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer !=
+       &intel_fb->color_rb[next_page]->Base) {
+      _mesa_remove_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT);
+      _mesa_add_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT,
+			     &intel_fb->color_rb[next_page]->Base);
+   }
 }
 
 
@@ -288,10 +295,24 @@ static GLboolean
 intel_alloc_window_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
                            GLenum internalFormat, GLuint width, GLuint height)
 {
+   struct intel_context *intel = intel_context(ctx);
+   struct intel_framebuffer *intel_fb;
+
    ASSERT(rb->Name == 0);
    rb->Width = width;
    rb->Height = height;
    rb->_ActualFormat = internalFormat;
+
+   if (intel && intel->driDrawable &&
+       (intel_fb = intel->driDrawable->driverPrivate) &&
+       intel_fb->pf_num_pages == 3 &&
+       rb == &intel_fb->color_rb[intel_fb->pf_current_page]->Base &&
+       (rb = &intel_fb->color_rb[(intel_fb->pf_current_page + 2) % 3]->Base)) {
+      rb->Width = width;
+      rb->Height = height;
+      rb->_ActualFormat = internalFormat;
+   }
+
    return GL_TRUE;
 }
 
diff --git a/src/mesa/drivers/dri/i915tex/intel_fbo.h b/src/mesa/drivers/dri/i915tex/intel_fbo.h
index d55f029..0446d68 100644
--- a/src/mesa/drivers/dri/i915tex/intel_fbo.h
+++ b/src/mesa/drivers/dri/i915tex/intel_fbo.h
@@ -39,11 +39,14 @@ struct intel_framebuffer
 {
    struct gl_framebuffer Base;
 
+   struct intel_renderbuffer *color_rb[3];
+
    /* Drawable page flipping state */
    GLboolean pf_active;
-   GLboolean flip_pending;
+   GLuint pf_seq;
    GLint pf_pipes;
    GLint pf_current_page;
+   GLint pf_num_pages;
 };
 
 
@@ -63,6 +66,8 @@ struct intel_renderbuffer
 
    GLuint PairedDepth;   /**< only used if this is a depth renderbuffer */
    GLuint PairedStencil; /**< only used if this is a stencil renderbuffer */
+
+   GLuint pf_pending;  /**< sequence number of pending flip */
 };
 
 
@@ -83,6 +88,8 @@ extern struct intel_renderbuffer *intel_
                                                          *fb,
                                                          GLuint attIndex);
 
+extern void intel_flip_renderbuffers(struct intel_framebuffer *intel_fb);
+
 
 /* XXX make inline or macro */
 extern struct intel_region *intel_get_rb_region(struct gl_framebuffer *fb,
diff --git a/src/mesa/drivers/dri/i915tex/intel_screen.c b/src/mesa/drivers/dri/i915tex/intel_screen.c
index f26b3f3..4763d14 100644
--- a/src/mesa/drivers/dri/i915tex/intel_screen.c
+++ b/src/mesa/drivers/dri/i915tex/intel_screen.c
@@ -98,6 +98,18 @@ intelMapScreenRegions(__DRIscreenPrivate
       return GL_FALSE;
    }
 
+   if (intelScreen->third.handle) {
+      if (0)
+	 _mesa_printf("Third 0x%08x ", intelScreen->third.handle);
+      if (drmMap(sPriv->fd,
+		 intelScreen->third.handle,
+		 intelScreen->third.size,
+		 (drmAddress *) & intelScreen->third.map) != 0) {
+	 intelUnmapScreenRegions(intelScreen);
+	 return GL_FALSE;
+      }
+   }
+
    if (0)
       _mesa_printf("Depth 0x%08x ", intelScreen->depth.handle);
    if (drmMap(sPriv->fd,
@@ -119,9 +131,9 @@ intelMapScreenRegions(__DRIscreenPrivate
    }
 #endif
    if (0)
-      printf("Mappings:  front: %p  back: %p  depth: %p  tex: %p\n",
+      printf("Mappings:  front: %p  back: %p  third: %p  depth: %p  tex: %p\n",
              intelScreen->front.map,
-             intelScreen->back.map,
+             intelScreen->back.map, intelScreen->third.map,
              intelScreen->depth.map, intelScreen->tex.map);
    return GL_TRUE;
 }
@@ -191,6 +203,18 @@ intel_recreate_static_regions(intelScree
 			    intelScreen->back.pitch / intelScreen->cpp,
 			    intelScreen->height);
 
+   if (intelScreen->third.handle) {
+      intelScreen->third_region =
+	 intel_recreate_static(intelScreen,
+			       intelScreen->third_region,
+			       DRM_BO_FLAG_MEM_TT,
+			       intelScreen->third.offset,
+			       intelScreen->third.map,
+			       intelScreen->cpp,
+			       intelScreen->third.pitch / intelScreen->cpp,
+			       intelScreen->height);
+   }
+
    /* Still assuming front.cpp == depth.cpp
     */
    intelScreen->depth_region =
@@ -240,6 +264,13 @@ intelUnmapScreenRegions(intelScreenPriva
 #endif
       intelScreen->back.map = NULL;
    }
+   if (intelScreen->third.map) {
+#if REALLY_UNMAP
+      if (drmUnmap(intelScreen->third.map, intelScreen->third.size) != 0)
+         printf("drmUnmap third failed!\n");
+#endif
+      intelScreen->third.map = NULL;
+   }
    if (intelScreen->depth.map) {
 #if REALLY_UNMAP
       drmUnmap(intelScreen->depth.map, intelScreen->depth.size);
@@ -325,6 +356,13 @@ intelUpdateScreenFromSAREA(intelScreenPr
    intelScreen->back.handle = sarea->back_handle;
    intelScreen->back.size = sarea->back_size;
 
+   if (intelScreen->driScrnPriv->ddxMinor >= 8) {
+      intelScreen->third.offset = sarea->third_offset;
+      intelScreen->third.pitch = sarea->pitch * intelScreen->cpp;
+      intelScreen->third.handle = sarea->third_handle;
+      intelScreen->third.size = sarea->third_size;
+   }
+
    intelScreen->depth.offset = sarea->depth_offset;
    intelScreen->depth.pitch = sarea->pitch * intelScreen->cpp;
    intelScreen->depth.handle = sarea->depth_handle;
@@ -550,29 +588,40 @@ intelCreateBuffer(__DRIscreenPrivate * d
 
       /* setup the hardware-based renderbuffers */
       {
-         struct intel_renderbuffer *frontRb
+         intel_fb->color_rb[0]
             = intel_create_renderbuffer(rgbFormat,
                                         screen->width, screen->height,
                                         screen->front.offset,
                                         screen->front.pitch,
                                         screen->cpp,
                                         screen->front.map);
-         intel_set_span_functions(&frontRb->Base);
+         intel_set_span_functions(&intel_fb->color_rb[0]->Base);
          _mesa_add_renderbuffer(&intel_fb->Base, BUFFER_FRONT_LEFT,
-				&frontRb->Base);
+				&intel_fb->color_rb[0]->Base);
       }
 
       if (mesaVis->doubleBufferMode) {
-         struct intel_renderbuffer *backRb
+         intel_fb->color_rb[1]
             = intel_create_renderbuffer(rgbFormat,
                                         screen->width, screen->height,
                                         screen->back.offset,
                                         screen->back.pitch,
                                         screen->cpp,
                                         screen->back.map);
-         intel_set_span_functions(&backRb->Base);
+         intel_set_span_functions(&intel_fb->color_rb[1]->Base);
          _mesa_add_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT,
-				&backRb->Base);
+				&intel_fb->color_rb[1]->Base);
+
+	 if (screen->third.handle) {
+	    intel_fb->color_rb[2]
+	       = intel_create_renderbuffer(rgbFormat,
+					   screen->width, screen->height,
+					   screen->third.offset,
+					   screen->third.pitch,
+					   screen->cpp,
+					   screen->third.map);
+	    intel_set_span_functions(&intel_fb->color_rb[2]->Base);
+	 }
       }
 
       if (mesaVis->depthBits == 24 && mesaVis->stencilBits == 8) {
diff --git a/src/mesa/drivers/dri/i915tex/intel_screen.h b/src/mesa/drivers/dri/i915tex/intel_screen.h
index 1769877..05e2f1f 100644
--- a/src/mesa/drivers/dri/i915tex/intel_screen.h
+++ b/src/mesa/drivers/dri/i915tex/intel_screen.h
@@ -51,12 +51,14 @@ typedef struct
 {
    intelRegion front;
    intelRegion back;
+   intelRegion third;
    intelRegion rotated;
    intelRegion depth;
    intelRegion tex;
 
    struct intel_region *front_region;
    struct intel_region *back_region;
+   struct intel_region *third_region;
    struct intel_region *depth_region;
    struct intel_region *rotated_region;
 
diff --git a/src/mesa/drivers/dri/i915tex/server/i830_common.h b/src/mesa/drivers/dri/i915tex/server/i830_common.h
index 06f28ed..d4d5888 100644
--- a/src/mesa/drivers/dri/i915tex/server/i830_common.h
+++ b/src/mesa/drivers/dri/i915tex/server/i830_common.h
@@ -129,6 +129,12 @@ typedef struct {
 	int pipeB_y;
 	int pipeB_w;
 	int pipeB_h;
+
+	/* Triple buffering */
+	drm_handle_t third_handle;
+	int third_offset;
+	int third_size;
+	unsigned int third_tiled;
 } drmI830Sarea;
 
 /* Flags for perf_boxes
diff-tree 356bf9563ed145de5ba4a14c9f23c379293f273a (from bfbc1de02ea5a26dc9c05bdd267aa933f04891c8)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Thu Feb 15 18:43:46 2007 +0100

    intelWindowMoved: Some debugging output was accidentally left always enabled.

diff --git a/src/mesa/drivers/dri/i915tex/intel_buffers.c b/src/mesa/drivers/dri/i915tex/intel_buffers.c
index f51b0af..ec2150d 100644
--- a/src/mesa/drivers/dri/i915tex/intel_buffers.c
+++ b/src/mesa/drivers/dri/i915tex/intel_buffers.c
@@ -249,7 +249,7 @@ intelWindowMoved(struct intel_context *i
 
       pf_active = (pf_pipes & intel->sarea->pf_active) == pf_pipes;
 
-      if (1 /*INTEL_DEBUG & DEBUG_LOCK*/)
+      if (INTEL_DEBUG & DEBUG_LOCK)
 	 if (pf_active != intel_fb->pf_active)
 	    _mesa_printf("%s - Page flipping %sactive\n", __progname,
 			 pf_active ? "" : "in");
diff-tree bfbc1de02ea5a26dc9c05bdd267aa933f04891c8 (from 6f2bf34748c2dfcff09216132c48377db7d6f17d)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Thu Feb 15 18:41:40 2007 +0100

    intelRotateWindow: Only use back buffer and cliprects in very specific cases.

diff --git a/src/mesa/drivers/dri/i915tex/intel_buffers.c b/src/mesa/drivers/dri/i915tex/intel_buffers.c
index fdb6ea9..f51b0af 100644
--- a/src/mesa/drivers/dri/i915tex/intel_buffers.c
+++ b/src/mesa/drivers/dri/i915tex/intel_buffers.c
@@ -471,17 +471,16 @@ intelRotateWindow(struct intel_context *
 
    intel_fb = dPriv->driverPrivate;
 
-   if ((srcBuf == BUFFER_BIT_BACK_LEFT && intel_fb->pf_current_page) ||
-       (srcBuf == BUFFER_BIT_FRONT_LEFT && !intel_fb->pf_current_page)) {
-      src = intel->intelScreen->front_region;
-      clipRects = dPriv->pClipRects;
-      numClipRects = dPriv->numClipRects;
-   }
-   else {
+   if ((srcBuf == BUFFER_BIT_BACK_LEFT && !intel_fb->pf_active)) {
       src = intel->intelScreen->back_region;
       clipRects = dPriv->pBackClipRects;
       numClipRects = dPriv->numBackClipRects;
    }
+   else {
+      src = intel->intelScreen->front_region;
+      clipRects = dPriv->pClipRects;
+      numClipRects = dPriv->numClipRects;
+   }
 
    if (src->cpp == 4) {
       format = GL_BGRA;
diff-tree 6f2bf34748c2dfcff09216132c48377db7d6f17d (from 6b99cafd69a791d03ce749d0fd2b9f59ca265677)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Thu Feb 15 18:33:53 2007 +0100

    intelCopyBuffer: Remove incorrect intel_fb->pf_current_page tests.
    
    intel_get_rb_region already takes the current page into account.
    
    This would result in broken rendering when multiple 3D windows are visible
    and the pages are reversed.

diff --git a/src/mesa/drivers/dri/i915tex/intel_blit.c b/src/mesa/drivers/dri/i915tex/intel_blit.c
index e33d283..640c73e 100644
--- a/src/mesa/drivers/dri/i915tex/intel_blit.c
+++ b/src/mesa/drivers/dri/i915tex/intel_blit.c
@@ -184,25 +184,12 @@ noschedule:
 	    OUT_BATCH((pbox->y1 << 16) | pbox->x1);
 	    OUT_BATCH((pbox->y2 << 16) | pbox->x2);
 
-	    if (intel_fb->pf_current_page == 0)
-	       OUT_RELOC(frontRegion->buffer,
-			 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
-			 DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, 0);
-	    else
-	       OUT_RELOC(backRegion->buffer,
-			 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
-			 DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, 0);
+	    OUT_RELOC(frontRegion->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
+		      DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, 0);
 	    OUT_BATCH((pbox->y1 << 16) | pbox->x1);
 	    OUT_BATCH(BR13 & 0xffff);
-
-	    if (intel_fb->pf_current_page == 0)
-	       OUT_RELOC(backRegion->buffer,
-			 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ,
-			 DRM_BO_MASK_MEM | DRM_BO_FLAG_READ, 0);
-	    else
-	       OUT_RELOC(frontRegion->buffer,
-			 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ,
-			 DRM_BO_MASK_MEM | DRM_BO_FLAG_READ, 0);
+	    OUT_RELOC(backRegion->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ,
+		      DRM_BO_MASK_MEM | DRM_BO_FLAG_READ, 0);
 
 	    ADVANCE_BATCH();
 	 }
diff-tree 6b99cafd69a791d03ce749d0fd2b9f59ca265677 (from af64dd2ae0aa31261002335f10d46492000f552b)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Thu Feb 15 16:30:40 2007 +0100

    i915tex: Support page flipping on both CRTCs independently.
    
    No longer track page flipping state per context but per window, via struct
    intel_framebuffer which wraps struct gl_framebuffer for windows.

diff --git a/src/mesa/drivers/dri/i915tex/intel_blit.c b/src/mesa/drivers/dri/i915tex/intel_blit.c
index c08c45a..e33d283 100644
--- a/src/mesa/drivers/dri/i915tex/intel_blit.c
+++ b/src/mesa/drivers/dri/i915tex/intel_blit.c
@@ -123,14 +123,13 @@ noschedule:
        */
       LOCK_HARDWARE(intel);
 
-      if (intel->driDrawable && intel->driDrawable->numClipRects) {
+      if (dPriv && dPriv->numClipRects) {
 	 const intelScreenPrivate *intelScreen = intel->intelScreen;
-	 struct gl_framebuffer *fb
-	    = (struct gl_framebuffer *) dPriv->driverPrivate;
+	 struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
 	 const struct intel_region *frontRegion
-	    = intel_get_rb_region(fb, BUFFER_FRONT_LEFT);
+	    = intel_get_rb_region(&intel_fb->Base, BUFFER_FRONT_LEFT);
 	 const struct intel_region *backRegion
-	    = intel_get_rb_region(fb, BUFFER_BACK_LEFT);
+	    = intel_get_rb_region(&intel_fb->Base, BUFFER_BACK_LEFT);
 	 const int nbox = dPriv->numClipRects;
 	 const drm_clip_rect_t *pbox = dPriv->pClipRects;
 	 const int pitch = frontRegion->pitch;
@@ -138,8 +137,8 @@ noschedule:
 	 int BR13, CMD;
 	 int i;
 
-	 ASSERT(fb);
-	 ASSERT(fb->Name == 0);    /* Not a user-created FBO */
+	 ASSERT(intel_fb);
+	 ASSERT(intel_fb->Base.Name == 0);    /* Not a user-created FBO */
 	 ASSERT(frontRegion);
 	 ASSERT(backRegion);
 	 ASSERT(frontRegion->pitch == backRegion->pitch);
@@ -185,7 +184,7 @@ noschedule:
 	    OUT_BATCH((pbox->y1 << 16) | pbox->x1);
 	    OUT_BATCH((pbox->y2 << 16) | pbox->x2);
 
-	    if (intel->sarea->pf_current_page == 0)
+	    if (intel_fb->pf_current_page == 0)
 	       OUT_RELOC(frontRegion->buffer,
 			 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
 			 DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, 0);
@@ -196,7 +195,7 @@ noschedule:
 	    OUT_BATCH((pbox->y1 << 16) | pbox->x1);
 	    OUT_BATCH(BR13 & 0xffff);
 
-	    if (intel->sarea->pf_current_page == 0)
+	    if (intel_fb->pf_current_page == 0)
 	       OUT_RELOC(backRegion->buffer,
 			 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ,
 			 DRM_BO_MASK_MEM | DRM_BO_FLAG_READ, 0);
@@ -406,6 +405,7 @@ void
 intelClearWithBlit(GLcontext * ctx, GLbitfield mask)
 {
    struct intel_context *intel = intel_context(ctx);
+   struct gl_framebuffer *fb = ctx->DrawBuffer;
    GLuint clear_depth;
    GLbitfield skipBuffers = 0;
    BATCH_LOCALS;
@@ -417,7 +417,7 @@ intelClearWithBlit(GLcontext * ctx, GLbi
     */
    clear_depth = 0;
    if (mask & BUFFER_BIT_DEPTH) {
-      clear_depth = (GLuint) (ctx->DrawBuffer->_DepthMax * ctx->Depth.Clear);
+      clear_depth = (GLuint) (fb->_DepthMax * ctx->Depth.Clear);
    }
    if (mask & BUFFER_BIT_STENCIL) {
       clear_depth |= (ctx->Stencil.Clear & 0xff) << 24;
@@ -440,12 +440,12 @@ intelClearWithBlit(GLcontext * ctx, GLbi
       int i;
 
       /* Get clear bounds after locking */
-      cx = ctx->DrawBuffer->_Xmin;
-      cy = ctx->DrawBuffer->_Ymin;
-      cw = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
-      ch = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
+      cx = fb->_Xmin;
+      cy = fb->_Ymin;
+      cw = fb->_Xmax - cx;
+      ch = fb->_Ymax - cy;
 
-      if (intel->ctx.DrawBuffer->Name == 0) {
+      if (fb->Name == 0) {
          /* clearing a window */
 
          /* flip top to bottom */
@@ -470,8 +470,7 @@ intelClearWithBlit(GLcontext * ctx, GLbi
          drm_clip_rect_t b;
          GLuint buf;
          GLuint clearMask = mask;      /* use copy, since we modify it below */
-         GLboolean all = (cw == ctx->DrawBuffer->Width &&
-                          ch == ctx->DrawBuffer->Height);
+         GLboolean all = (cw == fb->Width && ch == fb->Height);
 
          if (!all) {
             intel_intersect_cliprects(&b, &clear, box);
@@ -490,7 +489,7 @@ intelClearWithBlit(GLcontext * ctx, GLbi
             if ((clearMask & bufBit) && !(bufBit & skipBuffers)) {
                /* OK, clear this renderbuffer */
                struct intel_region *irb_region =
-		  intel_get_rb_region(ctx->DrawBuffer, buf);
+		  intel_get_rb_region(fb, buf);
                struct _DriBufferObject *write_buffer =
                   intel_region_buffer(intel->intelScreen, irb_region,
                                       all ? INTEL_WRITE_FULL :
@@ -546,15 +545,7 @@ intelClearWithBlit(GLcontext * ctx, GLbi
                   _mesa_debug(ctx, "hardware blit clear buf %d rb id %d\n",
                   buf, irb->Base.Name);
                 */
-	       if (intel->flip_pending) {
-		  /* Wait for a pending flip to take effect */
-		  BEGIN_BATCH(2, INTEL_BATCH_NO_CLIPRECTS);
-		  OUT_BATCH(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP);
-		  OUT_BATCH(0);
-		  ADVANCE_BATCH();
-
-		  intel->flip_pending = GL_FALSE;
-	       }
+	       intel_wait_flips(intel, INTEL_BATCH_NO_CLIPRECTS);
 
                BEGIN_BATCH(6, INTEL_BATCH_NO_CLIPRECTS);
                OUT_BATCH(CMD);
diff --git a/src/mesa/drivers/dri/i915tex/intel_buffers.c b/src/mesa/drivers/dri/i915tex/intel_buffers.c
index a8fb0b1..fdb6ea9 100644
--- a/src/mesa/drivers/dri/i915tex/intel_buffers.c
+++ b/src/mesa/drivers/dri/i915tex/intel_buffers.c
@@ -34,6 +34,7 @@
 #include "intel_tris.h"
 #include "intel_regions.h"
 #include "intel_batchbuffer.h"
+#include "intel_reg.h"
 #include "context.h"
 #include "utils.h"
 #include "drirenderbuffer.h"
@@ -155,11 +156,14 @@ static void
 intelSetBackClipRects(struct intel_context *intel)
 {
    __DRIdrawablePrivate *dPriv = intel->driDrawable;
+   struct intel_framebuffer *intel_fb;
 
    if (!dPriv)
       return;
 
-   if (intel->sarea->pf_active || dPriv->numBackClipRects == 0) {
+   intel_fb = dPriv->driverPrivate;
+
+   if (intel_fb->pf_active || dPriv->numBackClipRects == 0) {
       /* use the front clip rects */
       intel->numClipRects = dPriv->numClipRects;
       intel->pClipRects = dPriv->pClipRects;
@@ -185,7 +189,7 @@ intelWindowMoved(struct intel_context *i
 {
    GLcontext *ctx = &intel->ctx;
    __DRIdrawablePrivate *dPriv = intel->driDrawable;
-   GLframebuffer *drawFb = (GLframebuffer *) dPriv->driverPrivate;
+   struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
 
    if (!intel->ctx.DrawBuffer) {
       /* when would this happen? -BP */
@@ -197,7 +201,7 @@ intelWindowMoved(struct intel_context *i
    }
    else {
       /* drawing to a window */
-      switch (drawFb->_ColorDrawBufferMask[0]) {
+      switch (intel_fb->Base._ColorDrawBufferMask[0]) {
       case BUFFER_BIT_FRONT_LEFT:
          intelSetFrontClipRects(intel);
          break;
@@ -212,7 +216,7 @@ intelWindowMoved(struct intel_context *i
 
    /* Update Mesa's notion of window size */
    driUpdateFramebufferSize(ctx, dPriv);
-   drawFb->Initialized = GL_TRUE; /* XXX remove someday */
+   intel_fb->Base.Initialized = GL_TRUE; /* XXX remove someday */
 
    if (intel->intelScreen->driScrnPriv->ddxMinor >= 7) {
       drmI830Sarea *sarea = intel->sarea;
@@ -227,7 +231,50 @@ intelWindowMoved(struct intel_context *i
       GLint areaA = driIntersectArea( drw_rect, pipeA_rect );
       GLint areaB = driIntersectArea( drw_rect, pipeB_rect );
       GLuint flags = intel->vblank_flags;
+      GLboolean pf_active;
+      GLint pf_pipes;
+
+      /* Update page flipping info
+       */
+      pf_pipes = 0;
+
+      if (areaA > 0)
+	 pf_pipes |= 1;
+
+      if (areaB > 0)
+	 pf_pipes |= 2;
+
+      intel_fb->pf_current_page = (intel->sarea->pf_current_page >>
+				   (intel_fb->pf_pipes & 0x2)) & 0x3;
+
+      pf_active = (pf_pipes & intel->sarea->pf_active) == pf_pipes;
+
+      if (1 /*INTEL_DEBUG & DEBUG_LOCK*/)
+	 if (pf_active != intel_fb->pf_active)
+	    _mesa_printf("%s - Page flipping %sactive\n", __progname,
+			 pf_active ? "" : "in");
+
+      if (pf_active) {
+	 if (pf_pipes != intel_fb->pf_pipes && intel_fb->pf_pipes == 0x3 &&
+	     (intel->sarea->pf_current_page & 0x3) !=
+	     ((intel->sarea->pf_current_page) >> 2 & 0x3)) {
+	    drm_i915_flip_t flip;
+
+	    flip.pipes = (intel_fb->pf_current_page ==
+			  (intel->sarea->pf_current_page & 0x3)) ? 0x2 : 0x1;
+
+	    drmCommandWrite(intel->driFd, DRM_I915_FLIP, &flip, sizeof(flip));
+	 }
+
+	 intel_fb->pf_pipes = pf_pipes;
+      }
+
+      intel_fb->pf_active = pf_active;
+      driFlipRenderbuffers(intel->ctx.WinSysDrawBuffer, intel_fb->pf_current_page);
+      intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
 
+      /* Update vblank info
+       */
       if (areaB > areaA || (areaA == areaB && areaB > 0)) {
 	 flags = intel->vblank_flags | VBLANK_FLAG_SECONDARY;
       } else {
@@ -259,6 +306,7 @@ static void
 intelClearWithTris(struct intel_context *intel, GLbitfield mask)
 {
    GLcontext *ctx = &intel->ctx;
+   struct gl_framebuffer *fb = ctx->DrawBuffer;
    drm_clip_rect_t clear;
 
    if (INTEL_DEBUG & DEBUG_BLIT)
@@ -274,10 +322,10 @@ intelClearWithTris(struct intel_context 
       intel->vtbl.install_meta_state(intel);
 
       /* Get clear bounds after locking */
-      cx = ctx->DrawBuffer->_Xmin;
-      cy = ctx->DrawBuffer->_Ymin;
-      ch = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
-      cw = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
+      cx = fb->_Xmin;
+      cy = fb->_Ymin;
+      ch = fb->_Ymax - cx;
+      cw = fb->_Xmax - cy;
 
       /* note: regardless of 'all', cx, cy, cw, ch are now correct */
       clear.x1 = cx;
@@ -291,9 +339,9 @@ intelClearWithTris(struct intel_context 
       if (mask &
           (BUFFER_BIT_BACK_LEFT | BUFFER_BIT_STENCIL | BUFFER_BIT_DEPTH)) {
          struct intel_region *backRegion =
-            intel_get_rb_region(ctx->DrawBuffer, BUFFER_BACK_LEFT);
+            intel_get_rb_region(fb, BUFFER_BACK_LEFT);
          struct intel_region *depthRegion =
-            intel_get_rb_region(ctx->DrawBuffer, BUFFER_DEPTH);
+            intel_get_rb_region(fb, BUFFER_DEPTH);
          const GLuint clearColor = (backRegion && backRegion->cpp == 4)
             ? intel->ClearColor8888 : intel->ClearColor565;
 
@@ -330,8 +378,7 @@ intelClearWithTris(struct intel_context 
          const GLuint bufBit = 1 << buf;
          if (mask & bufBit) {
             struct intel_renderbuffer *irbColor =
-               intel_renderbuffer(ctx->DrawBuffer->
-                                  Attachment[buf].Renderbuffer);
+               intel_renderbuffer(fb->Attachment[buf].Renderbuffer);
             GLuint color = (irbColor->region->cpp == 4)
                ? intel->ClearColor8888 : intel->ClearColor565;
 
@@ -372,6 +419,7 @@ intelRotateWindow(struct intel_context *
 {
    intelScreenPrivate *screen = intel->intelScreen;
    drm_clip_rect_t fullRect;
+   struct intel_framebuffer *intel_fb;
    struct intel_region *src;
    const drm_clip_rect_t *clipRects;
    int numClipRects;
@@ -421,8 +469,10 @@ intelRotateWindow(struct intel_context *
 
    intel->vtbl.meta_draw_region(intel, screen->rotated_region, NULL);    /* ? */
 
-   if ((srcBuf == BUFFER_BIT_BACK_LEFT && intel->sarea->pf_current_page) ||
-       (srcBuf == BUFFER_BIT_FRONT_LEFT && !intel->sarea->pf_current_page)) {
+   intel_fb = dPriv->driverPrivate;
+
+   if ((srcBuf == BUFFER_BIT_BACK_LEFT && intel_fb->pf_current_page) ||
+       (srcBuf == BUFFER_BIT_FRONT_LEFT && !intel_fb->pf_current_page)) {
       src = intel->intelScreen->front_region;
       clipRects = dPriv->pClipRects;
       numClipRects = dPriv->numClipRects;
@@ -517,6 +567,7 @@ intelClear(GLcontext *ctx, GLbitfield ma
    GLbitfield tri_mask = 0;
    GLbitfield blit_mask = 0;
    GLbitfield swrast_mask = 0;
+   struct gl_framebuffer *fb = ctx->DrawBuffer;
    GLuint i;
 
    if (0)
@@ -536,7 +587,7 @@ intelClear(GLcontext *ctx, GLbitfield ma
    /* HW stencil */
    if (mask & BUFFER_BIT_STENCIL) {
       const struct intel_region *stencilRegion
-         = intel_get_rb_region(ctx->DrawBuffer, BUFFER_STENCIL);
+         = intel_get_rb_region(fb, BUFFER_STENCIL);
       if (stencilRegion) {
          /* have hw stencil */
          if ((ctx->Stencil.WriteMask[0] & 0xff) != 0xff) {
@@ -565,7 +616,7 @@ intelClear(GLcontext *ctx, GLbitfield ma
    for (i = 0; i < BUFFER_COUNT; i++) {
       GLuint bufBit = 1 << i;
       if ((blit_mask | tri_mask) & bufBit) {
-         if (!ctx->DrawBuffer->Attachment[i].Renderbuffer->ClassID) {
+         if (!fb->Attachment[i].Renderbuffer->ClassID) {
             blit_mask &= ~bufBit;
             tri_mask &= ~bufBit;
             swrast_mask |= bufBit;
@@ -587,15 +638,44 @@ intelClear(GLcontext *ctx, GLbitfield ma
 }
 
 
+/* Emit wait for pending flips */
+void
+intel_wait_flips(struct intel_context *intel, GLuint batch_flags)
+{
+   struct intel_framebuffer *intel_fb =
+      (struct intel_framebuffer *) intel->ctx.DrawBuffer;
+
+   if (intel_fb->Base.Name == 0 && intel_fb->flip_pending) {
+      GLuint mi_wait = MI_WAIT_FOR_EVENT;
+      GLint pf_pipes = intel_fb->pf_pipes;
+      BATCH_LOCALS;
+
+      if (pf_pipes & 0x1)
+	mi_wait |= MI_WAIT_FOR_PLANE_A_FLIP;
+
+      if (pf_pipes & 0x2)
+	mi_wait |= MI_WAIT_FOR_PLANE_B_FLIP;
+
+      /* Wait for pending flips to take effect */
+      BEGIN_BATCH(2, batch_flags);
+      OUT_BATCH(mi_wait);
+      OUT_BATCH(0);
+      ADVANCE_BATCH();
+
+      intel_fb->flip_pending = GL_FALSE;
+   }
+}
+
 
 /* Flip the front & back buffers
  */
-static void
+static GLboolean
 intelPageFlip(const __DRIdrawablePrivate * dPriv)
 {
    struct intel_context *intel;
    GLboolean missed_target;
    int ret;
+   struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
 
    if (INTEL_DEBUG & DEBUG_IOCTL)
       fprintf(stderr, "%s\n", __FUNCTION__);
@@ -606,6 +686,9 @@ intelPageFlip(const __DRIdrawablePrivate
 
    intel = (struct intel_context *) dPriv->driContextPriv->driverPrivate;
 
+   if (intel->intelScreen->drmMinor < 9)
+      return GL_FALSE;
+
    intelFlush(&intel->ctx);
 
    driWaitForVBlank(dPriv, &intel->vbl_seq, intel->vblank_flags, &missed_target);
@@ -615,28 +698,36 @@ intelPageFlip(const __DRIdrawablePrivate
       (void)(*dri_interface->getUST) (&intel->swap_missed_ust);
    }
 
+   ret = 0;
+
    LOCK_HARDWARE(intel);
 
-   if (!dPriv->numClipRects) {
-      UNLOCK_HARDWARE(intel);
-      usleep(10000);	/* throttle invisible client 10ms */
-      return;
+   if (dPriv->numClipRects && intel_fb->pf_active) {
+      drm_i915_flip_t flip;
+
+      flip.pipes = intel_fb->pf_pipes;
+
+      ret = drmCommandWrite(intel->driFd, DRM_I915_FLIP, &flip, sizeof(flip));
    }
 
-   ret = drmCommandNone(intel->driFd, DRM_I830_FLIP);
    UNLOCK_HARDWARE(intel);
 
-   if (ret) {
-      _mesa_error(&intel->ctx, GL_INVALID_OPERATION, "DRM_I830_FLIP: %d\n",
-		  ret);
-      return;
+   if (ret || !intel_fb->pf_active)
+      return GL_FALSE;
+
+   if (!dPriv->numClipRects) {
+      usleep(10000);	/* throttle invisible client 10ms */
    }
 
-   driFlipRenderbuffers(intel->ctx.WinSysDrawBuffer,
-			intel->sarea->pf_current_page);
-   intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
+   intel_fb->pf_current_page = (intel->sarea->pf_current_page >>
+				(intel_fb->pf_pipes & 0x2)) & 0x3;
+
+   driFlipRenderbuffers(intel->ctx.WinSysDrawBuffer, intel_fb->pf_current_page);
+   intel_draw_buffer(&intel->ctx, &intel_fb->Base);
 
-   intel->flip_pending = GL_TRUE;
+   intel_fb->flip_pending = dPriv->numClipRects != 0;
+
+   return GL_TRUE;
 }
 
 #if 0
@@ -682,10 +773,7 @@ intelSwapBuffers(__DRIdrawablePrivate * 
       if (ctx->Visual.doubleBufferMode) {
          intelScreenPrivate *screen = intel->intelScreen;
          _mesa_notifySwapBuffers(ctx);  /* flush pending rendering comands */
-         if (screen->current_rotation == 0 && intel->doPageFlip) {
-            intelPageFlip(dPriv);
-         }
-         else {
+         if (screen->current_rotation != 0 || !intelPageFlip(dPriv)) {
             intelCopyBuffer(dPriv, NULL);
          }
          if (screen->current_rotation != 0) {
diff --git a/src/mesa/drivers/dri/i915tex/intel_buffers.h b/src/mesa/drivers/dri/i915tex/intel_buffers.h
index 0faf055..3b686cb 100644
--- a/src/mesa/drivers/dri/i915tex/intel_buffers.h
+++ b/src/mesa/drivers/dri/i915tex/intel_buffers.h
@@ -30,6 +30,7 @@
 
 
 struct intel_context;
+struct intel_framebuffer;
 
 
 extern GLboolean
@@ -41,6 +42,8 @@ extern struct intel_region *intel_readbu
 
 extern struct intel_region *intel_drawbuf_region(struct intel_context *intel);
 
+extern void intel_wait_flips(struct intel_context *intel, GLuint batch_flags);
+
 extern void intelSwapBuffers(__DRIdrawablePrivate * dPriv);
 
 extern void intelWindowMoved(struct intel_context *intel);
diff --git a/src/mesa/drivers/dri/i915tex/intel_context.c b/src/mesa/drivers/dri/i915tex/intel_context.c
index 7eb209c..8d90489 100644
--- a/src/mesa/drivers/dri/i915tex/intel_context.c
+++ b/src/mesa/drivers/dri/i915tex/intel_context.c
@@ -690,21 +690,10 @@ intelContendedLock(struct intel_context 
       intelWindowMoved(intel);
       intel->lastStamp = dPriv->lastStamp;
    }
-
-   /* Update page flipping info
-    */
-   if (INTEL_DEBUG & DEBUG_LOCK)
-      if (intel->doPageFlip != intel->sarea->pf_active)
-	 _mesa_printf("%s - age flipping %sactive\n", __progname,
-		      intel->sarea->pf_active ? "" : "in");
-
-   intel->doPageFlip = intel->sarea->pf_active;
-   driFlipRenderbuffers(intel->ctx.WinSysDrawBuffer,
-			intel->sarea->pf_current_page);
-   intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
 }
 
 
+
 /* Lock the hardware and validate our state.  
  */
 void LOCK_HARDWARE( struct intel_context *intel )
diff --git a/src/mesa/drivers/dri/i915tex/intel_context.h b/src/mesa/drivers/dri/i915tex/intel_context.h
index 321a945..8f78597 100644
--- a/src/mesa/drivers/dri/i915tex/intel_context.h
+++ b/src/mesa/drivers/dri/i915tex/intel_context.h
@@ -294,11 +294,6 @@ struct intel_context
   int width;
   int height;
   int current_rotation;
-
-  /* Page flipping
-   */
-  GLboolean doPageFlip;
-  GLboolean flip_pending;
 };
 
 /* These are functions now:
diff --git a/src/mesa/drivers/dri/i915tex/intel_fbo.c b/src/mesa/drivers/dri/i915tex/intel_fbo.c
index b739e22..104cf1d 100644
--- a/src/mesa/drivers/dri/i915tex/intel_fbo.c
+++ b/src/mesa/drivers/dri/i915tex/intel_fbo.c
@@ -71,6 +71,21 @@ intel_renderbuffer(struct gl_renderbuffe
 struct intel_renderbuffer *
 intel_get_renderbuffer(struct gl_framebuffer *fb, GLuint attIndex)
 {
+   if (fb->Name == 0) {
+      struct intel_framebuffer *intel_fb = (struct intel_framebuffer*)fb;
+
+      if (intel_fb->pf_current_page) {
+	 switch (attIndex) {
+	 case BUFFER_BACK_LEFT:
+	    attIndex = BUFFER_FRONT_LEFT;
+	    break;
+	 case BUFFER_FRONT_LEFT:
+	    attIndex = BUFFER_BACK_LEFT;
+	    break;
+	 }
+      }
+   }
+
    return intel_renderbuffer(fb->Attachment[attIndex].Renderbuffer);
 }
 
@@ -78,22 +93,7 @@ intel_get_renderbuffer(struct gl_framebu
 struct intel_region *
 intel_get_rb_region(struct gl_framebuffer *fb, GLuint attIndex)
 {
-   GET_CURRENT_CONTEXT(ctx);
-   struct intel_context *intel = intel_context(ctx);
-   struct intel_renderbuffer *irb;
-
-   if (intel->sarea->pf_current_page) {
-      switch (attIndex) {
-      case BUFFER_BACK_LEFT:
-	 attIndex = BUFFER_FRONT_LEFT;
-	 break;
-      case BUFFER_FRONT_LEFT:
-	 attIndex = BUFFER_BACK_LEFT;
-	 break;
-      }
-   }
-
-   irb = intel_renderbuffer(fb->Attachment[attIndex].Renderbuffer);
+   struct intel_renderbuffer *irb = intel_get_renderbuffer(fb, attIndex);
 
    if (irb)
       return irb->region;
@@ -109,7 +109,9 @@ intel_get_rb_region(struct gl_framebuffe
 static struct gl_framebuffer *
 intel_new_framebuffer(GLcontext * ctx, GLuint name)
 {
-   /* there's no intel_framebuffer at this time, just use Mesa's class */
+   /* Only drawable state in intel_framebuffer at this time, just use Mesa's
+    * class
+    */
    return _mesa_new_framebuffer(ctx, name);
 }
 
diff --git a/src/mesa/drivers/dri/i915tex/intel_fbo.h b/src/mesa/drivers/dri/i915tex/intel_fbo.h
index 221f09b..d55f029 100644
--- a/src/mesa/drivers/dri/i915tex/intel_fbo.h
+++ b/src/mesa/drivers/dri/i915tex/intel_fbo.h
@@ -32,6 +32,20 @@
 struct intel_context;
 struct intel_region;
 
+/**
+ * Intel framebuffer, derived from gl_framebuffer.
+ */
+struct intel_framebuffer
+{
+   struct gl_framebuffer Base;
+
+   /* Drawable page flipping state */
+   GLboolean pf_active;
+   GLboolean flip_pending;
+   GLint pf_pipes;
+   GLint pf_current_page;
+};
+
 
 /**
  * Intel renderbuffer, derived from gl_renderbuffer.
diff --git a/src/mesa/drivers/dri/i915tex/intel_reg.h b/src/mesa/drivers/dri/i915tex/intel_reg.h
index 126d2ea..7828ba6 100644
--- a/src/mesa/drivers/dri/i915tex/intel_reg.h
+++ b/src/mesa/drivers/dri/i915tex/intel_reg.h
@@ -82,6 +82,7 @@
 #define XY_SRC_COPY_BLT_WRITE_RGB       (1<<20)
 
 #define MI_WAIT_FOR_EVENT               ((0x3<<23))
+#define MI_WAIT_FOR_PLANE_B_FLIP        (1<<6)
 #define MI_WAIT_FOR_PLANE_A_FLIP        (1<<2)
 
 #endif
diff --git a/src/mesa/drivers/dri/i915tex/intel_screen.c b/src/mesa/drivers/dri/i915tex/intel_screen.c
index efa1b01..f26b3f3 100644
--- a/src/mesa/drivers/dri/i915tex/intel_screen.c
+++ b/src/mesa/drivers/dri/i915tex/intel_screen.c
@@ -541,7 +541,12 @@ intelCreateBuffer(__DRIscreenPrivate * d
                              mesaVis->depthBits != 24);
       GLenum rgbFormat = (mesaVis->redBits == 5 ? GL_RGB5 : GL_RGBA8);
 
-      struct gl_framebuffer *fb = _mesa_create_framebuffer(mesaVis);
+      struct intel_framebuffer *intel_fb = CALLOC_STRUCT(intel_framebuffer);
+
+      if (!intel_fb)
+	 return GL_FALSE;
+
+      _mesa_initialize_framebuffer(&intel_fb->Base, mesaVis);
 
       /* setup the hardware-based renderbuffers */
       {
@@ -553,7 +558,8 @@ intelCreateBuffer(__DRIscreenPrivate * d
                                         screen->cpp,
                                         screen->front.map);
          intel_set_span_functions(&frontRb->Base);
-         _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &frontRb->Base);
+         _mesa_add_renderbuffer(&intel_fb->Base, BUFFER_FRONT_LEFT,
+				&frontRb->Base);
       }
 
       if (mesaVis->doubleBufferMode) {
@@ -565,7 +571,8 @@ intelCreateBuffer(__DRIscreenPrivate * d
                                         screen->cpp,
                                         screen->back.map);
          intel_set_span_functions(&backRb->Base);
-         _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &backRb->Base);
+         _mesa_add_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT,
+				&backRb->Base);
       }
 
       if (mesaVis->depthBits == 24 && mesaVis->stencilBits == 8) {
@@ -579,8 +586,10 @@ intelCreateBuffer(__DRIscreenPrivate * d
                                         screen->depth.map);
          intel_set_span_functions(&depthStencilRb->Base);
          /* note: bind RB to two attachment points */
-         _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthStencilRb->Base);
-         _mesa_add_renderbuffer(fb, BUFFER_STENCIL, &depthStencilRb->Base);
+         _mesa_add_renderbuffer(&intel_fb->Base, BUFFER_DEPTH,
+				&depthStencilRb->Base);
+         _mesa_add_renderbuffer(&intel_fb->Base, BUFFER_STENCIL,
+				&depthStencilRb->Base);
       }
       else if (mesaVis->depthBits == 16) {
          /* just 16-bit depth buffer, no hw stencil */
@@ -592,17 +601,19 @@ intelCreateBuffer(__DRIscreenPrivate * d
                                         screen->cpp,    /* 2! */
                                         screen->depth.map);
          intel_set_span_functions(&depthRb->Base);
-         _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base);
+         _mesa_add_renderbuffer(&intel_fb->Base, BUFFER_DEPTH, &depthRb->Base);
       }
 
       /* now add any/all software-based renderbuffers we may need */
-      _mesa_add_soft_renderbuffers(fb, GL_FALSE,        /* never sw color */
-                                   GL_FALSE,    /* never sw depth */
-                                   swStencil, mesaVis->accumRedBits > 0, GL_FALSE,      /* never sw alpha */
-                                   GL_FALSE /* never sw aux */ );
-      driDrawPriv->driverPrivate = (void *) fb;
+      _mesa_add_soft_renderbuffers(&intel_fb->Base,
+                                   GL_FALSE, /* never sw color */
+                                   GL_FALSE, /* never sw depth */
+                                   swStencil, mesaVis->accumRedBits > 0,
+                                   GL_FALSE, /* never sw alpha */
+                                   GL_FALSE  /* never sw aux */ );
+      driDrawPriv->driverPrivate = (void *) intel_fb;
 
-      return (driDrawPriv->driverPrivate != NULL);
+      return GL_TRUE;
    }
 }
 
diff --git a/src/mesa/drivers/dri/i915tex/intel_tris.c b/src/mesa/drivers/dri/i915tex/intel_tris.c
index 4e0ca70..9ac8c32 100644
--- a/src/mesa/drivers/dri/i915tex/intel_tris.c
+++ b/src/mesa/drivers/dri/i915tex/intel_tris.c
@@ -102,15 +102,7 @@ intelStartInlinePrimitive(struct intel_c
 
 /*    _mesa_printf("%s *", __progname); */
 
-   if (intel->flip_pending) {
-      /* Wait for a pending flip to take effect */
-      BEGIN_BATCH(2, batch_flags);
-      OUT_BATCH(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP);
-      OUT_BATCH(0);
-      ADVANCE_BATCH();
-
-      intel->flip_pending = GL_FALSE;
-   }
+   intel_wait_flips(intel, batch_flags);
 
    /* Emit a slot which will be filled with the inline primitive
     * command later.
diff-tree af64dd2ae0aa31261002335f10d46492000f552b (from d2b06403c6f06ee37f46c2a504983884382c8abc)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Fri Feb 2 17:10:25 2007 +0100

    i915tex: Make page flipping work again.

diff --git a/src/mesa/drivers/dri/i915tex/intel_blit.c b/src/mesa/drivers/dri/i915tex/intel_blit.c
index 550669a..c08c45a 100644
--- a/src/mesa/drivers/dri/i915tex/intel_blit.c
+++ b/src/mesa/drivers/dri/i915tex/intel_blit.c
@@ -453,16 +453,6 @@ intelClearWithBlit(GLcontext * ctx, GLbi
          clear.y1 = intel->driDrawable->y + intel->driDrawable->h - cy - ch;
          clear.x2 = clear.x1 + cw;
          clear.y2 = clear.y1 + ch;
-
-         /* adjust for page flipping */
-         if (intel->sarea->pf_current_page == 1) {
-            const GLuint tmp = mask;
-            mask &= ~(BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT);
-            if (tmp & BUFFER_BIT_FRONT_LEFT)
-               mask |= BUFFER_BIT_BACK_LEFT;
-            if (tmp & BUFFER_BIT_BACK_LEFT)
-               mask |= BUFFER_BIT_FRONT_LEFT;
-         }
       }
       else {
          /* clearing FBO */
@@ -499,11 +489,10 @@ intelClearWithBlit(GLcontext * ctx, GLbi
             const GLbitfield bufBit = 1 << buf;
             if ((clearMask & bufBit) && !(bufBit & skipBuffers)) {
                /* OK, clear this renderbuffer */
-               const struct intel_renderbuffer *irb
-                  = intel_renderbuffer(ctx->DrawBuffer->
-                                       Attachment[buf].Renderbuffer);
+               struct intel_region *irb_region =
+		  intel_get_rb_region(ctx->DrawBuffer, buf);
                struct _DriBufferObject *write_buffer =
-                  intel_region_buffer(intel->intelScreen, irb->region,
+                  intel_region_buffer(intel->intelScreen, irb_region,
                                       all ? INTEL_WRITE_FULL :
                                       INTEL_WRITE_PART);
 
@@ -511,16 +500,15 @@ intelClearWithBlit(GLcontext * ctx, GLbi
                GLint pitch, cpp;
                GLuint BR13, CMD;
 
-               ASSERT(irb);
-               ASSERT(irb->region);
+               ASSERT(irb_region);
 
-               pitch = irb->region->pitch;
-               cpp = irb->region->cpp;
+               pitch = irb_region->pitch;
+               cpp = irb_region->cpp;
 
                DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n",
                    __FUNCTION__,
-                   irb->region->buffer, (pitch * cpp),
-                   irb->region->draw_offset,
+                   irb_region->buffer, (pitch * cpp),
+                   irb_region->draw_offset,
                    b.x1, b.y1, b.x2 - b.x1, b.y2 - b.y1);
 
 
@@ -558,6 +546,16 @@ intelClearWithBlit(GLcontext * ctx, GLbi
                   _mesa_debug(ctx, "hardware blit clear buf %d rb id %d\n",
                   buf, irb->Base.Name);
                 */
+	       if (intel->flip_pending) {
+		  /* Wait for a pending flip to take effect */
+		  BEGIN_BATCH(2, INTEL_BATCH_NO_CLIPRECTS);
+		  OUT_BATCH(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP);
+		  OUT_BATCH(0);
+		  ADVANCE_BATCH();
+
+		  intel->flip_pending = GL_FALSE;
+	       }
+
                BEGIN_BATCH(6, INTEL_BATCH_NO_CLIPRECTS);
                OUT_BATCH(CMD);
                OUT_BATCH(BR13);
@@ -565,7 +563,7 @@ intelClearWithBlit(GLcontext * ctx, GLbi
                OUT_BATCH((b.y2 << 16) | b.x2);
                OUT_RELOC(write_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
                          DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE,
-                         irb->region->draw_offset);
+                         irb_region->draw_offset);
                OUT_BATCH(clearVal);
                ADVANCE_BATCH();
                clearMask &= ~bufBit;    /* turn off bit, for faster loop exit */
diff --git a/src/mesa/drivers/dri/i915tex/intel_buffers.c b/src/mesa/drivers/dri/i915tex/intel_buffers.c
index 1ded0b5..a8fb0b1 100644
--- a/src/mesa/drivers/dri/i915tex/intel_buffers.c
+++ b/src/mesa/drivers/dri/i915tex/intel_buffers.c
@@ -159,7 +159,7 @@ intelSetBackClipRects(struct intel_conte
    if (!dPriv)
       return;
 
-   if (intel->sarea->pf_enabled == 0 && dPriv->numBackClipRects == 0) {
+   if (intel->sarea->pf_active || dPriv->numBackClipRects == 0) {
       /* use the front clip rects */
       intel->numClipRects = dPriv->numClipRects;
       intel->pClipRects = dPriv->pClipRects;
@@ -421,7 +421,8 @@ intelRotateWindow(struct intel_context *
 
    intel->vtbl.meta_draw_region(intel, screen->rotated_region, NULL);    /* ? */
 
-   if (srcBuf == BUFFER_BIT_FRONT_LEFT) {
+   if ((srcBuf == BUFFER_BIT_BACK_LEFT && intel->sarea->pf_current_page) ||
+       (srcBuf == BUFFER_BIT_FRONT_LEFT && !intel->sarea->pf_current_page)) {
       src = intel->intelScreen->front_region;
       clipRects = dPriv->pClipRects;
       numClipRects = dPriv->numClipRects;
@@ -592,9 +593,9 @@ intelClear(GLcontext *ctx, GLbitfield ma
 static void
 intelPageFlip(const __DRIdrawablePrivate * dPriv)
 {
-#if 0
    struct intel_context *intel;
-   int tmp, ret;
+   GLboolean missed_target;
+   int ret;
 
    if (INTEL_DEBUG & DEBUG_IOCTL)
       fprintf(stderr, "%s\n", __FUNCTION__);
@@ -606,27 +607,36 @@ intelPageFlip(const __DRIdrawablePrivate
    intel = (struct intel_context *) dPriv->driContextPriv->driverPrivate;
 
    intelFlush(&intel->ctx);
-   LOCK_HARDWARE(intel);
 
-   if (dPriv->pClipRects) {
-      *(drm_clip_rect_t *) intel->sarea->boxes = dPriv->pClipRects[0];
-      intel->sarea->nbox = 1;
+   driWaitForVBlank(dPriv, &intel->vbl_seq, intel->vblank_flags, &missed_target);
+
+   if (missed_target) {
+      intel->swap_missed_count++;
+      (void)(*dri_interface->getUST) (&intel->swap_missed_ust);
    }
 
-   ret = drmCommandNone(intel->driFd, DRM_I830_FLIP);
-   if (ret) {
-      fprintf(stderr, "%s: %d\n", __FUNCTION__, ret);
+   LOCK_HARDWARE(intel);
+
+   if (!dPriv->numClipRects) {
       UNLOCK_HARDWARE(intel);
-      exit(1);
+      usleep(10000);	/* throttle invisible client 10ms */
+      return;
    }
 
-   tmp = intel->sarea->last_enqueue;
-   intelRefillBatchLocked(intel);
+   ret = drmCommandNone(intel->driFd, DRM_I830_FLIP);
    UNLOCK_HARDWARE(intel);
 
+   if (ret) {
+      _mesa_error(&intel->ctx, GL_INVALID_OPERATION, "DRM_I830_FLIP: %d\n",
+		  ret);
+      return;
+   }
 
-   intelSetDrawBuffer(&intel->ctx, intel->ctx.Color.DriverDrawBuffer);
-#endif
+   driFlipRenderbuffers(intel->ctx.WinSysDrawBuffer,
+			intel->sarea->pf_current_page);
+   intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
+
+   intel->flip_pending = GL_TRUE;
 }
 
 #if 0
@@ -641,7 +651,7 @@ intelSwapBuffers(__DRIdrawablePrivate * 
          if (ctx && ctx->DrawBuffer == fb) {
             _mesa_notifySwapBuffers(ctx);       /* flush pending rendering */
          }
-         if (0 /*intel->doPageFlip */ ) {       /* doPageFlip is never set !!! */
+         if (intel->doPageFlip) {
             intelPageFlip(dPriv);
          }
          else {
@@ -672,7 +682,7 @@ intelSwapBuffers(__DRIdrawablePrivate * 
       if (ctx->Visual.doubleBufferMode) {
          intelScreenPrivate *screen = intel->intelScreen;
          _mesa_notifySwapBuffers(ctx);  /* flush pending rendering comands */
-         if (0 /*intel->doPageFlip */ ) {       /* doPageFlip is never set !!! */
+         if (screen->current_rotation == 0 && intel->doPageFlip) {
             intelPageFlip(dPriv);
          }
          else {
@@ -788,10 +798,6 @@ intel_draw_buffer(GLcontext * ctx, struc
     */
    if (fb->Name == 0) {
       /* drawing to window system buffer */
-      if (intel->sarea->pf_current_page == 1) {
-         /* page flipped back/front */
-         front ^= 1;
-      }
       if (front) {
          intelSetFrontClipRects(intel);
          colorRegion = intel_get_rb_region(fb, BUFFER_FRONT_LEFT);
diff --git a/src/mesa/drivers/dri/i915tex/intel_context.c b/src/mesa/drivers/dri/i915tex/intel_context.c
index a5ce08b..7eb209c 100644
--- a/src/mesa/drivers/dri/i915tex/intel_context.c
+++ b/src/mesa/drivers/dri/i915tex/intel_context.c
@@ -59,6 +59,7 @@
 #include "intel_buffer_objects.h"
 #include "intel_fbo.h"
 
+#include "drirenderbuffer.h"
 #include "vblank.h"
 #include "utils.h"
 #include "xmlpool.h"            /* for symbolic values of enum-type options */
@@ -683,13 +684,24 @@ intelContendedLock(struct intel_context 
       intel->current_rotation = sarea->rotation;
    }
 
-
    /* Drawable changed?
     */
    if (dPriv && intel->lastStamp != dPriv->lastStamp) {
       intelWindowMoved(intel);
       intel->lastStamp = dPriv->lastStamp;
    }
+
+   /* Update page flipping info
+    */
+   if (INTEL_DEBUG & DEBUG_LOCK)
+      if (intel->doPageFlip != intel->sarea->pf_active)
+	 _mesa_printf("%s - age flipping %sactive\n", __progname,
+		      intel->sarea->pf_active ? "" : "in");
+
+   intel->doPageFlip = intel->sarea->pf_active;
+   driFlipRenderbuffers(intel->ctx.WinSysDrawBuffer,
+			intel->sarea->pf_current_page);
+   intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
 }
 
 
diff --git a/src/mesa/drivers/dri/i915tex/intel_context.h b/src/mesa/drivers/dri/i915tex/intel_context.h
index 96b9115..321a945 100644
--- a/src/mesa/drivers/dri/i915tex/intel_context.h
+++ b/src/mesa/drivers/dri/i915tex/intel_context.h
@@ -295,6 +295,10 @@ struct intel_context
   int height;
   int current_rotation;
 
+  /* Page flipping
+   */
+  GLboolean doPageFlip;
+  GLboolean flip_pending;
 };
 
 /* These are functions now:
diff --git a/src/mesa/drivers/dri/i915tex/intel_fbo.c b/src/mesa/drivers/dri/i915tex/intel_fbo.c
index ab0e569..b739e22 100644
--- a/src/mesa/drivers/dri/i915tex/intel_fbo.c
+++ b/src/mesa/drivers/dri/i915tex/intel_fbo.c
@@ -78,8 +78,23 @@ intel_get_renderbuffer(struct gl_framebu
 struct intel_region *
 intel_get_rb_region(struct gl_framebuffer *fb, GLuint attIndex)
 {
-   struct intel_renderbuffer *irb
-      = intel_renderbuffer(fb->Attachment[attIndex].Renderbuffer);
+   GET_CURRENT_CONTEXT(ctx);
+   struct intel_context *intel = intel_context(ctx);
+   struct intel_renderbuffer *irb;
+
+   if (intel->sarea->pf_current_page) {
+      switch (attIndex) {
+      case BUFFER_BACK_LEFT:
+	 attIndex = BUFFER_FRONT_LEFT;
+	 break;
+      case BUFFER_FRONT_LEFT:
+	 attIndex = BUFFER_BACK_LEFT;
+	 break;
+      }
+   }
+
+   irb = intel_renderbuffer(fb->Attachment[attIndex].Renderbuffer);
+
    if (irb)
       return irb->region;
    else
diff --git a/src/mesa/drivers/dri/i915tex/intel_reg.h b/src/mesa/drivers/dri/i915tex/intel_reg.h
index 1ec1532..126d2ea 100644
--- a/src/mesa/drivers/dri/i915tex/intel_reg.h
+++ b/src/mesa/drivers/dri/i915tex/intel_reg.h
@@ -81,4 +81,7 @@
 #define XY_SRC_COPY_BLT_WRITE_ALPHA     (1<<21)
 #define XY_SRC_COPY_BLT_WRITE_RGB       (1<<20)
 
+#define MI_WAIT_FOR_EVENT               ((0x3<<23))
+#define MI_WAIT_FOR_PLANE_A_FLIP        (1<<2)
+
 #endif
diff --git a/src/mesa/drivers/dri/i915tex/intel_tris.c b/src/mesa/drivers/dri/i915tex/intel_tris.c
index 1ba49d8..4e0ca70 100644
--- a/src/mesa/drivers/dri/i915tex/intel_tris.c
+++ b/src/mesa/drivers/dri/i915tex/intel_tris.c
@@ -102,6 +102,16 @@ intelStartInlinePrimitive(struct intel_c
 
 /*    _mesa_printf("%s *", __progname); */
 
+   if (intel->flip_pending) {
+      /* Wait for a pending flip to take effect */
+      BEGIN_BATCH(2, batch_flags);
+      OUT_BATCH(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP);
+      OUT_BATCH(0);
+      ADVANCE_BATCH();
+
+      intel->flip_pending = GL_FALSE;
+   }
+
    /* Emit a slot which will be filled with the inline primitive
     * command later.
     */



More information about the mesa-commit mailing list