Clients can terminate with pending SwapBuffers requests waiting for the trigger, potentially a long way in the future. Track these requests so we don't end up delivering SwapBuffersComplete to an entirely unrelated client.
Signed-off-by: Christopher James Halse Rogers <[email protected]> --- hw/xfree86/dri2/dri2.c | 54 +++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 51 insertions(+), 3 deletions(-) diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c index 6da2e17..37648bd 100644 --- a/hw/xfree86/dri2/dri2.c +++ b/hw/xfree86/dri2/dri2.c @@ -60,6 +60,9 @@ static DevPrivateKeyRec dri2WindowPrivateKeyRec; static DevPrivateKeyRec dri2PixmapPrivateKeyRec; #define dri2PixmapPrivateKey (&dri2PixmapPrivateKeyRec) +static DevPrivateKeyRec dri2ClientPrivateKeyRec; +#define dri2ClientPrivateKey (&dri2ClientPrivateKeyRec) + static RESTYPE dri2DrawableRes; typedef struct _DRI2Screen *DRI2ScreenPtr; @@ -111,8 +114,16 @@ typedef struct _DRI2SwapCompleteDataRec { DRI2BufferPtr src; DRI2BufferPtr dest; void * data; + Bool clientGone; + struct list link; } DRI2SwapCompleteDataRec, *DRI2SwapCompleteDataPtr; +static struct list * +DRI2GetClientEventList(ClientPtr client) +{ + return dixLookupPrivate(&client->devPrivates, dri2ClientPrivateKey); +} + static DRI2ScreenPtr DRI2GetScreen(ScreenPtr pScreen) { @@ -739,6 +750,7 @@ DRI2WakeClient(ClientPtr client, DrawablePtr pDraw, int frame, static void free_swap_complete_data (DrawablePtr pDraw, DRI2SwapCompleteDataPtr pSwapData) { + list_del(&pSwapData->link); buffer_unref(pDraw, pSwapData->src); buffer_unref(pDraw, pSwapData->dest); free(pSwapData); @@ -776,15 +788,16 @@ DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame, DRI2BufferFrontLeft); ust = ((CARD64)tv_sec * 1000000) + tv_usec; - if (swap_complete) + if (swap_complete && !pSwapData->clientGone) swap_complete(client, pSwapData->data, type, ust, frame, pPriv->swap_count); pPriv->last_swap_msc = frame; pPriv->last_swap_ust = ust; - DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec); - + if (!pSwapData->clientGone) + DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec); + free_swap_complete_data(pDraw, pSwapData); } @@ -817,6 +830,7 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, DRI2DrawablePtr pPriv; DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL; DRI2SwapCompleteDataPtr pSwapData; + struct list * clientEvents = DRI2GetClientEventList(client); int ret, i; CARD64 ust, current_msc; @@ -855,6 +869,8 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, pSwapData->src = pSrcBuffer; pSwapData->dest = pDestBuffer; pSwapData->data = data; + pSwapData->clientGone = FALSE; + list_add (&pSwapData->link, clientEvents); /* Old DDX or no swap interval, just blit */ if (!ds->ScheduleSwap || !pPriv->swap_interval) { @@ -1137,6 +1153,9 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) if (!dixRegisterPrivateKey(&dri2PixmapPrivateKeyRec, PRIVATE_PIXMAP, 0)) return FALSE; + if (!dixRegisterPrivateKey(&dri2ClientPrivateKeyRec, PRIVATE_CLIENT, sizeof (struct list))) + return FALSE; + ds = calloc(1, sizeof *ds); if (!ds) return FALSE; @@ -1226,6 +1245,34 @@ DRI2CloseScreen(ScreenPtr pScreen) dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, NULL); } +static void +DRI2ClientCallback(CallbackListPtr *ClientStateCallback, pointer closure, pointer calldata) +{ + NewClientInfoRec *clientinfo = calldata; + ClientPtr pClient = clientinfo->client; + struct list *clientEvents = DRI2GetClientEventList(pClient); + DRI2SwapCompleteDataPtr ref, next; + + switch (pClient->clientState) { + case ClientStateInitial: + list_init(clientEvents); + break; + case ClientStateRunning: + break; + case ClientStateRetained: + case ClientStateGone: + if (clientEvents) { + list_for_each_entry_safe(ref, next, clientEvents, link) { + ref->clientGone = TRUE; + list_del(&ref->link); + } + } + break; + default: + break; + } +} + extern ExtensionModule dri2ExtensionModule; static pointer @@ -1238,6 +1285,7 @@ DRI2Setup(pointer module, pointer opts, int *errmaj, int *errmin) if (!setupDone) { setupDone = TRUE; + AddCallback(&ClientStateCallback, DRI2ClientCallback, NULL); LoadExtension(&dri2ExtensionModule, FALSE); } else -- 1.7.2.3 _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel
