From cb51bc2690ff6a14c2306410810c461f9af3d516 Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Apr 30 2010 17:52:02 +0000 Subject: * Fri Apr 30 2010 Owen Taylor - 1.8.0-9 - Add patches cherry-picked from master for DRI2 VBlank synchronization (related to RH #577512, though not a complete fix without changes in other packages) - Add a new patch for RH #577142 that does a better job of fixing the handling of redirected pixmaps. --- diff --git a/xorg-x11-server.spec b/xorg-x11-server.spec index c003a89..b1e77eb 100644 --- a/xorg-x11-server.spec +++ b/xorg-x11-server.spec @@ -19,7 +19,7 @@ Summary: X.Org X11 X server Name: xorg-x11-server Version: 1.8.0 -Release: 8%{?gitdate:.%{gitdate}}%{dist} +Release: 9%{?gitdate:.%{gitdate}}%{dist} URL: http://www.x.org License: MIT Group: User Interface/X @@ -89,8 +89,8 @@ Patch6053: xserver-1.8-disable-vboxvideo.patch Patch6055: xserver-1.7.6-export-dix-functions.patch Patch6056: xserver-1.7.6-export-more-dix-functions.patch Patch6057: xserver-1.8.0-xorg.conf.d-changes.patch -Patch6058: xserver-1.8.0-glxdri2-resource-conversion.patch -Patch6059: xserver-1.8.0-dri2-fix-handling-of-redirected-pixmaps.patch +Patch6058: xserver-1.8.0-swap-fixes.patch +Patch6059: xserver-1.8.0-glxdri2-resource-conversion.patch %define moduledir %{_libdir}/xorg/modules %define drimoduledir %{_libdir}/dri @@ -532,6 +532,13 @@ rm -rf $RPM_BUILD_ROOT %{xserver_source_dir} %changelog +* Fri Apr 30 2010 Owen Taylor - 1.8.0-9 +- Add patches cherry-picked from master for DRI2 VBlank synchronization + (related to RH #577512, though not a complete fix without changes + in other packages) +- Add a new patch for RH #577142 that does a better job of fixing + the handling of redirected pixmaps. + * Fri Apr 23 2010 Adel Gadllah 1.8.0-8 - xserver-1.8.0-dri2-fix-handling-of-redirected-pixmaps.patch: Fix handling of redirected pixmaps. (RH #577142) diff --git a/xserver-1.8.0-glxdri2-resource-conversion.patch b/xserver-1.8.0-glxdri2-resource-conversion.patch index f2c51a5..6c450ac 100644 --- a/xserver-1.8.0-glxdri2-resource-conversion.patch +++ b/xserver-1.8.0-glxdri2-resource-conversion.patch @@ -1,21 +1,105 @@ -From 0eb88ae7bccdd38863d4599309ca07068386f415 Mon Sep 17 00:00:00 2001 -From: Adam Jackson -Date: Tue, 20 Apr 2010 13:43:52 -0400 -Subject: [PATCH] DRI2/GLX: Switch to resource system for drawable tracking +From b75609ab65bf2aeee553435e43072d7f859162f7 Mon Sep 17 00:00:00 2001 +From: Owen Taylor +Date: Fri, 30 Apr 2010 13:17:18 -0400 +Subject: [PATCH 2/2] Merge fixes for DRI drawable handling from master +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit -Signed-off-by: Adam Jackson +commit a92b2c2c8dd1e86ee852168146f01bdf72bfe2d0 +Author: Kristian Høgsberg +Date: Fri Apr 16 05:55:35 2010 -0400 + +glx: Drop DestroyWindow hook + +Now that glx doesn't call DRI2DestroyDrawable anymore, we don't need to +force a specific resource destruction order in the DestroyWindow hook. + +Signed-off-by: Kristian Høgsberg +Reviewed-by: Michel Dänzer + +https://bugs.freedesktop.org/show_bug.cgi?id=26394 +Signed-off-by: Keith Packard + +commit 3ff8ba50a6a173bfb6d42dc7e2fd5da4e8706db8 +Author: Kristian Høgsberg +Date: Thu, 29 Apr 2010 16:36:10 -0400 + +dri2: Take an XID for tracking the DRI2 drawable + +Some pixmaps (window pixmaps and scratch pixmaps) don't have the +drawable->id set and thus DRI2 gets confused when using that field +for looking up the DRI2 drawable. Go back to using privates for getting +at the DRI2 drawable from a DrawablePtr. We need to keep the resource +tracking in place so we can remove the DRI2 drawable when the X resource +it was created for goes away. Additionally, we also now track the DRI2 +drawable using a client XID so we can reclaim the DRI2 drawable even if +the client goes before the drawable and doesn't destroy the DRI2 drawable. + +commit 1da1f33f2dd5b437dd56cd9f5d6782de4ad5a1bc +Author: Kristian Høgsberg +Date: Fri Apr 16 05:55:34 2010 -0400 + +DRI2: Track DRI2 drawables as resources, not privates + +The main motivation here is to have the resource system clean up the +DRI2 drawable automatically so glx doesn't have to. Right now, the +glx drawable resource must be destroyed before the X drawable, so that +calling DRI2DestroyDrawable doesn't crash. By making the DRI2 +drawable a resource, GLX doesn't have to worry about that and the +resource destruction order becomes irrelevant. + +https://bugs.freedesktop.org/show_bug.cgi?id=26394 + +Signed-off-by: Kristian Høgsberg +Signed-off-by: Keith Packard + +commit f0006aa58f6cf7552a239e169ff6e7e4fda532f4 +Author: Kristian Høgsberg +Date: Fri Apr 16 05:55:32 2010 -0400 + +glx: Track GLX 1.3 style GLX drawables under their X drawable ID as well + +This ensures that the DrawableGone callback gets called as necessary +when the X drawable goes away. Otherwise, using a GLX drawable +(say, glXSwapBuffers) in indirect mode after the X drawable has been +destroyed will crash the server. + +Signed-off-by: Kristian Høgsberg +Reviewed-by: Michel Dänzer +Signed-off-by: Keith Packard + +commit 22da7aa9d743deee198aaf6df5d370a446db9763 +Author: Kristian Høgsberg +Date: Fri Apr 16 05:55:33 2010 -0400 + +glx: Let the resource system destroy pixmaps + +GLX pbuffers are implemented using a pixmap allocated by the server. +With the change to DRI2 to track DRI2 drawables as resources, we need to make +sure that every drawable we create a DRI2 drawable for has an XID. By +using the XID of the pbuffer, the resource system will automatically +reclaim the hidden pixmap and the DRI2 drawable when the pbuffer is +destroyed or the client exits. + +Signed-off-by: Kristian Høgsberg +Signed-off-by: Keith Packard --- - glx/glxcmds.c | 39 +++++++++----- - glx/glxdri2.c | 5 -- - glx/glxext.c | 11 ++++ - glx/glxscreens.c | 28 ---------- - glx/glxscreens.h | 1 - - hw/xfree86/dri2/dri2.c | 131 ++++++++++++-------------------------------- - hw/xfree86/dri2/dri2ext.c | 22 -------- - 7 files changed, 73 insertions(+), 164 deletions(-) + glx/glxcmds.c | 62 ++++++++----- + glx/glxdri.c | 8 +- + glx/glxdri2.c | 17 ++-- + glx/glxdriswrast.c | 8 +- + glx/glxext.c | 11 +++ + glx/glxscreens.c | 40 +-------- + glx/glxscreens.h | 7 +- + hw/xfree86/dri2/dri2.c | 221 +++++++++++++++++++++++++-------------------- + hw/xfree86/dri2/dri2.h | 3 +- + hw/xfree86/dri2/dri2ext.c | 24 +----- + include/list.h | 6 ++ + 11 files changed, 204 insertions(+), 203 deletions(-) diff --git a/glx/glxcmds.c b/glx/glxcmds.c -index 77afbf4..087d52e 100644 +index 77afbf4..31a7d32 100644 --- a/glx/glxcmds.c +++ b/glx/glxcmds.c @@ -161,7 +161,11 @@ validGlxDrawable(ClientPtr client, XID id, int type, int access_mode, @@ -30,7 +114,19 @@ index 77afbf4..087d52e 100644 (type != GLX_DRAWABLE_ANY && type != (*drawable)->type)) { client->errorValue = id; switch (type) { -@@ -1097,14 +1101,6 @@ __glXDrawableInit(__GLXdrawable *drawable, +@@ -508,8 +512,9 @@ __glXGetDrawable(__GLXcontext *glxc, GLXDrawable drawId, ClientPtr client, + if (!validGlxFBConfigForWindow(client, glxc->config, pDraw, error)) + return NULL; + +- pGlxDraw = glxc->pGlxScreen->createDrawable(glxc->pGlxScreen, +- pDraw, GLX_DRAWABLE_WINDOW, ++ pGlxDraw = glxc->pGlxScreen->createDrawable(client, glxc->pGlxScreen, ++ pDraw, drawId, ++ GLX_DRAWABLE_WINDOW, + drawId, glxc->config); + + /* since we are creating the drawablePrivate, drawId should be new */ +@@ -1097,28 +1102,20 @@ __glXDrawableInit(__GLXdrawable *drawable, void __glXDrawableRelease(__GLXdrawable *drawable) { @@ -45,7 +141,11 @@ index 77afbf4..087d52e 100644 } static int -@@ -1113,8 +1109,6 @@ DoCreateGLXDrawable(ClientPtr client, __GLXscreen *pGlxScreen, __GLXconfig *conf +-DoCreateGLXDrawable(ClientPtr client, __GLXscreen *pGlxScreen, __GLXconfig *config, +- DrawablePtr pDraw, XID glxDrawableId, int type) ++DoCreateGLXDrawable(ClientPtr client, __GLXscreen *pGlxScreen, ++ __GLXconfig *config, DrawablePtr pDraw, XID drawableId, ++ XID glxDrawableId, int type) { __GLXdrawable *pGlxDraw; @@ -54,7 +154,13 @@ index 77afbf4..087d52e 100644 if (pGlxScreen->pScreen != pDraw->pScreen) return BadMatch; -@@ -1128,6 +1122,15 @@ DoCreateGLXDrawable(ClientPtr client, __GLXscreen *pGlxScreen, __GLXconfig *conf +- pGlxDraw = pGlxScreen->createDrawable(pGlxScreen, pDraw, type, ++ pGlxDraw = pGlxScreen->createDrawable(client, pGlxScreen, pDraw, ++ drawableId, type, + glxDrawableId, config); + if (pGlxDraw == NULL) + return BadAlloc; +@@ -1128,6 +1125,15 @@ DoCreateGLXDrawable(ClientPtr client, __GLXscreen *pGlxScreen, __GLXconfig *conf return BadAlloc; } @@ -70,7 +176,7 @@ index 77afbf4..087d52e 100644 return Success; } -@@ -1138,6 +1141,8 @@ DoCreateGLXPixmap(ClientPtr client, __GLXscreen *pGlxScreen, __GLXconfig *config +@@ -1138,6 +1144,8 @@ DoCreateGLXPixmap(ClientPtr client, __GLXscreen *pGlxScreen, __GLXconfig *config DrawablePtr pDraw; int err; @@ -79,8 +185,12 @@ index 77afbf4..087d52e 100644 err = dixLookupDrawable(&pDraw, drawableId, client, 0, DixAddAccess); if (err != Success) { client->errorValue = drawableId; -@@ -1151,9 +1156,6 @@ DoCreateGLXPixmap(ClientPtr client, __GLXscreen *pGlxScreen, __GLXconfig *config - err = DoCreateGLXDrawable(client, pGlxScreen, config, pDraw, +@@ -1148,12 +1156,9 @@ DoCreateGLXPixmap(ClientPtr client, __GLXscreen *pGlxScreen, __GLXconfig *config + return BadPixmap; + } + +- err = DoCreateGLXDrawable(client, pGlxScreen, config, pDraw, ++ err = DoCreateGLXDrawable(client, pGlxScreen, config, pDraw, drawableId, glxDrawableId, GLX_DRAWABLE_PIXMAP); - if (err == Success) @@ -89,7 +199,16 @@ index 77afbf4..087d52e 100644 return err; } -@@ -1294,6 +1296,8 @@ DoCreatePbuffer(ClientPtr client, int screenNum, XID fbconfigId, +@@ -1266,7 +1271,7 @@ static int DoDestroyDrawable(__GLXclientState *cl, XID glxdrawable, int type) + DixDestroyAccess, &pGlxDraw, &err)) + return err; + +- FreeResource(glxdrawable, FALSE); ++ FreeResourceByType(glxdrawable, __glXDrawableRes, FALSE); + + return Success; + } +@@ -1294,6 +1299,8 @@ DoCreatePbuffer(ClientPtr client, int screenNum, XID fbconfigId, PixmapPtr pPixmap; int err; @@ -98,7 +217,7 @@ index 77afbf4..087d52e 100644 if (!validGlxScreen(client, screenNum, &pGlxScreen, &err)) return err; if (!validGlxFBConfig(client, pGlxScreen, fbconfigId, &config, &err)) -@@ -1304,6 +1308,13 @@ DoCreatePbuffer(ClientPtr client, int screenNum, XID fbconfigId, +@@ -1304,8 +1311,16 @@ DoCreatePbuffer(ClientPtr client, int screenNum, XID fbconfigId, width, height, config->rgbBits, 0); __glXleaveServer(GL_FALSE); @@ -110,9 +229,13 @@ index 77afbf4..087d52e 100644 + return BadAlloc; + return DoCreateGLXDrawable(client, pGlxScreen, config, &pPixmap->drawable, - glxDrawableId, GLX_DRAWABLE_PBUFFER); +- glxDrawableId, GLX_DRAWABLE_PBUFFER); ++ glxDrawableId, glxDrawableId, ++ GLX_DRAWABLE_PBUFFER); } -@@ -1411,6 +1422,8 @@ int __glXDisp_CreateWindow(__GLXclientState *cl, GLbyte *pc) + + int __glXDisp_CreatePbuffer(__GLXclientState *cl, GLbyte *pc) +@@ -1411,6 +1426,8 @@ int __glXDisp_CreateWindow(__GLXclientState *cl, GLbyte *pc) DrawablePtr pDraw; int err; @@ -121,8 +244,46 @@ index 77afbf4..087d52e 100644 if (!validGlxScreen(client, req->screen, &pGlxScreen, &err)) return err; if (!validGlxFBConfig(client, pGlxScreen, req->fbconfig, &config, &err)) +@@ -1426,7 +1443,8 @@ int __glXDisp_CreateWindow(__GLXclientState *cl, GLbyte *pc) + return err; + + return DoCreateGLXDrawable(client, pGlxScreen, config, +- pDraw, req->glxwindow, GLX_DRAWABLE_WINDOW); ++ pDraw, req->window, ++ req->glxwindow, GLX_DRAWABLE_WINDOW); + } + + int __glXDisp_DestroyWindow(__GLXclientState *cl, GLbyte *pc) +diff --git a/glx/glxdri.c b/glx/glxdri.c +index 21e44d1..e4870c3 100644 +--- a/glx/glxdri.c ++++ b/glx/glxdri.c +@@ -682,10 +682,12 @@ __glXDRIscreenCreateContext(__GLXscreen *baseScreen, + } + + static __GLXdrawable * +-__glXDRIscreenCreateDrawable(__GLXscreen *screen, ++__glXDRIscreenCreateDrawable(ClientPtr client, ++ __GLXscreen *screen, + DrawablePtr pDraw, +- int type, + XID drawId, ++ int type, ++ XID glxDrawId, + __GLXconfig *glxConfig) + { + __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen; +@@ -699,7 +701,7 @@ __glXDRIscreenCreateDrawable(__GLXscreen *screen, + return NULL; + + if (!__glXDrawableInit(&private->base, screen, +- pDraw, type, drawId, glxConfig)) { ++ pDraw, type, glxDrawId, glxConfig)) { + xfree(private); + return NULL; + } diff --git a/glx/glxdri2.c b/glx/glxdri2.c -index fd435ee..6449978 100644 +index e791bf6..38b52bd 100644 --- a/glx/glxdri2.c +++ b/glx/glxdri2.c @@ -105,11 +105,6 @@ __glXDRIdrawableDestroy(__GLXdrawable *drawable) @@ -137,6 +298,76 @@ index fd435ee..6449978 100644 __glXDrawableRelease(drawable); xfree(private); +@@ -435,10 +430,12 @@ __glXDRIscreenCreateContext(__GLXscreen *baseScreen, + } + + static __GLXdrawable * +-__glXDRIscreenCreateDrawable(__GLXscreen *screen, ++__glXDRIscreenCreateDrawable(ClientPtr client, ++ __GLXscreen *screen, + DrawablePtr pDraw, +- int type, + XID drawId, ++ int type, ++ XID glxDrawId, + __GLXconfig *glxConfig) + { + __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen; +@@ -451,7 +448,7 @@ __glXDRIscreenCreateDrawable(__GLXscreen *screen, + + private->screen = driScreen; + if (!__glXDrawableInit(&private->base, screen, +- pDraw, type, drawId, glxConfig)) { ++ pDraw, type, glxDrawId, glxConfig)) { + xfree(private); + return NULL; + } +@@ -462,7 +459,7 @@ __glXDRIscreenCreateDrawable(__GLXscreen *screen, + private->base.waitGL = __glXDRIdrawableWaitGL; + private->base.waitX = __glXDRIdrawableWaitX; + +- if (DRI2CreateDrawable(pDraw)) { ++ if (DRI2CreateDrawable(client, pDraw, drawId)) { + xfree(private); + return NULL; + } +@@ -722,7 +719,7 @@ __glXDRIscreenProbe(ScreenPtr pScreen) + screen->core = (const __DRIcoreExtension *) extensions[i]; + } + if (strcmp(extensions[i]->name, __DRI_DRI2) == 0 && +- extensions[i]->version >= __DRI_DRI2_VERSION) { ++ extensions[i]->version >= 1) { + screen->dri2 = (const __DRIdri2Extension *) extensions[i]; + } + } +diff --git a/glx/glxdriswrast.c b/glx/glxdriswrast.c +index c647d83..6a34393 100644 +--- a/glx/glxdriswrast.c ++++ b/glx/glxdriswrast.c +@@ -301,10 +301,12 @@ glxChangeGC(GCPtr gc, BITS32 mask, CARD32 val) + } + + static __GLXdrawable * +-__glXDRIscreenCreateDrawable(__GLXscreen *screen, ++__glXDRIscreenCreateDrawable(ClientPtr client, ++ __GLXscreen *screen, + DrawablePtr pDraw, +- int type, + XID drawId, ++ int type, ++ XID glxDrawId, + __GLXconfig *glxConfig) + { + __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen; +@@ -319,7 +321,7 @@ __glXDRIscreenCreateDrawable(__GLXscreen *screen, + + private->screen = driScreen; + if (!__glXDrawableInit(&private->base, screen, +- pDraw, type, drawId, glxConfig)) { ++ pDraw, type, glxDrawId, glxConfig)) { + xfree(private); + return NULL; + } diff --git a/glx/glxext.c b/glx/glxext.c index 59bcfbe..89e58b0 100644 --- a/glx/glxext.c @@ -160,7 +391,7 @@ index 59bcfbe..89e58b0 100644 if (c->isCurrent && (c->drawPriv == glxPriv || c->readPriv == glxPriv)) { int i; diff --git a/glx/glxscreens.c b/glx/glxscreens.c -index 58d8ee0..b75aea6 100644 +index 58d8ee0..da11834 100644 --- a/glx/glxscreens.c +++ b/glx/glxscreens.c @@ -215,7 +215,6 @@ glxCloseScreen (int index, ScreenPtr pScreen) @@ -212,11 +443,60 @@ index 58d8ee0..b75aea6 100644 i = 0; for (m = pGlxScreen->fbconfigs; m != NULL; m = m->next) { +@@ -427,31 +399,23 @@ void __glXScreenInit(__GLXscreen *pGlxScreen, ScreenPtr pScreen) + * an existing, appropriate visual. + */ + for (config = pGlxScreen->fbconfigs; config != NULL; config = config->next) { +- int depth; +- + VisualPtr visual; + + if (config->visualID != 0) + continue; + +- /* Only count RGB bits and not alpha, as we're not trying to create +- * visuals for compositing (that's what the 32-bit composite visual +- * set up above is for. +- */ +- depth = config->redBits + config->greenBits + config->blueBits; +- + /* Make sure that our FBconfig's depth can actually be displayed + * (corresponds to an existing visual). + */ + for (i = 0; i < pScreen->numVisuals; i++) { +- if (depth == pScreen->visuals[i].nplanes) ++ if (config->rgbBits == pScreen->visuals[i].nplanes) + break; + } + if (i == pScreen->numVisuals) + continue; + + /* Create a new X visual for our FBconfig. */ +- visual = AddScreenVisuals(pScreen, 1, depth); ++ visual = AddScreenVisuals(pScreen, 1, config->rgbBits); + if (visual == NULL) + continue; + diff --git a/glx/glxscreens.h b/glx/glxscreens.h -index bff4363..d52099f 100644 +index bff4363..861e03c 100644 --- a/glx/glxscreens.h +++ b/glx/glxscreens.h -@@ -173,7 +173,6 @@ struct __GLXscreen { +@@ -134,10 +134,12 @@ struct __GLXscreen { + __GLXconfig *modes, + __GLXcontext *shareContext); + +- __GLXdrawable *(*createDrawable)(__GLXscreen *context, ++ __GLXdrawable *(*createDrawable)(ClientPtr client, ++ __GLXscreen *context, + DrawablePtr pDraw, +- int type, + XID drawId, ++ int type, ++ XID glxDrawId, + __GLXconfig *modes); + int (*swapInterval) (__GLXdrawable *drawable, + int interval); +@@ -173,7 +175,6 @@ struct __GLXscreen { /*@}*/ Bool (*CloseScreen)(int index, ScreenPtr pScreen); @@ -225,12 +505,20 @@ index bff4363..d52099f 100644 diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c -index 48618e1..b8cbc52 100644 +index 2bdb733..178116a 100644 --- a/hw/xfree86/dri2/dri2.c +++ b/hw/xfree86/dri2/dri2.c -@@ -45,15 +45,14 @@ - - #include "xf86.h" +@@ -37,6 +37,7 @@ + #include + #include + #include "xf86Module.h" ++#include "list.h" + #include "scrnintstr.h" + #include "windowstr.h" + #include "dixstruct.h" +@@ -48,15 +49,16 @@ + CARD8 dri2_major; /* version of DRI2 supported by DDX */ + CARD8 dri2_minor; -static int dri2ScreenPrivateKeyIndex; +static int dri2ScreenPrivateKeyIndex; @@ -246,10 +534,12 @@ index 48618e1..b8cbc52 100644 typedef struct _DRI2Drawable { - unsigned int refCount; + DRI2ScreenPtr dri2_screen; ++ DrawablePtr drawable; ++ struct list reference_list; int width; int height; DRI2BufferPtr *buffers; -@@ -67,9 +66,8 @@ typedef struct _DRI2Drawable { +@@ -73,9 +75,9 @@ typedef struct _DRI2Drawable { int swap_limit; /* for N-buffering */ } DRI2DrawableRec, *DRI2DrawablePtr; @@ -257,10 +547,11 @@ index 48618e1..b8cbc52 100644 - typedef struct _DRI2Screen { + ScreenPtr screen; ++ int refcnt; unsigned int numDrivers; const char **driverNames; const char *deviceName; -@@ -95,43 +93,33 @@ DRI2GetScreen(ScreenPtr pScreen) +@@ -101,45 +103,30 @@ DRI2GetScreen(ScreenPtr pScreen) static DRI2DrawablePtr DRI2GetDrawable(DrawablePtr pDraw) { @@ -288,13 +579,16 @@ index 48618e1..b8cbc52 100644 + return pPriv; } - int - DRI2CreateDrawable(DrawablePtr pDraw) +-int +-DRI2CreateDrawable(DrawablePtr pDraw) ++static DRI2DrawablePtr ++DRI2AllocateDrawable(DrawablePtr pDraw) { + DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); - WindowPtr pWin; - PixmapPtr pPixmap; DRI2DrawablePtr pPriv; -+ int rc; + CARD64 ust; - pPriv = DRI2GetDrawable(pDraw); - if (pPriv != NULL) @@ -302,23 +596,23 @@ index 48618e1..b8cbc52 100644 - pPriv->refCount++; - return Success; - } -+ rc = dixLookupResourceByType((pointer *) &pPriv, pDraw->id, -+ dri2DrawableRes, NULL, DixReadAccess); -+ if (rc == Success || rc != BadValue) -+ return rc; - +- pPriv = xalloc(sizeof *pPriv); if (pPriv == NULL) - return BadAlloc; +- return BadAlloc; ++ return NULL; - pPriv->refCount = 1; -+ pPriv->dri2_screen = DRI2GetScreen(pDraw->pScreen); ++ pPriv->dri2_screen = ds; ++ pPriv->drawable = pDraw; pPriv->width = pDraw->width; pPriv->height = pDraw->height; pPriv->buffers = NULL; -@@ -144,43 +132,30 @@ DRI2CreateDrawable(DrawablePtr pDraw) - pPriv->last_swap_target = -1; +@@ -157,44 +144,116 @@ DRI2CreateDrawable(DrawablePtr pDraw) pPriv->swap_limit = 1; /* default to double buffering */ + pPriv->last_swap_msc = 0; + pPriv->last_swap_ust = 0; ++ list_init(&pPriv->reference_list); - if (pDraw->type == DRAWABLE_WINDOW) - { @@ -329,67 +623,175 @@ index 48618e1..b8cbc52 100644 - { - pPixmap = (PixmapPtr) pDraw; - dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, pPriv); -- } -+ if (!AddResource(pDraw->id, dri2DrawableRes, pPriv)) ++ return pPriv; ++} ++ ++typedef struct DRI2DrawableRefRec { ++ XID id; ++ XID dri2_id; ++ struct list link; ++} DRI2DrawableRefRec, *DRI2DrawableRefPtr; ++ ++static DRI2DrawableRefPtr ++DRI2LookupDrawableRef(DRI2DrawablePtr pPriv, XID id, XID dri2_id) ++{ ++ DRI2DrawableRefPtr ref; ++ ++ list_for_each_entry(ref, &pPriv->reference_list, link) { ++ if (id != None && ref->id == id) ++ return ref; ++ if (dri2_id != None && ref->dri2_id == dri2_id) ++ return ref; + } ++ ++ return NULL; ++} ++ ++static int ++DRI2AddDrawableRef(DRI2DrawablePtr pPriv, XID id, XID dri2_id) ++{ ++ DRI2DrawableRefPtr ref; ++ ++ ref = malloc(sizeof *ref); ++ if (ref == NULL) ++ return BadAlloc; ++ ++ if (!AddResource(dri2_id, dri2DrawableRes, pPriv)) + return BadAlloc; ++ if (!DRI2LookupDrawableRef(pPriv, id, None)) ++ if (!AddResource(id, dri2DrawableRes, pPriv)) ++ return BadAlloc; ++ ++ ref->id = id; ++ ref->dri2_id = dri2_id; ++ list_add(&ref->link, &pPriv->reference_list); return Success; } -static void -DRI2FreeDrawable(DrawablePtr pDraw) -+static int DRI2DrawableGone(pointer p, XID id) ++int ++DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id) { -- DRI2DrawablePtr pPriv; + DRI2DrawablePtr pPriv; - WindowPtr pWin; - PixmapPtr pPixmap; -+ DRI2DrawablePtr pPriv = p; -+ DRI2ScreenPtr ds = pPriv->dri2_screen; -+ DrawablePtr root; -+ int i; ++ XID dri2_id; ++ int rc; -- pPriv = DRI2GetDrawable(pDraw); -- if (pPriv == NULL) + pPriv = DRI2GetDrawable(pDraw); + if (pPriv == NULL) - return; -+ root = &WindowTable[ds->screen->myNum]->drawable; -+ if (pPriv->buffers != NULL) { -+ for (i = 0; i < pPriv->bufferCount; i++) -+ (*ds->DestroyBuffer)(root, pPriv->buffers[i]); -+ -+ xfree(pPriv->buffers); -+ } ++ pPriv = DRI2AllocateDrawable(pDraw); ++ if (pPriv == NULL) ++ return BadAlloc; ++ ++ dri2_id = FakeClientID(client->index); ++ rc = DRI2AddDrawableRef(pPriv, id, dri2_id); ++ if (rc != Success) ++ return rc; - xfree(pPriv); +- xfree(pPriv); ++ return Success; ++} - if (pDraw->type == DRAWABLE_WINDOW) - { - pWin = (WindowPtr) pDraw; - dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, NULL); -- } ++static int DRI2DrawableGone(pointer p, XID id) ++{ ++ DRI2DrawablePtr pPriv = p; ++ DRI2ScreenPtr ds = pPriv->dri2_screen; ++ DRI2DrawableRefPtr ref, next; ++ DrawablePtr root; ++ int i; ++ ++ list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) { ++ if (ref->dri2_id == id) { ++ list_del(&ref->link); ++ /* If this was the last ref under this X drawable XID, ++ * unregister the X drawable resource. */ ++ if (!DRI2LookupDrawableRef(pPriv, ref->id, None)) ++ FreeResourceByType(ref->id, dri2DrawableRes, TRUE); ++ break; ++ } ++ ++ if (ref->id == id) { ++ list_del(&ref->link); ++ FreeResourceByType(ref->dri2_id, dri2DrawableRes, TRUE); ++ free(ref); ++ } + } - else - { - pPixmap = (PixmapPtr) pDraw; - dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, NULL); -- } ++ ++ if (!list_is_empty(&pPriv->reference_list)) ++ return Success; ++ ++ ErrorF("freeing dri2 drawable\n"); ++ ++ root = &WindowTable[ds->screen->myNum]->drawable; ++ if (pPriv->buffers != NULL) { ++ for (i = 0; i < pPriv->bufferCount; i++) ++ (*ds->DestroyBuffer)(root, pPriv->buffers[i]); ++ ++ xfree(pPriv->buffers); + } ++ ++ xfree(pPriv); ++ + return Success; } static int -@@ -534,13 +509,6 @@ DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame, - return; - } +@@ -505,10 +564,6 @@ DRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw, int frame, -- if (pPriv->refCount == 0) { -- xf86DrvMsg(pScreen->myNum, X_ERROR, -- "[DRI2] %s: bad drawable refcount\n", __func__); + pPriv->blockedClient = NULL; + pPriv->blockedOnMsc = FALSE; +- +- /* If there's still a swap pending, let DRI2SwapComplete free it */ +- if (pPriv->refCount == 0 && pPriv->swapsPending == 0) - DRI2FreeDrawable(pDraw); -- return; -- } + } + + static void +@@ -576,13 +631,6 @@ DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame, + pPriv->last_swap_ust = ust; + + DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec); - - ust = ((CARD64)tv_sec * 1000000) + tv_usec; - if (swap_complete) - swap_complete(client, swap_data, type, ust, frame, pPriv->swap_count); -@@ -753,36 +721,6 @@ DRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, CARD64 target_sbc, +- /* +- * It's normal for the app to have exited with a swap outstanding, but +- * don't free the drawable until they're all complete. +- */ +- if (pPriv->swapsPending == 0 && pPriv->refCount == 0) +- DRI2FreeDrawable(pDraw); + } + + Bool +@@ -750,7 +798,7 @@ DRI2WaitMSC(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, + Bool ret; + + pPriv = DRI2GetDrawable(pDraw); +- if (pPriv == NULL || pPriv->refCount == 0) ++ if (pPriv == NULL) + return BadDrawable; + + /* Old DDX just completes immediately */ +@@ -774,7 +822,7 @@ DRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, CARD64 target_sbc, + DRI2DrawablePtr pPriv; + + pPriv = DRI2GetDrawable(pDraw); +- if (pPriv == NULL || pPriv->refCount == 0) ++ if (pPriv == NULL) + return BadDrawable; + + /* target_sbc == 0 means to block until all pending swaps are +@@ -800,36 +848,6 @@ DRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, CARD64 target_sbc, return Success; } @@ -416,25 +818,25 @@ index 48618e1..b8cbc52 100644 - xfree(pPriv->buffers); - } - -- /* If the window is destroyed while we have a swap pending, don't +- /* If the window is destroyed while we have a swap or wait pending, don't - * actually free the priv yet. We'll need it in the DRI2SwapComplete() - * callback and we'll free it there once we're done. */ -- if (!pPriv->swapsPending) +- if (!pPriv->swapsPending && !pPriv->blockedClient) - DRI2FreeDrawable(pDraw); -} - Bool - DRI2Connect(ScreenPtr pScreen, unsigned int driverType, int *fd, - const char **driverName, const char **deviceName) -@@ -834,6 +772,7 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) + DRI2HasSwapControl(ScreenPtr pScreen) + { +@@ -890,6 +908,7 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) if (!ds) return FALSE; + ds->screen = pScreen; ds->fd = info->fd; ds->deviceName = info->deviceName; - -@@ -897,6 +836,8 @@ DRI2Setup(pointer module, pointer opts, int *errmaj, int *errmin) + dri2_major = 1; +@@ -961,6 +980,8 @@ DRI2Setup(pointer module, pointer opts, int *errmaj, int *errmin) { static Bool setupDone = FALSE; @@ -443,8 +845,22 @@ index 48618e1..b8cbc52 100644 if (!setupDone) { setupDone = TRUE; +diff --git a/hw/xfree86/dri2/dri2.h b/hw/xfree86/dri2/dri2.h +index ce8a5df..5415a0b 100644 +--- a/hw/xfree86/dri2/dri2.h ++++ b/hw/xfree86/dri2/dri2.h +@@ -198,7 +198,8 @@ extern _X_EXPORT Bool DRI2Connect(ScreenPtr pScreen, + + extern _X_EXPORT Bool DRI2Authenticate(ScreenPtr pScreen, drm_magic_t magic); + +-extern _X_EXPORT int DRI2CreateDrawable(DrawablePtr pDraw); ++extern _X_EXPORT int DRI2CreateDrawable(ClientPtr client, ++ DrawablePtr pDraw, XID id); + + extern _X_EXPORT void DRI2DestroyDrawable(DrawablePtr pDraw); + diff --git a/hw/xfree86/dri2/dri2ext.c b/hw/xfree86/dri2/dri2ext.c -index bd92fd3..1ac4a5f 100644 +index 094d54d..58eaa10 100644 --- a/hw/xfree86/dri2/dri2ext.c +++ b/hw/xfree86/dri2/dri2ext.c @@ -51,7 +51,6 @@ @@ -455,7 +871,12 @@ index bd92fd3..1ac4a5f 100644 static Bool validDrawable(ClientPtr client, XID drawable, Mask access_mode, -@@ -172,11 +171,6 @@ ProcDRI2CreateDrawable(ClientPtr client) +@@ -168,15 +167,10 @@ ProcDRI2CreateDrawable(ClientPtr client) + &pDrawable, &status)) + return status; + +- status = DRI2CreateDrawable(pDrawable); ++ status = DRI2CreateDrawable(client, pDrawable, stuff->drawable); if (status != Success) return status; @@ -476,7 +897,7 @@ index bd92fd3..1ac4a5f 100644 return client->noClientException; } -@@ -620,25 +612,11 @@ SProcDRI2Dispatch (ClientPtr client) +@@ -627,25 +619,11 @@ SProcDRI2Dispatch (ClientPtr client) } } @@ -502,6 +923,21 @@ index bd92fd3..1ac4a5f 100644 dri2Extension = AddExtension(DRI2_NAME, DRI2NumberEvents, DRI2NumberErrors, +diff --git a/include/list.h b/include/list.h +index a126a65..89dc29d 100644 +--- a/include/list.h ++++ b/include/list.h +@@ -94,4 +94,10 @@ list_is_empty(struct list *head) + &pos->member != (head); \ + pos = __container_of(pos->member.next, pos, member)) + ++#define list_for_each_entry_safe(pos, next, head, member) \ ++ for (pos = __container_of((head)->next, pos, member), \ ++ next = __container_of(pos->member.next, pos, member); \ ++ &pos->member != (head); \ ++ pos = next, next = __container_of(next->member.next, next, member)) ++ + #endif -- -1.6.5.2 +1.7.0.1 diff --git a/xserver-1.8.0-swap-fixes.patch b/xserver-1.8.0-swap-fixes.patch new file mode 100644 index 0000000..41c5b57 --- /dev/null +++ b/xserver-1.8.0-swap-fixes.patch @@ -0,0 +1,710 @@ +From 93244eeb6bfa9666228c55bbebb3bd5dae42a275 Mon Sep 17 00:00:00 2001 +From: Jesse Barnes +Date: Thu, 4 Mar 2010 09:19:13 -0800 +Subject: [PATCH 1/2] Merge fixes for buffer swapping from master +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 165a4a9c7de0fcc6ef6a6421736b412ccb35965e +Author: Jesse Barnes +Date: Tue Mar 23 09:47:08 2010 -0700 + +GLX/DRI2: expose swap control extensions if DDX support is present + +Export DDX swap control status from the DRI2 module and check for it in +GLX when initializing extensions. + +Reviewed-by: Mario Kleiner +Signed-off-by: Jesse Barnes + +commit 5933b0abc6a76aaea84aa534df89900cd795c888 +Author: Jesse Barnes +Date: Mon Mar 8 15:10:47 2010 -0800 + +DRI2: prevent swap wakes from waking MSC waiters + +If a few swaps were queued leading to a throttle related block on the +client, and then the client submitted an MSC wait, one of the previous +swap wakeups could have caused the MSC wait to complete early. Add a +flag for this to prevent a swap wake from prematurely waking an MSC +waiter. + +Reported-by: Mario Kleiner +Reviewed-by: Mario Kleiner +Signed-off-by: Jesse Barnes + +commit b00d435ddf2e9817e33bfd5f7e9b905442dc23c7 +Author: Jesse Barnes +Date: Mon Mar 8 12:41:25 2010 -0800 + +DRI2: handle swapsPending better + +Avoid a potential swapsPending underflow by incrementing it before +ScheduleSwap, which may complete it immediately. And be sure to +decrement it again in case the schedule failed. + +Reported-by: Mario Kleiner +Reviewed-by: Mario Kleiner +Signed-off-by: Jesse Barnes + +commit 0294ff2a5cadddc8fcc77ba9a851f979f0b91fc3 +Author: Jesse Barnes +Date: Mon Mar 8 12:39:54 2010 -0800 + +DRI2: throttle swaps at submission time too + +We need to throttle swaps here in addition to when the context is made +current to avoid causing problems with clients that just swap. +Throttling here also ensures our swaps get ordered as long as we block +the client occasionally. + +Reported-by: Mario Kleiner +Reviewed-by: Mario Kleiner +Signed-off-by: Jesse Barnes + +commit db1c7cb604167baf49e61be4c09ccf7b592c4af3 +Author: Jesse Barnes +Date: Mon Mar 8 12:38:37 2010 -0800 + +DRI2: advertise lowest supported DRI2 protocol version + +Update our supported DRI2 protocol version as each driver does +DRI2ScreenInit, since depending on available kernel features, each DDX +may support different callbacks and therefore protocol. + +Reviewed-by: Mario Kleiner +Signed-off-by: Jesse Barnes + +commit 87ca6320f26eb3129e3c19056e1d8fa5c1784723 +Author: Jesse Barnes +Date: Fri Mar 5 09:49:03 2010 -0800 + +DRI2: handle swap_interval of 0 correctly + +A 0 swap interval means that swaps shouldn't be sync'd to vblank, so +just complete the swap immediately in that case. + +Reviewed-by: Mario Kleiner +Signed-off-by: Jesse Barnes + +commit 8476d99231cb725c090305d60f1c1c889d25c8dc +Author: Jesse Barnes +Date: Fri Mar 5 09:15:24 2010 -0800 + +DRI2: drawable lifetime fixes + +Handle drawable destruction and lifetime correctly. + +Check whether the drawable priv is valid in DRI2SwapInterval(), +DRI2WaitSBC() and DRI2WaitMSC(); it may have gone away, so be sure to +check it before using it. + +If more than 1 outstanding swap is queued, we may complete several after +an app has exited. If we free it after the first one completes and the +refcount reaches 0, we'll crash the server on subsequent completions. +So delay freeing until all swaps complete and remove the error message +as this is a normal occurence. To do this properly, we must also avoid +destroying drawables in DRI2DestroyDrawable() if a swap or wait event is +pending. + +And finally, make sure we free drawables in DRI2WaitMSCComplete() if +necessary (i.e. if the refcount has reached 0 and this MSC was the last +pending event on the object). + +Reported-by: Mario Kleiner +Reviewed-by: Mario Kleiner +Signed-off-by: Jesse Barnes + +commit b180e43977710b56ccfd6780f204ddcc952987a1 +Author: Jesse Barnes +Date: Thu Mar 4 10:31:59 2010 -0800 + +DRI2: fix swapbuffers handling of SBC and target MSC + +Returns expected SBC after completion of swap to caller, as required by +OML_sync_control spec, instead of the last_swap_target value. + +Passes target_msc, divisor, remainder, correctly for +glXSwapBuffersMscOML() call, while retaining old behaviour for simple +glXSwapBuffers() call. + +An OML swap can have a 0 target_msc, which just means it needs to +satisfy the divisor/remainder equation. Pass this down to the driver as +needed so we can support it. + +Signed-off-by: Jesse Barnes +Signed-off-by: Mario Kleiner + +commit 751e8c09d34df4b41e8d8384a3ec1bf5cb8ca028 +Author: Mario Kleiner +Date: Sun Feb 21 05:26:00 2010 +0100 + +DRI2WaitSbc(): Fixes for correct semantic of glXWaitForSbcOML() + +Added implementation for case target_sbc == 0. In that case, the +function shall schedule a wait until all pending swaps for the drawable +have completed. + +Fix for non-blocking case. Old implementation returned random, +uninitialized values for (ust,msc,sbc) if it returned immediately +without scheduling a wait due to sbc >= target_sbc. + +Now if function doesn't schedule a wait, but returns immediately, +it returns the (ust,msc,sbc) of the most recently completed swap, +i.e., the UST and MSC corresponding to the time when the returned +current SBC was reached. + +Signed-off-by: Mario Kleiner + +commit 0de4974b90b10fa6a447cdf980b4a114c6c9e5a8 +Author: Mario Kleiner +Date: Sun Feb 21 05:25:59 2010 +0100 + +DRI2: Fix glitches in DRI2SwapComplete() and DRI2WakeupClient() + +DRI2SwapComplete(): Increment pPriv->swap_count++; before calling +into callback for INTEL_swap_events extension, so the swap event +contains the current SBC after swap completion instead of the +previous one. + +DRI2WakeupClient: Check for pPriv->target_sbc <= pPriv->swap_count, +had wrong comparison pPriv->target_sbc >= pPriv->swap_count for +unblocking of clients of DRI2WaitSBC(). + +Signed-off-by: Mario Kleiner + +commit 4c8ec49826a46eb3b36c69d2ad3f82320c179c38 +Author: Jesse Barnes +Date: Thu Mar 4 09:54:15 2010 -0800 + +DRI2: make target_sbc signed + +We need to track invalid targets as well as 0 targets, so just make it +signed so our comparisons work like they should. + +Reviewed-by: Mario Kleiner +Reported-by: Kristian Høgsberg +Signed-off-by: Jesse Barnes + +commit c4d54816f2ee4883d8f9bcf4595474fb58c95146 +Author: Jesse Barnes +Date: Thu Mar 4 09:19:13 2010 -0800 + +DRI2: fixup handling of last_swap_target + +We need to initialize the swap target, which is passed to the driver to +schedule events. Rather than using -1 to indicate that the field is +uninitialized, just make sure we initialize it at drawable creation +time. + +Reviewed-by: Mario Kleiner +Signed-off-by: Jesse Barnes +--- + glx/glxdri2.c | 23 ++---- + hw/xfree86/dri2/dri2.c | 174 +++++++++++++++++++++++++++++-------------- + hw/xfree86/dri2/dri2.h | 6 ++ + hw/xfree86/dri2/dri2ext.c | 11 ++- + include/protocol-versions.h | 4 - + 5 files changed, 143 insertions(+), 75 deletions(-) + +diff --git a/glx/glxdri2.c b/glx/glxdri2.c +index edd29b0..e791bf6 100644 +--- a/glx/glxdri2.c ++++ b/glx/glxdri2.c +@@ -616,6 +616,7 @@ glxDRILeaveVT (int index, int flags) + static void + initializeExtensions(__GLXDRIscreen *screen) + { ++ ScreenPtr pScreen = screen->base.pScreen; + const __DRIextension **extensions; + int i; + +@@ -625,10 +626,17 @@ initializeExtensions(__GLXDRIscreen *screen) + "GLX_MESA_copy_sub_buffer"); + LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n"); + +- /* FIXME: only if DDX supports it */ + __glXEnableExtension(screen->glx_enable_bits, "GLX_INTEL_swap_event"); + LogMessage(X_INFO, "AIGLX: enabled GLX_INTEL_swap_event\n"); + ++ if (DRI2HasSwapControl(pScreen)) { ++ __glXEnableExtension(screen->glx_enable_bits, ++ "GLX_SGI_swap_control"); ++ __glXEnableExtension(screen->glx_enable_bits, ++ "GLX_MESA_swap_control"); ++ LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n"); ++ } ++ + for (i = 0; extensions[i]; i++) { + #ifdef __DRI_READ_DRAWABLE + if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) { +@@ -639,19 +647,6 @@ initializeExtensions(__GLXDRIscreen *screen) + } + #endif + +-#ifdef __DRI_SWAP_CONTROL +- if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) { +- screen->swapControl = +- (const __DRIswapControlExtension *) extensions[i]; +- __glXEnableExtension(screen->glx_enable_bits, +- "GLX_SGI_swap_control"); +- __glXEnableExtension(screen->glx_enable_bits, +- "GLX_MESA_swap_control"); +- +- LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n"); +- } +-#endif +- + #ifdef __DRI_TEX_BUFFER + if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) { + screen->texBuffer = +diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c +index 48618e1..2bdb733 100644 +--- a/hw/xfree86/dri2/dri2.c ++++ b/hw/xfree86/dri2/dri2.c +@@ -45,6 +45,9 @@ + + #include "xf86.h" + ++CARD8 dri2_major; /* version of DRI2 supported by DDX */ ++CARD8 dri2_minor; ++ + static int dri2ScreenPrivateKeyIndex; + static DevPrivateKey dri2ScreenPrivateKey = &dri2ScreenPrivateKeyIndex; + static int dri2WindowPrivateKeyIndex; +@@ -60,10 +63,13 @@ typedef struct _DRI2Drawable { + int bufferCount; + unsigned int swapsPending; + ClientPtr blockedClient; ++ Bool blockedOnMsc; + int swap_interval; + CARD64 swap_count; +- CARD64 target_sbc; /* -1 means no SBC wait outstanding */ ++ int64_t target_sbc; /* -1 means no SBC wait outstanding */ + CARD64 last_swap_target; /* most recently queued swap target */ ++ CARD64 last_swap_msc; /* msc at completion of most recent swap */ ++ CARD64 last_swap_ust; /* ust at completion of most recent swap */ + int swap_limit; /* for N-buffering */ + } DRI2DrawableRec, *DRI2DrawablePtr; + +@@ -116,9 +122,11 @@ DRI2GetDrawable(DrawablePtr pDraw) + int + DRI2CreateDrawable(DrawablePtr pDraw) + { ++ DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); + WindowPtr pWin; + PixmapPtr pPixmap; + DRI2DrawablePtr pPriv; ++ CARD64 ust; + + pPriv = DRI2GetDrawable(pDraw); + if (pPriv != NULL) +@@ -138,11 +146,17 @@ DRI2CreateDrawable(DrawablePtr pDraw) + pPriv->bufferCount = 0; + pPriv->swapsPending = 0; + pPriv->blockedClient = NULL; ++ pPriv->blockedOnMsc = FALSE; + pPriv->swap_count = 0; + pPriv->target_sbc = -1; + pPriv->swap_interval = 1; +- pPriv->last_swap_target = -1; ++ /* Initialize last swap target from DDX if possible */ ++ if (!ds->GetMSC || !(*ds->GetMSC)(pDraw, &ust, &pPriv->last_swap_target)) ++ pPriv->last_swap_target = 0; ++ + pPriv->swap_limit = 1; /* default to double buffering */ ++ pPriv->last_swap_msc = 0; ++ pPriv->last_swap_ust = 0; + + if (pDraw->type == DRAWABLE_WINDOW) + { +@@ -390,6 +404,15 @@ DRI2ThrottleClient(ClientPtr client, DrawablePtr pDraw) + return FALSE; + } + ++static void ++__DRI2BlockClient(ClientPtr client, DRI2DrawablePtr pPriv) ++{ ++ if (pPriv->blockedClient == NULL) { ++ IgnoreClient(client); ++ pPriv->blockedClient = client; ++ } ++} ++ + void + DRI2BlockClient(ClientPtr client, DrawablePtr pDraw) + { +@@ -399,10 +422,8 @@ DRI2BlockClient(ClientPtr client, DrawablePtr pDraw) + if (pPriv == NULL) + return; + +- if (pPriv->blockedClient == NULL) { +- IgnoreClient(client); +- pPriv->blockedClient = client; +- } ++ __DRI2BlockClient(client, pPriv); ++ pPriv->blockedOnMsc = TRUE; + } + + int +@@ -483,6 +504,11 @@ DRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw, int frame, + AttendClient(pPriv->blockedClient); + + pPriv->blockedClient = NULL; ++ pPriv->blockedOnMsc = FALSE; ++ ++ /* If there's still a swap pending, let DRI2SwapComplete free it */ ++ if (pPriv->refCount == 0 && pPriv->swapsPending == 0) ++ DRI2FreeDrawable(pDraw); + } + + static void +@@ -500,21 +526,26 @@ DRI2WakeClient(ClientPtr client, DrawablePtr pDraw, int frame, + } + + /* +- * Swap completed. Either wake up an SBC waiter or a client that was +- * blocked due to GLX activity during a swap. ++ * Swap completed. ++ * Wake the client iff: ++ * - it was waiting on SBC ++ * - was blocked due to GLX make current ++ * - was blocked due to swap throttling ++ * - is not blocked due to an MSC wait + */ + if (pPriv->target_sbc != -1 && +- pPriv->target_sbc >= pPriv->swap_count) { ++ pPriv->target_sbc <= pPriv->swap_count) { + ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec, + frame, pPriv->swap_count); + pPriv->target_sbc = -1; + + AttendClient(pPriv->blockedClient); + pPriv->blockedClient = NULL; +- } else if (pPriv->target_sbc == -1) { +- if (pPriv->blockedClient) ++ } else if (pPriv->target_sbc == -1 && !pPriv->blockedOnMsc) { ++ if (pPriv->blockedClient) { + AttendClient(pPriv->blockedClient); +- pPriv->blockedClient = NULL; ++ pPriv->blockedClient = NULL; ++ } + } + } + +@@ -534,21 +565,24 @@ DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame, + return; + } + +- if (pPriv->refCount == 0) { +- xf86DrvMsg(pScreen->myNum, X_ERROR, +- "[DRI2] %s: bad drawable refcount\n", __func__); +- DRI2FreeDrawable(pDraw); +- return; +- } ++ pPriv->swapsPending--; ++ pPriv->swap_count++; + + ust = ((CARD64)tv_sec * 1000000) + tv_usec; + if (swap_complete) + swap_complete(client, swap_data, type, ust, frame, pPriv->swap_count); + +- pPriv->swapsPending--; +- pPriv->swap_count++; ++ pPriv->last_swap_msc = frame; ++ pPriv->last_swap_ust = ust; + + DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec); ++ ++ /* ++ * It's normal for the app to have exited with a swap outstanding, but ++ * don't free the drawable until they're all complete. ++ */ ++ if (pPriv->swapsPending == 0 && pPriv->refCount == 0) ++ DRI2FreeDrawable(pDraw); + } + + Bool +@@ -563,7 +597,7 @@ DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable) + pPriv->blockedClient == NULL) { + ResetCurrentRequest(client); + client->sequence--; +- DRI2BlockClient(client, pDrawable); ++ __DRI2BlockClient(client, pPriv); + return TRUE; + } + +@@ -579,7 +613,6 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, + DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); + DRI2DrawablePtr pPriv; + DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL; +- CARD64 ust; + int ret, i; + + pPriv = DRI2GetDrawable(pDraw); +@@ -601,8 +634,8 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, + return BadDrawable; + } + +- /* Old DDX, just blit */ +- if (!ds->ScheduleSwap) { ++ /* Old DDX or no swap interval, just blit */ ++ if (!ds->ScheduleSwap || !pPriv->swap_interval) { + BoxRec box; + RegionRec region; + +@@ -623,52 +656,52 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, + /* + * In the simple glXSwapBuffers case, all params will be 0, and we just + * need to schedule a swap for the last swap target + the swap interval. +- * If the last swap target hasn't been set yet, call into the driver +- * to get the current count. + */ +- if (target_msc == 0 && divisor == 0 && remainder == 0 && +- pPriv->last_swap_target < 0) { +- ret = (*ds->GetMSC)(pDraw, &ust, &target_msc); +- if (!ret) { +- xf86DrvMsg(pScreen->myNum, X_ERROR, +- "[DRI2] %s: driver failed to return current MSC\n", +- __func__); +- return BadDrawable; +- } ++ if (target_msc == 0 && divisor == 0 && remainder == 0) { ++ /* ++ * Swap target for this swap is last swap target + swap interval since ++ * we have to account for the current swap count, interval, and the ++ * number of pending swaps. ++ */ ++ *swap_target = pPriv->last_swap_target + pPriv->swap_interval; ++ } else { ++ /* glXSwapBuffersMscOML could have a 0 target_msc, honor it */ ++ *swap_target = target_msc; + } + +- /* First swap needs to initialize last_swap_target */ +- if (pPriv->last_swap_target < 0) +- pPriv->last_swap_target = target_msc; +- +- /* +- * Swap target for this swap is last swap target + swap interval since +- * we have to account for the current swap count, interval, and the +- * number of pending swaps. +- */ +- *swap_target = pPriv->last_swap_target + pPriv->swap_interval; +- ++ pPriv->swapsPending++; + ret = (*ds->ScheduleSwap)(client, pDraw, pDestBuffer, pSrcBuffer, + swap_target, divisor, remainder, func, data); + if (!ret) { ++ pPriv->swapsPending--; /* didn't schedule */ + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[DRI2] %s: driver failed to schedule swap\n", __func__); + return BadDrawable; + } + +- pPriv->swapsPending++; + pPriv->last_swap_target = *swap_target; + ++ /* According to spec, return expected swapbuffers count SBC after this swap ++ * will complete. ++ */ ++ *swap_target = pPriv->swap_count + pPriv->swapsPending; ++ + return Success; + } + + void + DRI2SwapInterval(DrawablePtr pDrawable, int interval) + { ++ ScreenPtr pScreen = pDrawable->pScreen; + DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable); + +- /* fixme: check against arbitrary max? */ ++ if (pPriv == NULL) { ++ xf86DrvMsg(pScreen->myNum, X_ERROR, ++ "[DRI2] %s: bad drawable\n", __func__); ++ return; ++ } + ++ /* fixme: check against arbitrary max? */ + pPriv->swap_interval = interval; + } + +@@ -717,7 +750,7 @@ DRI2WaitMSC(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, + Bool ret; + + pPriv = DRI2GetDrawable(pDraw); +- if (pPriv == NULL) ++ if (pPriv == NULL || pPriv->refCount == 0) + return BadDrawable; + + /* Old DDX just completes immediately */ +@@ -741,14 +774,28 @@ DRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, CARD64 target_sbc, + DRI2DrawablePtr pPriv; + + pPriv = DRI2GetDrawable(pDraw); +- if (pPriv == NULL) ++ if (pPriv == NULL || pPriv->refCount == 0) + return BadDrawable; + +- if (pPriv->swap_count >= target_sbc) +- return Success; ++ /* target_sbc == 0 means to block until all pending swaps are ++ * finished. Recalculate target_sbc to get that behaviour. ++ */ ++ if (target_sbc == 0) ++ target_sbc = pPriv->swap_count + pPriv->swapsPending; ++ ++ /* If current swap count already >= target_sbc, ++ * return immediately with (ust, msc, sbc) triplet of ++ * most recent completed swap. ++ */ ++ if (pPriv->swap_count >= target_sbc) { ++ *sbc = pPriv->swap_count; ++ *msc = pPriv->last_swap_msc; ++ *ust = pPriv->last_swap_ust; ++ return Success; ++ } + + pPriv->target_sbc = target_sbc; +- DRI2BlockClient(client, pDraw); ++ __DRI2BlockClient(client, pPriv); + + return Success; + } +@@ -776,14 +823,22 @@ DRI2DestroyDrawable(DrawablePtr pDraw) + xfree(pPriv->buffers); + } + +- /* If the window is destroyed while we have a swap pending, don't ++ /* If the window is destroyed while we have a swap or wait pending, don't + * actually free the priv yet. We'll need it in the DRI2SwapComplete() + * callback and we'll free it there once we're done. */ +- if (!pPriv->swapsPending) ++ if (!pPriv->swapsPending && !pPriv->blockedClient) + DRI2FreeDrawable(pDraw); + } + + Bool ++DRI2HasSwapControl(ScreenPtr pScreen) ++{ ++ DRI2ScreenPtr ds = DRI2GetScreen(pScreen); ++ ++ return (ds->ScheduleSwap && ds->GetMSC); ++} ++ ++Bool + DRI2Connect(ScreenPtr pScreen, unsigned int driverType, int *fd, + const char **driverName, const char **deviceName) + { +@@ -820,6 +875,7 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) + "VDPAU", /* DRI2DriverVDPAU */ + }; + unsigned int i; ++ CARD8 cur_minor; + + if (info->version < 3) + return FALSE; +@@ -836,6 +892,7 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) + + ds->fd = info->fd; + ds->deviceName = info->deviceName; ++ dri2_major = 1; + + ds->CreateBuffer = info->CreateBuffer; + ds->DestroyBuffer = info->DestroyBuffer; +@@ -845,8 +902,15 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) + ds->ScheduleSwap = info->ScheduleSwap; + ds->ScheduleWaitMSC = info->ScheduleWaitMSC; + ds->GetMSC = info->GetMSC; ++ cur_minor = 2; ++ } else { ++ cur_minor = 1; + } + ++ /* Initialize minor if needed and set to minimum provied by DDX */ ++ if (!dri2_minor || dri2_minor > cur_minor) ++ dri2_minor = cur_minor; ++ + if (info->version == 3 || info->numDrivers == 0) { + /* Driver too old: use the old-style driverName field */ + ds->numDrivers = 1; +diff --git a/hw/xfree86/dri2/dri2.h b/hw/xfree86/dri2/dri2.h +index 1c8626b..ce8a5df 100644 +--- a/hw/xfree86/dri2/dri2.h ++++ b/hw/xfree86/dri2/dri2.h +@@ -46,6 +46,9 @@ typedef struct { + void *driverPrivate; + } DRI2BufferRec, *DRI2BufferPtr; + ++extern CARD8 dri2_major; /* version of DRI2 supported by DDX */ ++extern CARD8 dri2_minor; ++ + typedef DRI2BufferRec DRI2Buffer2Rec, *DRI2Buffer2Ptr; + typedef void (*DRI2SwapEventPtr)(ClientPtr client, void *data, int type, + CARD64 ust, CARD64 msc, CARD64 sbc); +@@ -185,6 +188,8 @@ extern _X_EXPORT Bool DRI2ScreenInit(ScreenPtr pScreen, + + extern _X_EXPORT void DRI2CloseScreen(ScreenPtr pScreen); + ++extern _X_EXPORT Bool DRI2HasSwapControl(ScreenPtr pScreen); ++ + extern _X_EXPORT Bool DRI2Connect(ScreenPtr pScreen, + unsigned int driverType, + int *fd, +@@ -254,6 +259,7 @@ extern _X_EXPORT Bool DRI2CanFlip(DrawablePtr pDraw); + + extern _X_EXPORT Bool DRI2CanExchange(DrawablePtr pDraw); + ++/* Note: use *only* for MSC related waits */ + extern _X_EXPORT void DRI2BlockClient(ClientPtr client, DrawablePtr pDraw); + + extern _X_EXPORT void DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, +diff --git a/hw/xfree86/dri2/dri2ext.c b/hw/xfree86/dri2/dri2ext.c +index bd92fd3..094d54d 100644 +--- a/hw/xfree86/dri2/dri2ext.c ++++ b/hw/xfree86/dri2/dri2ext.c +@@ -80,8 +80,8 @@ ProcDRI2QueryVersion(ClientPtr client) + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; +- rep.majorVersion = SERVER_DRI2_MAJOR_VERSION; +- rep.minorVersion = SERVER_DRI2_MINOR_VERSION; ++ rep.majorVersion = dri2_major; ++ rep.minorVersion = dri2_minor; + + if (client->swapped) { + swaps(&rep.sequenceNumber, n); +@@ -384,6 +384,13 @@ ProcDRI2SwapBuffers(ClientPtr client) + DixReadAccess | DixWriteAccess, &pDrawable, &status)) + return status; + ++ /* ++ * Ensures an out of control client can't exhaust our swap queue, and ++ * also orders swaps. ++ */ ++ if (DRI2ThrottleClient(client, pDrawable)) ++ return client->noClientException; ++ + target_msc = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi); + divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi); + remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi); +diff --git a/include/protocol-versions.h b/include/protocol-versions.h +index c74b7fa..97ef5da 100644 +--- a/include/protocol-versions.h ++++ b/include/protocol-versions.h +@@ -51,10 +51,6 @@ + #define SERVER_DMX_MINOR_VERSION 2 + #define SERVER_DMX_PATCH_VERSION 20040604 + +-/* DRI2 */ +-#define SERVER_DRI2_MAJOR_VERSION 1 +-#define SERVER_DRI2_MINOR_VERSION 2 +- + /* Generic event extension */ + #define SERVER_GE_MAJOR_VERSION 1 + #define SERVER_GE_MINOR_VERSION 0 +-- +1.7.0.1 +