Hi,

I've been experiencing serious tearing in compiz when screen is painted only 
partly. Either "Sync To Vblank" option in compiz doesn't work or copying 
repainted parts from backbuffer to frontbuffer is too slow. And since many 
people rely on driver's implementation of Sync to Vblank, it would be optimal 
to always use glXSwapBuffers. This can be accomplished via keeping up-to-date 
copy of frontbuffer in backbuffer and painting updates over it.

My patch (swap-buffers-and-copy-only-needed.patch) keeps copy of last painted 
region and in case of partial screen repaint uses it to determine which parts 
should be copied from frontbuffer to backbuffer. Since region going to be 
painted this time is known, it can be substracted from last painted region. 
Thus only parts that were painted in previous pass and aren't going to be 
repainted, are copied saving expensive pixel copy operations.

Since glxCopySubBufferMESA does only implement copy-from-backbuffer (correct 
me if I'm wrong) it is no longer needed (remove-copySubBuffer.patch).

I've been using this a quite long time and it works generally well. Problem 
arises only when a plugin paints outside of the given region. For example 
screenshot (quick-n-dirty patch provided) and scale (shadows don't belong to 
damaged area, causing slowly darkening and finally solid black border around 
scaled windows) do that.

Pyry
diff --git a/include/compiz.h b/include/compiz.h
index 7e8c99a..dc69276 100644
--- a/include/compiz.h
+++ b/include/compiz.h
@@ -1475,13 +1475,6 @@ typedef void    (*GLXQueryDrawableProc)   (Display	 *display,
 					   int		 attribute,
 					   unsigned int  *value);
 
-typedef void (*GLXCopySubBufferProc) (Display     *display,
-				      GLXDrawable drawable,
-				      int	  x,
-				      int	  y,
-				      int	  width,
-				      int	  height);
-
 typedef int (*GLXGetVideoSyncProc)  (unsigned int *count);
 typedef int (*GLXWaitVideoSyncProc) (int	  divisor,
 				     int	  remainder,
@@ -1844,7 +1837,6 @@ struct _CompScreen {
     GLXBindTexImageProc      bindTexImage;
     GLXReleaseTexImageProc   releaseTexImage;
     GLXQueryDrawableProc     queryDrawable;
-    GLXCopySubBufferProc     copySubBuffer;
     GLXGetVideoSyncProc      getVideoSync;
     GLXWaitVideoSyncProc     waitVideoSync;
     GLXGetFBConfigsProc      getFBConfigs;
diff --git a/src/screen.c b/src/screen.c
index b82f194..080d7bc 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -1780,11 +1780,6 @@ addScreen (CompDisplay *display,
 	return FALSE;
     }
 
-    s->copySubBuffer = NULL;
-    if (strstr (glxExtensions, "GLX_MESA_copy_sub_buffer"))
-	s->copySubBuffer = (GLXCopySubBufferProc)
-	    getProcAddress (s, "glXCopySubBufferMESA");
-
     s->getVideoSync = NULL;
     s->waitVideoSync = NULL;
     if (strstr (glxExtensions, "GLX_SGI_video_sync"))
diff --git a/plugins/screenshot.c b/plugins/screenshot.c
index a66cc76..1a72eec 100644
--- a/plugins/screenshot.c
+++ b/plugins/screenshot.c
@@ -207,24 +207,40 @@ shotPaintScreen (CompScreen		 *s,
 
 	if (ss->grabIndex)
 	{
-	    glPushMatrix ();
+	    BoxPtr pBox = region->rects;
+	    int    nBox = region->numRects;
 
+	    glPushMatrix ();
 	    prepareXCoords (s, output, -DEFAULT_Z_CAMERA);
 
+	    glEnable (GL_SCISSOR_TEST);
 	    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
-	    glEnable (GL_BLEND);
-	    glColor4us (0x2fff, 0x2fff, 0x4fff, 0x4fff);
-	    glRecti (x1, y2, x2, y1);
-	    glColor4us (0x2fff, 0x2fff, 0x4fff, 0x9fff);
-	    glBegin (GL_LINE_LOOP);
-	    glVertex2i (x1, y1);
-	    glVertex2i (x2, y1);
-	    glVertex2i (x2, y2);
-	    glVertex2i (x1, y2);
-	    glEnd ();
-	    glColor4usv (defaultColor);
-	    glDisable (GL_BLEND);
+
+	    while (nBox--)
+	    {
+		glScissor (pBox->x1, s->height - pBox->y2,
+			   pBox->x2 - pBox->x1,
+			   pBox->y2 - pBox->y1);
+
+		glEnable (GL_BLEND);
+		glColor4us (0x2fff, 0x2fff, 0x4fff, 0x4fff);
+		glRecti (x1, y2, x2, y1);
+		glColor4us (0x2fff, 0x2fff, 0x4fff, 0x9fff);
+		glBegin (GL_LINE_LOOP);
+		glVertex2i (x1, y1);
+		glVertex2i (x2, y1);
+		glVertex2i (x2, y2);
+		glVertex2i (x1, y2);
+		glEnd ();
+		glColor4usv (defaultColor);
+		glDisable (GL_BLEND);
+		
+		pBox++;
+	    }
+
 	    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+	    glDisable (GL_SCISSOR_TEST);
+
 	    glPopMatrix ();
 	}
 	else if (output == (s->nOutputDev - 1))
diff --git a/src/display.c b/src/display.c
index 15236a8..99e8980 100644
--- a/src/display.c
+++ b/src/display.c
@@ -2028,7 +2028,7 @@ eventLoop (void)
     XEvent	   event;
     int		   timeDiff, i;
     struct timeval tv;
-    Region	   tmpRegion, outputRegion;
+    Region	   tmpRegion, outputRegion, copyRegion, lastPaintRegion;
     CompDisplay    *display = compDisplays;
     CompScreen	   *s;
     int		   time, timeToNextRedraw = 0;
@@ -2037,6 +2037,8 @@ eventLoop (void)
 
     tmpRegion = XCreateRegion ();
     outputRegion = XCreateRegion ();
+    copyRegion = XCreateRegion ();
+    lastPaintRegion = XCreateRegion ();
     if (!tmpRegion || !outputRegion)
     {
 	fprintf (stderr, "%s: Couldn't create temporary regions\n",
@@ -2224,6 +2226,54 @@ eventLoop (void)
 			    glClear (GL_COLOR_BUFFER_BIT);
 		    }
 
+		    /* copy painted parts from frontbuffer which are not
+		       going to be repainted so backbuffer is up-to-date
+		       when buffers are swapped */
+		    if (mask & COMP_SCREEN_DAMAGE_REGION_MASK)
+		    {
+			BoxPtr pBox;
+			int    nBox, y;
+
+			XSubtractRegion (lastPaintRegion, tmpRegion,
+					  copyRegion);
+
+			pBox = copyRegion->rects;
+			nBox = copyRegion->numRects;
+			
+			glEnable (GL_SCISSOR_TEST);
+			glReadBuffer (GL_FRONT);
+			glDrawBuffer (GL_BACK);
+
+			while (nBox--)
+			{
+			    y = s->height - pBox->y2;
+
+			    glBitmap (0, 0, 0, 0,
+				      pBox->x1 - s->rasterX,
+				      y - s->rasterY,
+				      NULL);
+
+			    s->rasterX = pBox->x1;
+			    s->rasterY = y;
+
+			    glScissor (pBox->x1, y,
+				       pBox->x2 - pBox->x1,
+				       pBox->y2 - pBox->y1);
+
+			    glCopyPixels (pBox->x1, y,
+				          pBox->x2 - pBox->x1,
+				          pBox->y2 - pBox->y1,
+				          GL_COLOR);
+
+			    pBox++;
+			}
+
+			glReadBuffer (GL_BACK);
+			glDisable (GL_SCISSOR_TEST);
+
+			XEmptyRegion (lastPaintRegion);
+		    }
+
 		    for (i = 0; i < s->nOutputDev; i++)
 		    {
 			targetScreen = s;
@@ -2266,7 +2316,6 @@ eventLoop (void)
 				XUnionRegion (tmpRegion,
 					      &s->outputDev[i].region,
 					      tmpRegion);
-
 			    }
 			}
 		    }
@@ -2276,69 +2325,9 @@ eventLoop (void)
 
 		    waitForVideoSync (s);
 
-		    if (mask & COMP_SCREEN_DAMAGE_ALL_MASK)
-		    {
-			glXSwapBuffers (display->display, s->output);
-		    }
-		    else
-		    {
-			BoxPtr pBox;
-			int    nBox, y;
-
-			pBox = tmpRegion->rects;
-			nBox = tmpRegion->numRects;
-
-			if (s->copySubBuffer)
-			{
-			    while (nBox--)
-			    {
-				y = s->height - pBox->y2;
-
-				(*s->copySubBuffer) (display->display,
-						     s->output,
-						     pBox->x1, y,
-						     pBox->x2 -
-						     pBox->x1,
-						     pBox->y2 -
-						     pBox->y1);
-
-				pBox++;
-			    }
-			}
-			else
-			{
-			    glEnable (GL_SCISSOR_TEST);
-			    glDrawBuffer (GL_FRONT);
+		    glXSwapBuffers (display->display, s->output);
 
-			    while (nBox--)
-			    {
-				y = s->height - pBox->y2;
-
-				glBitmap (0, 0, 0, 0,
-					  pBox->x1 - s->rasterX,
-					  y - s->rasterY,
-					  NULL);
-
-				s->rasterX = pBox->x1;
-				s->rasterY = y;
-
-				glScissor (pBox->x1, y,
-					   pBox->x2 - pBox->x1,
-					   pBox->y2 - pBox->y1);
-
-				glCopyPixels (pBox->x1, y,
-					      pBox->x2 - pBox->x1,
-					      pBox->y2 - pBox->y1,
-					      GL_COLOR);
-
-				pBox++;
-			    }
-
-			    glDrawBuffer (GL_BACK);
-			    glDisable (GL_SCISSOR_TEST);
-			    glFlush ();
-			}
-		    }
+		    XUnionRegion (lastPaintRegion, tmpRegion, lastPaintRegion);
 
 		    s->lastRedraw = tv;
 
_______________________________________________
compiz mailing list
compiz@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/compiz

Reply via email to