From 3ff8ba50a6a173bfb6d42dc7e2fd5da4e8706db8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Thu, 29 Apr 2010 16:36:10 -0400 Subject: [PATCH] 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. --- glx/glxcmds.c | 23 ++++++---- glx/glxdri.c | 8 ++- glx/glxdri2.c | 12 +++-- glx/glxdriswrast.c | 8 ++- glx/glxscreens.c | 12 +---- glx/glxscreens.h | 6 ++- hw/xfree86/dri2/dri2.c | 104 ++++++++++++++++++++++++++++++++++++++++---- hw/xfree86/dri2/dri2.h | 3 +- hw/xfree86/dri2/dri2ext.c | 2 +- include/list.h | 6 +++ 10 files changed, 140 insertions(+), 44 deletions(-) diff --git a/glx/glxcmds.c b/glx/glxcmds.c index 087d52e..31a7d32 100644 --- a/glx/glxcmds.c +++ b/glx/glxcmds.c @@ -512,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 */ @@ -1104,15 +1105,17 @@ __glXDrawableRelease(__GLXdrawable *drawable) } static int -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; if (pGlxScreen->pScreen != pDraw->pScreen) return BadMatch; - pGlxDraw = pGlxScreen->createDrawable(pGlxScreen, pDraw, type, + pGlxDraw = pGlxScreen->createDrawable(client, pGlxScreen, pDraw, + drawableId, type, glxDrawableId, config); if (pGlxDraw == NULL) return BadAlloc; @@ -1153,7 +1156,7 @@ 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); return err; @@ -1268,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; } @@ -1316,7 +1319,8 @@ DoCreatePbuffer(ClientPtr client, int screenNum, XID fbconfigId, return BadAlloc; return DoCreateGLXDrawable(client, pGlxScreen, config, &pPixmap->drawable, - glxDrawableId, GLX_DRAWABLE_PBUFFER); + glxDrawableId, glxDrawableId, + GLX_DRAWABLE_PBUFFER); } int __glXDisp_CreatePbuffer(__GLXclientState *cl, GLbyte *pc) @@ -1439,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 9810a73..1d8c902 100644 --- a/glx/glxdri.c +++ b/glx/glxdri.c @@ -683,10 +683,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; @@ -700,7 +702,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 74d6ebc..40825c8 100644 --- a/glx/glxdri2.c +++ b/glx/glxdri2.c @@ -430,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; @@ -446,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; } @@ -457,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; } @@ -717,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 918383c..4ba448a 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/glxscreens.c b/glx/glxscreens.c index b75aea6..da11834 100644 --- a/glx/glxscreens.c +++ b/glx/glxscreens.c @@ -399,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 d52099f..861e03c 100644 --- a/glx/glxscreens.h +++ b/glx/glxscreens.h @@ -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); diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c index 6c4dabc..178116a 100644 --- a/hw/xfree86/dri2/dri2.c +++ b/hw/xfree86/dri2/dri2.c @@ -37,6 +37,7 @@ #include #include #include "xf86Module.h" +#include "list.h" #include "scrnintstr.h" #include "windowstr.h" #include "dixstruct.h" @@ -56,6 +57,8 @@ typedef struct _DRI2Screen *DRI2ScreenPtr; typedef struct _DRI2Drawable { DRI2ScreenPtr dri2_screen; + DrawablePtr drawable; + struct list reference_list; int width; int height; DRI2BufferPtr *buffers; @@ -74,6 +77,7 @@ typedef struct _DRI2Drawable { typedef struct _DRI2Screen { ScreenPtr screen; + int refcnt; unsigned int numDrivers; const char **driverNames; const char *deviceName; @@ -110,24 +114,19 @@ DRI2GetDrawable(DrawablePtr pDraw) return pPriv; } -int -DRI2CreateDrawable(DrawablePtr pDraw) +static DRI2DrawablePtr +DRI2AllocateDrawable(DrawablePtr pDraw) { DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); DRI2DrawablePtr pPriv; CARD64 ust; - int rc; - - 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 NULL; pPriv->dri2_screen = ds; + pPriv->drawable = pDraw; pPriv->width = pDraw->width; pPriv->height = pDraw->height; pPriv->buffers = NULL; @@ -145,9 +144,71 @@ 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); + + return pPriv; +} + +typedef struct DRI2DrawableRefRec { + XID id; + XID dri2_id; + struct list link; +} DRI2DrawableRefRec, *DRI2DrawableRefPtr; - if (!AddResource(pDraw->id, dri2DrawableRes, pPriv)) +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; +} + +int +DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id) +{ + DRI2DrawablePtr pPriv; + XID dri2_id; + int rc; + + pPriv = DRI2GetDrawable(pDraw); + if (pPriv == NULL) + pPriv = DRI2AllocateDrawable(pDraw); + if (pPriv == NULL) + return BadAlloc; + + dri2_id = FakeClientID(client->index); + rc = DRI2AddDrawableRef(pPriv, id, dri2_id); + if (rc != Success) + return rc; return Success; } @@ -156,9 +217,32 @@ 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); + } + } + + 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++) 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 17df130..58eaa10 100644 --- a/hw/xfree86/dri2/dri2ext.c +++ b/hw/xfree86/dri2/dri2ext.c @@ -167,7 +167,7 @@ ProcDRI2CreateDrawable(ClientPtr client) &pDrawable, &status)) return status; - status = DRI2CreateDrawable(pDrawable); + status = DRI2CreateDrawable(client, pDrawable, stuff->drawable); if (status != Success) return status; 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.7.0.1