From: Christopher James Halse Rogers <[email protected]>
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]> Signed-off-by: Pauli Nieminen <[email protected]> --- hw/xfree86/dri2/dri2.c | 56 +++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 53 insertions(+), 3 deletions(-) diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c index 5868fb4..9133bb3 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) + RESTYPE dri2DrawableRes; typedef struct _DRI2Screen *DRI2ScreenPtr; @@ -113,8 +116,15 @@ typedef struct _DRI2SwapCompleteDataRec { DRI2BufferPtr dest; ClientPtr client; void * data; + struct list link; } DRI2SwapCompleteDataRec, *DRI2SwapCompleteDataPtr; +static struct list * +DRI2GetClientEventList(ClientPtr client) +{ + return dixLookupPrivate(&client->devPrivates, dri2ClientPrivateKey); +} + static DRI2ScreenPtr DRI2GetScreen(ScreenPtr pScreen) { @@ -806,6 +816,7 @@ DRI2WakeClient(ClientPtr client, DRI2DrawablePtr pPriv, int frame, static void free_swap_complete_data (DRI2DrawablePtr pPriv, DRI2SwapCompleteDataPtr pSwapData) { + list_del(&pSwapData->link); buffer_unref(pPriv, pSwapData->src); buffer_unref(pPriv, pSwapData->dest); free(pSwapData); @@ -825,6 +836,11 @@ DRI2SwapComplete2(DRI2DrawablePtr pPriv, int frame, pPriv->swap_count++; pPriv->refcnt--; + ust = ((CARD64)tv_sec * 1000000) + tv_usec; + + if (client == NULL) + goto out; + if (pDraw) { BoxRec box; RegionRec region; @@ -838,16 +854,16 @@ DRI2SwapComplete2(DRI2DrawablePtr pPriv, int frame, DRI2BufferFrontLeft); } - ust = ((CARD64)tv_sec * 1000000) + tv_usec; if (swap_complete) swap_complete(client, pSwapData->data, type, ust, frame, pPriv->swap_count); + DRI2WakeClient(client, pPriv, frame, tv_sec, tv_usec); + +out: pPriv->last_swap_msc = frame; pPriv->last_swap_ust = ust; - DRI2WakeClient(client, pPriv, frame, tv_sec, tv_usec); - free_swap_complete_data(pPriv, pSwapData); if (pPriv->refcnt <= 0) @@ -881,6 +897,7 @@ DRI2SwapBuffers(ClientPtr client, DRI2DrawablePtr pPriv, CARD64 target_msc, DRI2ScreenPtr ds = pPriv->dri2_screen; DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL; DRI2SwapCompleteDataPtr pSwapData; + struct list * clientEvents = DRI2GetClientEventList(client); int ret, i; CARD64 ust, current_msc; @@ -919,6 +936,7 @@ DRI2SwapBuffers(ClientPtr client, DRI2DrawablePtr pPriv, CARD64 target_msc, pSwapData->dest = pDestBuffer; pSwapData->client = client; pSwapData->data = data; + list_add (&pSwapData->link, clientEvents); /* Old DDX or no swap interval, just blit */ if (!ds->ScheduleSwap || !pPriv->swap_interval) { @@ -1191,6 +1209,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; @@ -1289,6 +1310,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->client = NULL; + list_del(&ref->link); + } + } + break; + default: + break; + } +} + extern ExtensionModule dri2ExtensionModule; static pointer @@ -1301,6 +1350,7 @@ DRI2Setup(pointer module, pointer opts, int *errmaj, int *errmin) if (!setupDone) { setupDone = TRUE; + AddCallback(&ClientStateCallback, DRI2ClientCallback, NULL); LoadExtension(&dri2ExtensionModule, FALSE); } else -- 1.7.0.4 _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel
