i915tex: Triple buffering support, only effective with page flipping so far.
authorMichel Dänzer <michel@tungstengraphics.com>
Tue, 20 Feb 2007 18:14:23 +0000 (19:14 +0100)
committerMichel Dänzer <michel@tungstengraphics.com>
Tue, 20 Feb 2007 18:15:44 +0000 (19:15 +0100)
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.

src/mesa/drivers/dri/i915tex/intel_buffers.c
src/mesa/drivers/dri/i915tex/intel_context.c
src/mesa/drivers/dri/i915tex/intel_fbo.c
src/mesa/drivers/dri/i915tex/intel_fbo.h
src/mesa/drivers/dri/i915tex/intel_screen.c
src/mesa/drivers/dri/i915tex/intel_screen.h
src/mesa/drivers/dri/i915tex/server/i830_common.h

index ec2150d27bca711d24919e0c93d7d55af310e75f..7db5ccfc26586459925fa3c10301acbadb5a2e14 100644 (file)
@@ -214,10 +214,6 @@ intelWindowMoved(struct intel_context *intel)
       }
    }
 
-   /* 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 *intel)
       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 *intel)
                         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 *intel)
       }
 
       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 *intel)
       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,
    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 *intel, GLuint batch_flags)
 {
    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 *intel, GLuint batch_flags)
       OUT_BATCH(0);
       ADVANCE_BATCH();
 
-      intel_fb->flip_pending = GL_FALSE;
+      intel_rb->pf_pending--;
    }
 }
 
@@ -721,10 +732,14 @@ intelPageFlip(const __DRIdrawablePrivate * dPriv)
    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;
 }
index 8d90489b4e871085076e327c952b671ac952028c..649fe549bf4ece2a03aa9c6f405d9190cbb669f7 100644 (file)
@@ -551,27 +551,30 @@ intelMakeCurrent(__DRIcontextPrivate * driContextPriv,
    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 * driContextPriv,
          }
       }
 
-      /* 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 * driContextPriv,
            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);
index 104cf1d9bbf9d1e1c5426f5f0933e971ebeb8e0c..ad078451bf2acd93d390f94e72ac585ad9d835b0 100644 (file)
@@ -71,22 +71,29 @@ intel_renderbuffer(struct gl_renderbuffer *rb)
 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);
+}
+
+
+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);
    }
 
-   return intel_renderbuffer(fb->Attachment[attIndex].Renderbuffer);
+   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;
 }
 
index d55f02967f7ca7fdf18f03385bd87b262ea677b2..0446d681c61f7400b42cebfc1355781bde4e3bb1 100644 (file)
@@ -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_get_renderbuffer(struct gl_framebuffer
                                                          *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,
index f26b3f33ad25c1f24603e6dd27b63dfc48d65b5b..4763d14f4f587e9835ed5e1b01a7eb3167570be4 100644 (file)
@@ -98,6 +98,18 @@ intelMapScreenRegions(__DRIscreenPrivate * sPriv)
       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 * sPriv)
    }
 #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(intelScreenPrivate *intelScreen)
                            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(intelScreenPrivate * intelScreen)
 #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(intelScreenPrivate * intelScreen,
    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 * driScrnPriv,
 
       /* 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) {
index 17698773f3d67152dd953bfe79d661fe5807381d..05e2f1f2eac471e49177a4ab3a76e5af4f8ec5be 100644 (file)
@@ -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;
 
index 06f28ed19a4a80fb1b46b7ccd63f1156d2e1c98d..d4d58886ce07a7e99784f91406b61000ef9eba3b 100644 (file)
@@ -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