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
[email protected]
http://lists.freedesktop.org/mailman/listinfo/compiz