On Mon, 2006-03-13 at 10:45 -0800, Ian Romanick wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> David Reveman wrote:
> > This patch adds direct and indirect rendering support for
> > GLX_MESA_copy_sub_buffer. Intel, r200 and r300 drivers are the only
> > drivers I've implemented support for so far. I've only tried the intel
> > implementation and that seems to be working OK. I've attached a patch
> > for CVS head and one for 6.4.2.
> 
> I think the spec for this extension and the code implementing it needs a
> slight update.  The problem is that the extension assumes that
> SwapBuffers is implemented by copying the back buffer to the front.
> However, this is *not* always the case.  The result is that this
> extension does not produce the desired results with page flipping.
> 
> However, it is possible for an application to detect / request the copy
> behavior by using GLX_OML_swap_method.  An fbconfig with copy semantics
> can be requested by using "GLX_SWAP_METHOD_OML, GLX_SWAP_COPY_OML" in
> the attribs list.  If not particular method is requested, the current
> method can be queried via glXGetFBConfigAttrib.
> 
> The only rub is that most of our drivers only advertise a
> GLX_SWAP_METHOD_OML of GLX_SWAP_UNDEFINED_OML.  This is because, in the
> drivers that support page-flipping, we switch between GLX_SWAP_COPY_OML
> and GLX_SWAP_EXCHANGE_OML on the fly.  We can easilly modify the drivers
> to adverteise GLX_SWAP_COPY_OML fbconfigs and enforce that behavior.
> 
> Currently none of the drivers actually advertise GLX_SWAP_EXCHANGE_OML
> fbconfigs.
> 
> http://oss.sgi.com/projects/ogl-sample/registry/OML/glx_swap_method.txt
> 
> My opinion is that we should modify GLX_MESA_copy_sub_buffer to, at the
> very least, note that the desired behavior is only guaranteed for the
> GLX_SWAP_COPY_OML case.  We may even want to say that, if
> GLX_OML_swap_method is supported, it is an error to call
> glXCopySubBufferMESA when GLX_SWAP_METHOD_OML is not GLX_SWAP_COPY_OML.
> 
> Dunno.
> 
> I have a few comments about the patches, but nothing too major...
> 
> > --- include/GL/internal/dri_interface.h     29 Nov 2005 23:01:43 -0000      
> > 1.17
> > +++ include/GL/internal/dri_interface.h     12 Mar 2006 15:58:04 -0000
> > @@ -472,6 +472,9 @@
> >       * \since Internal API version 20030317.
> >       */
> >      unsigned swap_interval;
> > +
> > +    void (*copySubBuffer)(__DRInativeDisplay *dpy, void *drawablePrivate,
> > +                     int x, int y, int w, int h);
> >  };
> 
> Please add a \since comment here and bump the internal version.  You'll
> also need to update __glXGetInternalVersion (glxcmds.c).
> 
> > --- src/glx/x11/glxextensions.c     24 Feb 2006 15:36:24 -0000      1.13
> > +++ src/glx/x11/glxextensions.c     12 Mar 2006 15:58:41 -0000
> > @@ -79,7 +79,7 @@
> >     { GLX(EXT_visual_rating),           VER(0,0), Y, Y, N, N },
> >     { GLX(MESA_agp_offset),             VER(0,0), N, N, N, Y }, /* 
> > Deprecated */
> >     { GLX(MESA_allocate_memory),        VER(0,0), Y, N, N, Y },
> > -   { GLX(MESA_copy_sub_buffer),        VER(0,0), N, N, N, N }, /* 
> > Deprecated? */
> > +   { GLX(MESA_copy_sub_buffer),        VER(0,0), Y, Y, N, N }, /* 
> > Deprecated? */
> 
> This should be "Y, N, N, N".  Setting direct_support here means that the
> extension is enable without the driver explicitly enabling it.  Since
> not all drivers will set the copySubBuffer pointer, I assume that's not
> what you want. :)
> 
> I'll update the field comments in the extension_info structure today.
> It's not very clear.  Sorry.
> 
> >     { GLX(MESA_pixmap_colormap),        VER(0,0), N, N, N, N }, /* 
> > Deprecated */
> >     { GLX(MESA_release_buffers),        VER(0,0), N, N, N, N }, /* 
> > Deprecated */
> >     { GLX(MESA_set_3dfx_mode),          VER(0,0), N, N, N, N }, /* 
> > Deprecated */
> > --- src/mesa/drivers/dri/common/dri_util.c  29 Nov 2005 23:01:43 -0000      
> > 1.29
> > +++ src/mesa/drivers/dri/common/dri_util.c  12 Mar 2006 15:58:46 -0000
> > @@ -547,6 +547,13 @@
> >                                                             remainder );
> >  }
> >  
> > +static void driCopySubBuffer( __DRInativeDisplay *dpy, void 
> > *drawablePrivate,
> > +                         int x, int y, int w, int h)
> > +{
> > +    __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePrivate;
> > +    dPriv->driScreenPriv->DriverAPI.CopySubBuffer(dPriv, x, y, w, h);
> > +    (void) dpy;
> > +}
> >  
> >  /**
> >   * This is called via __DRIscreenRec's createNewDrawable pointer.
> > @@ -622,6 +629,7 @@
> >      pdraw->swapBuffersMSC = driSwapBuffersMSC;
> >      pdraw->frameTracking = NULL;
> >      pdraw->queryFrameTracking = driQueryFrameTracking;
> > +    pdraw->copySubBuffer = driCopySubBuffer;
> 
> After bumping the API version, this code will need to verify that
> api_ver is new enough for this field to exist.

I've updated my patch.

-David
--- include/GL/internal/dri_interface.h	29 Nov 2005 23:01:43 -0000	1.17
+++ include/GL/internal/dri_interface.h	14 Mar 2006 12:26:53 -0000
@@ -472,6 +472,14 @@
      * \since Internal API version 20030317.
      */
     unsigned swap_interval;
+
+    /**
+     * Used by drivers that implement the GLX_MESA_copy_sub_buffer extension.
+     *
+     * \since Internal API version 20060314.
+     */
+    void (*copySubBuffer)(__DRInativeDisplay *dpy, void *drawablePrivate,
+			  int x, int y, int w, int h);
 };
 
 #endif
--- src/glx/x11/glxcmds.c	9 Mar 2006 16:25:46 -0000	1.13
+++ src/glx/x11/glxcmds.c	14 Mar 2006 12:27:49 -0000
@@ -2570,18 +2570,69 @@
    return 0;
 }
 
-
+#define X_GLXvop_CopySubBufferMESA 5154 /* temporary */
 PUBLIC void glXCopySubBufferMESA(Display *dpy, GLXDrawable drawable,
 				 int x, int y, int width, int height)
 {
-   (void) dpy;
-   (void) drawable;
-   (void) x;
-   (void) y;
-   (void) width;
-   (void) height;
-}
+    xGLXVendorPrivateReq *req;
+    GLXContext gc;
+    GLXContextTag tag;
+    CARD32 *drawable_ptr;
+    INT32 *x_ptr, *y_ptr, *w_ptr, *h_ptr;
+    CARD8 opcode;
+
+#ifdef GLX_DIRECT_RENDERING
+    int screen;
+    __DRIdrawable *pdraw = GetDRIDrawable( dpy, drawable, & screen );
+    if ( pdraw != NULL ) {
+	__GLXscreenConfigs * const psc = GetGLXScreenConfigs( dpy, screen );
+	if ( __glXExtensionBitIsEnabled( psc, MESA_copy_sub_buffer_bit ) ) {
+	    (*pdraw->copySubBuffer)(dpy, pdraw->private, x, y, width, height);
+	}
+
+	return;
+    }
+#endif
+
+    opcode = __glXSetupForCommand(dpy);
+    if (!opcode)
+	return;
+
+    /*
+    ** The calling thread may or may not have a current context.  If it
+    ** does, send the context tag so the server can do a flush.
+    */
+    gc = __glXGetCurrentContext();
+    if ((gc != NULL) && (dpy == gc->currentDpy) &&
+	((drawable == gc->currentDrawable) ||
+	 (drawable == gc->currentReadable)) ) {
+	tag = gc->currentContextTag;
+    } else {
+	tag = 0;
+    }
+
+    LockDisplay(dpy);
+    GetReqExtra(GLXVendorPrivate, sizeof(CARD32) + sizeof(INT32) * 4,req);
+    req->reqType = opcode;
+    req->glxCode = X_GLXVendorPrivate;
+    req->vendorCode = X_GLXvop_CopySubBufferMESA;
+    req->contextTag = tag;
 
+    drawable_ptr = (CARD32 *) (req + 1);
+    x_ptr = (INT32 *) (drawable_ptr + 1);
+    y_ptr = (INT32 *) (drawable_ptr + 2);
+    w_ptr = (INT32 *) (drawable_ptr + 3);
+    h_ptr = (INT32 *) (drawable_ptr + 4);
+
+    *drawable_ptr = drawable;
+    *x_ptr = x;
+    *y_ptr = y;
+    *w_ptr = width;
+    *h_ptr = height;
+
+    UnlockDisplay(dpy);
+    SyncHandle();
+}
 
 PUBLIC Bool glXSet3DfxModeMESA( int mode )
 {
@@ -2973,8 +3024,9 @@
      *            months ago. :(
      * 20050727 - Gut all the old interfaces.  This breaks compatability with
      *            any DRI driver built to any previous version.
+     * 20060314 - Added support for GLX_MESA_copy_sub_buffer.
      */
-    return 20050727;
+    return 20060314;
 }
 
 
--- src/glx/x11/glxextensions.c	24 Feb 2006 15:36:24 -0000	1.13
+++ src/glx/x11/glxextensions.c	14 Mar 2006 12:27:50 -0000
@@ -79,7 +79,7 @@
    { GLX(EXT_visual_rating),           VER(0,0), Y, Y, N, N },
    { GLX(MESA_agp_offset),             VER(0,0), N, N, N, Y }, /* Deprecated */
    { GLX(MESA_allocate_memory),        VER(0,0), Y, N, N, Y },
-   { GLX(MESA_copy_sub_buffer),        VER(0,0), N, N, N, N }, /* Deprecated? */
+   { GLX(MESA_copy_sub_buffer),        VER(0,0), Y, N, N, N },
    { GLX(MESA_pixmap_colormap),        VER(0,0), N, N, N, N }, /* Deprecated */
    { GLX(MESA_release_buffers),        VER(0,0), N, N, N, N }, /* Deprecated */
    { GLX(MESA_set_3dfx_mode),          VER(0,0), N, N, N, N }, /* Deprecated */
--- src/mesa/drivers/dri/common/dri_util.c	29 Nov 2005 23:01:43 -0000	1.29
+++ src/mesa/drivers/dri/common/dri_util.c	14 Mar 2006 12:27:59 -0000
@@ -547,6 +547,13 @@
                                                            remainder );
 }
 
+static void driCopySubBuffer( __DRInativeDisplay *dpy, void *drawablePrivate,
+			      int x, int y, int w, int h)
+{
+    __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePrivate;
+    dPriv->driScreenPriv->DriverAPI.CopySubBuffer(dPriv, x, y, w, h);
+    (void) dpy;
+}
 
 /**
  * This is called via __DRIscreenRec's createNewDrawable pointer.
@@ -623,6 +630,9 @@
     pdraw->frameTracking = NULL;
     pdraw->queryFrameTracking = driQueryFrameTracking;
 
+    if (driCompareGLXAPIVersion (20060314) >= 0)
+	pdraw->copySubBuffer = driCopySubBuffer;
+
     /* This special default value is replaced with the configured
      * default value when the drawable is first bound to a direct
      * rendering context. 
--- src/mesa/drivers/dri/common/dri_util.h	29 Nov 2005 23:01:43 -0000	1.21
+++ src/mesa/drivers/dri/common/dri_util.h	14 Mar 2006 12:27:59 -0000
@@ -189,6 +189,8 @@
     int64_t (*SwapBuffersMSC)( __DRIdrawablePrivate *priv, int64_t target_msc,
 			       int64_t divisor, int64_t remainder );
     /[EMAIL PROTECTED]/
+    void (*CopySubBuffer)(__DRIdrawablePrivate *driDrawPriv,
+			  int x, int y, int w, int h);
 };
 
 
--- src/mesa/drivers/dri/i915/intel_batchbuffer.c	6 Feb 2006 00:09:58 -0000	1.6
+++ src/mesa/drivers/dri/i915/intel_batchbuffer.c	14 Mar 2006 12:28:09 -0000
@@ -366,7 +366,8 @@
 /*
  * Copy the back buffer to the front buffer. 
  */
-void intelCopyBuffer( const __DRIdrawablePrivate *dPriv ) 
+void intelCopyBuffer( const __DRIdrawablePrivate *dPriv,
+		      const drm_clip_rect_t	 *rect)
 {
    intelContextPtr intel;
    GLboolean   missed_target;
@@ -385,15 +386,19 @@
    
    LOCK_HARDWARE( intel );
    intelWaitForFrameCompletion( intel );
-   UNLOCK_HARDWARE( intel );
-   driWaitForVBlank( dPriv, &intel->vbl_seq, intel->vblank_flags, & missed_target );
 
-   LOCK_HARDWARE( intel );
+   if (!rect)
+   {
+       UNLOCK_HARDWARE( intel );
+       driWaitForVBlank( dPriv, &intel->vbl_seq, intel->vblank_flags, & missed_target );
+       LOCK_HARDWARE( intel );
+   }
    {
       const intelScreenPrivate *intelScreen = intel->intelScreen;
       const __DRIdrawablePrivate *dPriv = intel->driDrawable;
       const int nbox = dPriv->numClipRects;
       const drm_clip_rect_t *pbox = dPriv->pClipRects;
+      drm_clip_rect_t box;
       const int cpp = intelScreen->cpp;
       const int pitch = intelScreen->front.pitch; /* in bytes */
       int i;
@@ -429,18 +434,35 @@
 	    continue;
          }
 
+	 box = *pbox;
+
+	 if (rect)
+	 {
+	     if (rect->x1 > box.x1)
+		 box.x1 = rect->x1;
+	     if (rect->y1 > box.y1)
+		 box.y1 = rect->y1;
+	     if (rect->x2 < box.x2)
+		 box.x2 = rect->x2;
+	     if (rect->y2 < box.y2)
+		 box.y2 = rect->y2;
+
+	     if (box.x1 > box.x2 || box.y1 > box.y2)
+		 continue;
+	 }
+
 	 BEGIN_BATCH( 8);
 	 OUT_BATCH( CMD );
 	 OUT_BATCH( BR13 );
-	 OUT_BATCH( (pbox->y1 << 16) | pbox->x1 );
-	 OUT_BATCH( (pbox->y2 << 16) | pbox->x2 );
+	 OUT_BATCH( (box.y1 << 16) | box.x1 );
+	 OUT_BATCH( (box.y2 << 16) | box.x2 );
 
 	 if (intel->sarea->pf_current_page == 0) 
 	    OUT_BATCH( intelScreen->front.offset );
 	 else
 	    OUT_BATCH( intelScreen->back.offset );			
 
-	 OUT_BATCH( (pbox->y1 << 16) | pbox->x1 );
+	 OUT_BATCH( (box.y1 << 16) | box.x1 );
 	 OUT_BATCH( BR13 & 0xffff );
 
 	 if (intel->sarea->pf_current_page == 0) 
@@ -454,14 +476,17 @@
    intelFlushBatchLocked( intel, GL_TRUE, GL_TRUE, GL_TRUE );
    UNLOCK_HARDWARE( intel );
 
-   intel->swap_count++;
-   (*dri_interface->getUST)(&ust);
-   if (missed_target) {
-     intel->swap_missed_count++;
-     intel->swap_missed_ust = ust -  intel->swap_ust;
-   }
+   if (!rect)
+   {
+       intel->swap_count++;
+       (*dri_interface->getUST)(&ust);
+       if (missed_target) {
+	   intel->swap_missed_count++;
+	   intel->swap_missed_ust = ust -  intel->swap_ust;
+       }
    
-   intel->swap_ust = ust;
+       intel->swap_ust = ust;
+   }
 }
 
 
--- src/mesa/drivers/dri/i915/intel_batchbuffer.h	23 Jan 2006 10:10:48 -0000	1.3
+++ src/mesa/drivers/dri/i915/intel_batchbuffer.h	14 Mar 2006 12:28:09 -0000
@@ -75,7 +75,8 @@
 extern GLuint *intelEmitInlinePrimitiveLocked(intelContextPtr intel, 
 					      int primitive, int dwords,
 					      int vertex_size);
-extern void intelCopyBuffer( const __DRIdrawablePrivate *dpriv );
+extern void intelCopyBuffer( const __DRIdrawablePrivate *dpriv,
+			     const drm_clip_rect_t	*rect);
 extern void intelClearWithBlit(GLcontext *ctx, GLbitfield mask, GLboolean all,
 			     GLint cx1, GLint cy1, GLint cw, GLint ch);
 
--- src/mesa/drivers/dri/i915/intel_context.c	6 Feb 2006 00:09:58 -0000	1.22
+++ src/mesa/drivers/dri/i915/intel_context.c	14 Mar 2006 12:28:10 -0000
@@ -722,7 +722,7 @@
 	 if ( 0 /*intel->doPageFlip*/ ) { /* doPageFlip is never set !!! */
 	    intelPageFlip( dPriv );
 	 } else {
-	    intelCopyBuffer( dPriv );
+	     intelCopyBuffer( dPriv, NULL );
 	 }
          if (screen->current_rotation != 0) {
             intelRotateWindow(intel, dPriv, BUFFER_BIT_FRONT_LEFT);
@@ -734,6 +734,29 @@
    }
 }
 
+void intelCopySubBuffer( __DRIdrawablePrivate *dPriv,
+			 int x, int y, int w, int h )
+{
+   if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
+      intelContextPtr intel;
+      GLcontext *ctx;
+      intel = (intelContextPtr) dPriv->driContextPriv->driverPrivate;
+      ctx = &intel->ctx;
+      if (ctx->Visual.doubleBufferMode) {
+         intelScreenPrivate *screen = intel->intelScreen;
+	 drm_clip_rect_t rect;
+	 rect.x1 = x + dPriv->x;
+	 rect.y1 = (dPriv->h - y - h) + dPriv->y;
+	 rect.x2 = rect.x1 + w;
+	 rect.y2 = rect.y1 + h;
+	 _mesa_notifySwapBuffers( ctx );  /* flush pending rendering comands */
+	 intelCopyBuffer( dPriv, &rect );
+      }
+   } else {
+      /* XXX this shouldn't be an error but we can't handle it for now */
+      fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__);
+   }
+}
 
 void intelInitState( GLcontext *ctx )
 {
--- src/mesa/drivers/dri/i915/intel_screen.c	8 Feb 2006 22:05:42 -0000	1.35
+++ src/mesa/drivers/dri/i915/intel_screen.c	14 Mar 2006 12:28:10 -0000
@@ -341,6 +341,7 @@
       (*glx_enable_extension)( psc, "GLX_MESA_swap_frame_usage" );
       (*glx_enable_extension)( psc, "GLX_SGI_make_current_read" );
       (*glx_enable_extension)( psc, "GLX_MESA_allocate_memory" );
+      (*glx_enable_extension)( psc, "GLX_MESA_copy_sub_buffer" );
    }
    
    sPriv->psc->allocateMemory = (void *) intelAllocateMemoryMESA;
@@ -534,7 +535,8 @@
    .GetMSC          = driGetMSC32,
    .WaitForMSC      = driWaitForMSC32,
    .WaitForSBC      = NULL,
-   .SwapBuffersMSC  = NULL
+   .SwapBuffersMSC  = NULL,
+   .CopySubBuffer   = intelCopySubBuffer
 };
 
 
--- src/mesa/drivers/dri/i915/intel_screen.h	23 Jan 2006 10:10:48 -0000	1.6
+++ src/mesa/drivers/dri/i915/intel_screen.h	14 Mar 2006 12:28:10 -0000
@@ -106,4 +106,7 @@
 extern void
 intelSwapBuffers(__DRIdrawablePrivate *dPriv);
 
+extern void
+intelCopySubBuffer( __DRIdrawablePrivate *dPriv, int x, int y, int w, int h );
+
 #endif
--- src/mesa/drivers/dri/r200/r200_context.c	3 Feb 2006 13:29:11 -0000	1.55
+++ src/mesa/drivers/dri/r200/r200_context.c	14 Mar 2006 12:28:14 -0000
@@ -637,7 +637,7 @@
             r200PageFlip( dPriv );
          }
          else {
-            r200CopyBuffer( dPriv );
+	     r200CopyBuffer( dPriv, NULL );
          }
       }
    }
@@ -647,6 +647,30 @@
    }
 }
 
+void
+r200CopySubBuffer( __DRIdrawablePrivate *dPriv,
+		   int x, int y, int w, int h )
+{
+   if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
+      r200ContextPtr rmesa;
+      GLcontext *ctx;
+      rmesa = (r200ContextPtr) dPriv->driContextPriv->driverPrivate;
+      ctx = rmesa->glCtx;
+      if (ctx->Visual.doubleBufferMode) {
+	 drm_clip_rect_t rect;
+	 rect.x1 = x + dPriv->x;
+	 rect.y1 = (dPriv->h - y - h) + dPriv->y;
+	 rect.x2 = rect.x1 + w;
+	 rect.y2 = rect.y1 + h;
+         _mesa_notifySwapBuffers( ctx );  /* flush pending rendering comands */
+	 r200CopyBuffer( dPriv, &rect );
+      }
+   }
+   else {
+      /* XXX this shouldn't be an error but we can't handle it for now */
+      _mesa_problem(NULL, "%s: drawable has no context!", __FUNCTION__);
+   }
+}
 
 /* Force the context `c' to be the current context and associate with it
  * buffer `b'.
--- src/mesa/drivers/dri/r200/r200_context.h	2 Nov 2005 01:15:08 -0000	1.37
+++ src/mesa/drivers/dri/r200/r200_context.h	14 Mar 2006 12:28:14 -0000
@@ -1002,6 +1002,8 @@
 				    __DRIcontextPrivate *driContextPriv,
 				    void *sharedContextPrivate);
 extern void r200SwapBuffers( __DRIdrawablePrivate *dPriv );
+extern void r200CopySubBuffer( __DRIdrawablePrivate * dPriv,
+			       int x, int y, int w, int h );
 extern GLboolean r200MakeCurrent( __DRIcontextPrivate *driContextPriv,
 				  __DRIdrawablePrivate *driDrawPriv,
 				  __DRIdrawablePrivate *driReadPriv );
--- src/mesa/drivers/dri/r200/r200_ioctl.c	2 Nov 2005 01:15:08 -0000	1.32
+++ src/mesa/drivers/dri/r200/r200_ioctl.c	14 Mar 2006 12:28:14 -0000
@@ -420,7 +420,8 @@
 
 /* Copy the back color buffer to the front color buffer.
  */
-void r200CopyBuffer( const __DRIdrawablePrivate *dPriv )
+void r200CopyBuffer( const __DRIdrawablePrivate *dPriv,
+		      const drm_clip_rect_t	 *rect)
 {
    r200ContextPtr rmesa;
    GLint nbox, i, ret;
@@ -446,9 +447,12 @@
     * request at a time.
     */
    r200WaitForFrameCompletion( rmesa );
-   UNLOCK_HARDWARE( rmesa );
-   driWaitForVBlank( dPriv, & rmesa->vbl_seq, rmesa->vblank_flags, & missed_target );
-   LOCK_HARDWARE( rmesa );
+   if (!rect)
+   {
+       UNLOCK_HARDWARE( rmesa );
+       driWaitForVBlank( dPriv, & rmesa->vbl_seq, rmesa->vblank_flags, & missed_target );
+       LOCK_HARDWARE( rmesa );
+   }
 
    nbox = dPriv->numClipRects; /* must be in locked region */
 
@@ -459,8 +463,27 @@
       GLint n = 0;
 
       for ( ; i < nr ; i++ ) {
-	 *b++ = box[i];
-	 n++;
+
+	  *b = box[i];
+
+	  if (rect)
+	  {
+	     if (rect->x1 > b->x1)
+		 b->x1 = rect->x1;
+	     if (rect->y1 > b->y1)
+		 b->y1 = rect->y1;
+	     if (rect->x2 < b->x2)
+		 b->x2 = rect->x2;
+	     if (rect->y2 < b->y2)
+		 b->y2 = rect->y2;
+
+	     if (b->x1 < b->x2 && b->y1 < b->y2)
+		 b++;
+	  }
+	  else
+	      b++;
+
+	  n++;
       }
       rmesa->sarea->nbox = n;
 
@@ -474,18 +497,21 @@
    }
 
    UNLOCK_HARDWARE( rmesa );
-   rmesa->hw.all_dirty = GL_TRUE;
+   if (!rect)
+   {
+       rmesa->hw.all_dirty = GL_TRUE;
 
-   rmesa->swap_count++;
-   (*dri_interface->getUST)( & ust );
-   if ( missed_target ) {
-      rmesa->swap_missed_count++;
-      rmesa->swap_missed_ust = ust - rmesa->swap_ust;
-   }
+       rmesa->swap_count++;
+       (*dri_interface->getUST)( & ust );
+       if ( missed_target ) {
+	   rmesa->swap_missed_count++;
+	   rmesa->swap_missed_ust = ust - rmesa->swap_ust;
+       }
 
-   rmesa->swap_ust = ust;
+       rmesa->swap_ust = ust;
 
-   sched_yield();
+       sched_yield();
+   }
 }
 
 void r200PageFlip( const __DRIdrawablePrivate *dPriv )
--- src/mesa/drivers/dri/r200/r200_ioctl.h	11 Oct 2005 17:55:54 -0000	1.14
+++ src/mesa/drivers/dri/r200/r200_ioctl.h	14 Mar 2006 12:28:14 -0000
@@ -90,7 +90,8 @@
 				    struct r200_dma_region *region,
 				    const char *caller );
 
-extern void r200CopyBuffer( const __DRIdrawablePrivate *drawable );
+extern void r200CopyBuffer( const __DRIdrawablePrivate *drawable,
+			    const drm_clip_rect_t      *rect);
 extern void r200PageFlip( const __DRIdrawablePrivate *drawable );
 extern void r200Flush( GLcontext *ctx );
 extern void r200Finish( GLcontext *ctx );
--- src/mesa/drivers/dri/r300/radeon_context.c	17 Dec 2005 11:39:40 -0000	1.8
+++ src/mesa/drivers/dri/r300/radeon_context.c	14 Mar 2006 12:28:17 -0000
@@ -229,7 +229,7 @@
 			if (radeon->doPageFlip) {
 				radeonPageFlip(dPriv);
 			} else {
-				radeonCopyBuffer(dPriv);
+			    radeonCopyBuffer(dPriv, NULL);
 			}
 		}
 	} else {
@@ -239,6 +239,31 @@
 	}
 }
 
+void radeonCopySubBuffer(__DRIdrawablePrivate * dPriv,
+			 int x, int y, int w, int h )
+{
+    if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
+	radeonContextPtr radeon;
+	GLcontext *ctx;
+
+	radeon = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
+	ctx = radeon->glCtx;
+
+	if (ctx->Visual.doubleBufferMode) {
+	    drm_clip_rect_t rect;
+	    rect.x1 = x + dPriv->x;
+	    rect.y1 = (dPriv->h - y - h) + dPriv->y;
+	    rect.x2 = rect.x1 + w;
+	    rect.y2 = rect.y1 + h;
+	    _mesa_notifySwapBuffers(ctx);	/* flush pending rendering comands */
+	    radeonCopyBuffer(dPriv, &rect);
+	}
+    } else {
+	/* XXX this shouldn't be an error but we can't handle it for now */
+	_mesa_problem(NULL, "%s: drawable has no context!",
+		      __FUNCTION__);
+    }
+}
 
 /* Force the context `c' to be the current context and associate with it
  * buffer `b'.
--- src/mesa/drivers/dri/r300/radeon_context.h	3 Sep 2005 16:40:44 -0000	1.7
+++ src/mesa/drivers/dri/r300/radeon_context.h	14 Mar 2006 12:28:17 -0000
@@ -203,6 +203,8 @@
 #define RADEON_CONTEXT(glctx) ((radeonContextPtr)(ctx->DriverCtx))
 
 extern void radeonSwapBuffers(__DRIdrawablePrivate * dPriv);
+extern void radeonCopySubBuffer(__DRIdrawablePrivate * dPriv,
+				int x, int y, int w, int h);
 extern GLboolean radeonInitContext(radeonContextPtr radeon,
 				   struct dd_function_table* functions,
 				   const __GLcontextModes * glVisual,
--- src/mesa/drivers/dri/r300/radeon_ioctl.c	2 Nov 2005 01:15:08 -0000	1.9
+++ src/mesa/drivers/dri/r300/radeon_ioctl.c	14 Mar 2006 12:28:17 -0000
@@ -145,7 +145,8 @@
 
 /* Copy the back color buffer to the front color buffer.
  */
-void radeonCopyBuffer(const __DRIdrawablePrivate * dPriv)
+void radeonCopyBuffer(const __DRIdrawablePrivate * dPriv,
+		      const drm_clip_rect_t	 * rect)
 {
 	radeonContextPtr radeon;
 	GLint nbox, i, ret;
@@ -174,10 +175,13 @@
 	 * request at a time.
 	 */
 	radeonWaitForFrameCompletion(radeon);
-	UNLOCK_HARDWARE(radeon);
-	driWaitForVBlank(dPriv, &radeon->vbl_seq, radeon->vblank_flags,
-			 &missed_target);
-	LOCK_HARDWARE(radeon);
+	if (!rect)
+	{
+	    UNLOCK_HARDWARE(radeon);
+	    driWaitForVBlank(dPriv, &radeon->vbl_seq, radeon->vblank_flags,
+			     &missed_target);
+	    LOCK_HARDWARE(radeon);
+	}
 
 	nbox = dPriv->numClipRects;	/* must be in locked region */
 
@@ -187,9 +191,28 @@
 		drm_clip_rect_t *b = radeon->sarea->boxes;
 		GLint n = 0;
 
-		for (; i < nr; i++) {
-			*b++ = box[i];
-			n++;
+		for ( ; i < nr ; i++ ) {
+
+		    *b = box[i];
+
+		    if (rect)
+		    {
+			if (rect->x1 > b->x1)
+			    b->x1 = rect->x1;
+			if (rect->y1 > b->y1)
+			    b->y1 = rect->y1;
+			if (rect->x2 < b->x2)
+			    b->x2 = rect->x2;
+			if (rect->y2 < b->y2)
+			    b->y2 = rect->y2;
+
+			if (b->x1 < b->x2 && b->y1 < b->y2)
+			    b++;
+		    }
+		    else
+			b++;
+
+		    n++;
 		}
 		radeon->sarea->nbox = n;
 
@@ -204,22 +227,24 @@
 	}
 
 	UNLOCK_HARDWARE(radeon);
-
-	if (IS_R200_CLASS(radeon->radeonScreen))
+	if (!rect)
+	{
+	    if (IS_R200_CLASS(radeon->radeonScreen))
 		((r200ContextPtr)radeon)->hw.all_dirty = GL_TRUE;
-	else
+	    else
 		((r300ContextPtr)radeon)->hw.all_dirty = GL_TRUE;
 
-	radeon->swap_count++;
-	(*dri_interface->getUST) (&ust);
-	if (missed_target) {
+	    radeon->swap_count++;
+	    (*dri_interface->getUST) (&ust);
+	    if (missed_target) {
 		radeon->swap_missed_count++;
 		radeon->swap_missed_ust = ust - radeon->swap_ust;
-	}
+	    }
 
-	radeon->swap_ust = ust;
+	    radeon->swap_ust = ust;
 
-	sched_yield();
+	    sched_yield();
+	}
 }
 
 void radeonPageFlip(const __DRIdrawablePrivate * dPriv)
--- src/mesa/drivers/dri/r300/radeon_ioctl.h	20 Jul 2005 21:35:27 -0000	1.2
+++ src/mesa/drivers/dri/r300/radeon_ioctl.h	14 Mar 2006 12:28:17 -0000
@@ -44,7 +44,8 @@
 #include "r200_context.h"
 #include "radeon_drm.h"
 
-extern void radeonCopyBuffer(const __DRIdrawablePrivate * drawable);
+extern void radeonCopyBuffer(const __DRIdrawablePrivate * drawable,
+			     const drm_clip_rect_t	* rect);
 extern void radeonPageFlip(const __DRIdrawablePrivate * drawable);
 extern void radeonFlush(GLcontext * ctx);
 extern void radeonFinish(GLcontext * ctx);
--- src/mesa/drivers/dri/radeon/radeon_context.c	3 Feb 2006 13:29:11 -0000	1.48
+++ src/mesa/drivers/dri/radeon/radeon_context.c	14 Mar 2006 12:28:18 -0000
@@ -572,7 +572,7 @@
             radeonPageFlip( dPriv );
          }
          else {
-            radeonCopyBuffer( dPriv );
+	     radeonCopyBuffer( dPriv, NULL );
          }
       }
    }
@@ -582,6 +582,31 @@
    }
 }
 
+void radeonCopySubBuffer(__DRIdrawablePrivate * dPriv,
+			 int x, int y, int w, int h )
+{
+    if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
+	radeonContextPtr radeon;
+	GLcontext *ctx;
+
+	radeon = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
+	ctx = radeon->glCtx;
+
+	if (ctx->Visual.doubleBufferMode) {
+	    drm_clip_rect_t rect;
+	    rect.x1 = x + dPriv->x;
+	    rect.y1 = (dPriv->h - y - h) + dPriv->y;
+	    rect.x2 = rect.x1 + w;
+	    rect.y2 = rect.y1 + h;
+	    _mesa_notifySwapBuffers(ctx);	/* flush pending rendering comands */
+	    radeonCopyBuffer(dPriv, &rect);
+	}
+    } else {
+	/* XXX this shouldn't be an error but we can't handle it for now */
+	_mesa_problem(NULL, "%s: drawable has no context!",
+		      __FUNCTION__);
+    }
+}
 
 /* Make context `c' the current context and bind it to the given
  * drawing and reading surfaces.
--- src/mesa/drivers/dri/radeon/radeon_context.h	15 Oct 2005 23:45:54 -0000	1.27
+++ src/mesa/drivers/dri/radeon/radeon_context.h	14 Mar 2006 12:28:18 -0000
@@ -846,6 +846,8 @@
 				     __DRIcontextPrivate *driContextPriv,
 				     void *sharedContextPrivate);
 extern void radeonSwapBuffers( __DRIdrawablePrivate *dPriv );
+extern void radeonCopySubBuffer(__DRIdrawablePrivate * dPriv,
+				int x, int y, int w, int h);
 extern GLboolean radeonMakeCurrent( __DRIcontextPrivate *driContextPriv,
 				    __DRIdrawablePrivate *driDrawPriv,
 				    __DRIdrawablePrivate *driReadPriv );
--- src/mesa/drivers/dri/radeon/radeon_ioctl.c	2 Nov 2005 01:15:07 -0000	1.30
+++ src/mesa/drivers/dri/radeon/radeon_ioctl.c	14 Mar 2006 12:28:18 -0000
@@ -875,7 +875,8 @@
 
 /* Copy the back color buffer to the front color buffer.
  */
-void radeonCopyBuffer( const __DRIdrawablePrivate *dPriv )
+void radeonCopyBuffer( const __DRIdrawablePrivate *dPriv,
+		       const drm_clip_rect_t	  *rect)
 {
    radeonContextPtr rmesa;
    GLint nbox, i, ret;
@@ -899,9 +900,12 @@
     * request at a time.
     */
    radeonWaitForFrameCompletion( rmesa );
-   UNLOCK_HARDWARE( rmesa );
-   driWaitForVBlank( dPriv, & rmesa->vbl_seq, rmesa->vblank_flags, & missed_target );
-   LOCK_HARDWARE( rmesa );
+   if (!rect)
+   {
+       UNLOCK_HARDWARE( rmesa );
+       driWaitForVBlank( dPriv, & rmesa->vbl_seq, rmesa->vblank_flags, & missed_target );
+       LOCK_HARDWARE( rmesa );
+   }
 
    nbox = dPriv->numClipRects; /* must be in locked region */
 
@@ -912,8 +916,27 @@
       GLint n = 0;
 
       for ( ; i < nr ; i++ ) {
-	 *b++ = box[i];
-	 n++;
+
+	  *b = box[i];
+
+	  if (rect)
+	  {
+	      if (rect->x1 > b->x1)
+		  b->x1 = rect->x1;
+	      if (rect->y1 > b->y1)
+		  b->y1 = rect->y1;
+	      if (rect->x2 < b->x2)
+		  b->x2 = rect->x2;
+	      if (rect->y2 < b->y2)
+		  b->y2 = rect->y2;
+
+	      if (b->x1 < b->x2 && b->y1 < b->y2)
+		  b++;
+	  }
+	  else
+	      b++;
+
+	  n++;
       }
       rmesa->sarea->nbox = n;
 
@@ -927,15 +950,18 @@
    }
 
    UNLOCK_HARDWARE( rmesa );
-   rmesa->swap_count++;
-   (*dri_interface->getUST)( & ust );
-   if ( missed_target ) {
-      rmesa->swap_missed_count++;
-      rmesa->swap_missed_ust = ust - rmesa->swap_ust;
-   }
+   if (!rect)
+   {
+       rmesa->swap_count++;
+       (*dri_interface->getUST)( & ust );
+       if ( missed_target ) {
+	   rmesa->swap_missed_count++;
+	   rmesa->swap_missed_ust = ust - rmesa->swap_ust;
+       }
 
-   rmesa->swap_ust = ust;
-   rmesa->hw.all_dirty = GL_TRUE;
+       rmesa->swap_ust = ust;
+       rmesa->hw.all_dirty = GL_TRUE;
+   }
 }
 
 void radeonPageFlip( const __DRIdrawablePrivate *dPriv )
--- src/mesa/drivers/dri/radeon/radeon_ioctl.h	11 Oct 2005 17:55:54 -0000	1.7
+++ src/mesa/drivers/dri/radeon/radeon_ioctl.h	14 Mar 2006 12:28:18 -0000
@@ -87,7 +87,8 @@
 				    struct radeon_dma_region *region,
 				    const char *caller );
 
-extern void radeonCopyBuffer( const __DRIdrawablePrivate *drawable );
+extern void radeonCopyBuffer( const __DRIdrawablePrivate *drawable,
+			      const drm_clip_rect_t	 *rect);
 extern void radeonPageFlip( const __DRIdrawablePrivate *drawable );
 extern void radeonFlush( GLcontext *ctx );
 extern void radeonFinish( GLcontext *ctx );
--- src/mesa/drivers/dri/radeon/radeon_screen.c	7 Mar 2006 05:31:36 -0000	1.54
+++ src/mesa/drivers/dri/radeon/radeon_screen.c	14 Mar 2006 12:28:18 -0000
@@ -708,6 +708,8 @@
       (*glx_enable_extension)( psc, "GLX_MESA_swap_frame_usage" );
       if (IS_R200_CLASS(screen))
 	 (*glx_enable_extension)( psc, "GLX_MESA_allocate_memory" );
+
+      (*glx_enable_extension)( psc, "GLX_MESA_copy_sub_buffer" );
    }
 
 #if RADEON_COMMON && defined(RADEON_COMMON_FOR_R200)
@@ -915,7 +917,8 @@
    .GetMSC          = driGetMSC32,
    .WaitForMSC      = driWaitForMSC32,
    .WaitForSBC      = NULL,
-   .SwapBuffersMSC  = NULL
+   .SwapBuffersMSC  = NULL,
+   .CopySubBuffer   = radeonCopySubBuffer,
 };
 #else
 static const struct __DriverAPIRec r200API = {
@@ -932,7 +935,8 @@
    .GetMSC          = driGetMSC32,
    .WaitForMSC      = driWaitForMSC32,
    .WaitForSBC      = NULL,
-   .SwapBuffersMSC  = NULL
+   .SwapBuffersMSC  = NULL,
+   .CopySubBuffer   = r200CopySubBuffer
 };
 #endif
 

Reply via email to