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