summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPauli Nieminen <ext-pauli.nieminen@nokia.com>2011-02-01 21:35:24 +0200
committerPauli Nieminen <ext-pauli.nieminen@nokia.com>2011-02-04 17:32:56 +0200
commit21bff5348601ba10d9a69e6879f0b7dbc902b89f (patch)
treefd646faf9523b846745bdbd64c2bf24429490675
parentf0f9dda84e7e9fd0fe59bdc0c2eaa75204df077e (diff)
dri2: Add reference counting to DRI2
Asynchronous request like SwapBuffers can still reference Drawable after the Drawable has been freed. DRI2Drawable cleanup should be delayed until all asynchronous operations have completed. Reference counted DRI2Drawable helps to keep DRI2Drawable around until all request on it has completed. Signed-off-by: Pauli Nieminen <ext-pauli.nieminen@nokia.com>
-rw-r--r--hw/xfree86/dri2/dri2.c32
1 files changed, 30 insertions, 2 deletions
diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c
index f97f60ea0..9f262aeef 100644
--- a/hw/xfree86/dri2/dri2.c
+++ b/hw/xfree86/dri2/dri2.c
@@ -83,6 +83,7 @@ typedef struct _DRI2Drawable {
CARD64 last_swap_ust; /* ust at completion of most recent swap */
int swap_limit; /* for N-buffering */
unsigned long serialNumber;
+ unsigned refcnt;
} DRI2DrawableRec;
typedef struct _DRI2Screen {
@@ -190,12 +191,14 @@ DRI2AllocateDrawable(DrawablePtr pDraw)
pPriv->last_swap_ust = 0;
list_init(&pPriv->reference_list);
pPriv->serialNumber = DRI2DrawableSerial(pDraw);
+ pPriv->refcnt = 0;
if (pDraw->type == DRAWABLE_WINDOW) {
pWin = (WindowPtr) pDraw;
dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, pPriv);
} else {
pPixmap = (PixmapPtr) pDraw;
+ pPixmap->refcnt++;
dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, pPriv);
}
@@ -251,6 +254,8 @@ DRI2AddDrawableRef(DRI2DrawablePtr pPriv, XID id, XID dri2_id,
if (!AddResource(id, dri2DrawableRes, pPriv))
return BadAlloc;
+ pPriv->refcnt++;
+
ref->id = id;
ref->dri2_id = dri2_id;
ref->invalidate = invalidate;
@@ -309,6 +314,7 @@ static int DRI2DrawableGone(pointer p, XID id)
list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) {
if (ref->dri2_id == id) {
+ pPriv->refcnt--;
list_del(&ref->link);
/* If this was the last ref under this X drawable XID,
* unregister the X drawable resource. */
@@ -319,13 +325,15 @@ static int DRI2DrawableGone(pointer p, XID id)
}
if (ref->id == id) {
+ pPriv->refcnt--;
list_del(&ref->link);
FreeResourceByType(ref->dri2_id, dri2DrawableRes, TRUE);
free(ref);
}
}
- if (!list_is_empty(&pPriv->reference_list))
+
+ if (pPriv->refcnt > 0)
return Success;
pDraw = pPriv->drawable;
@@ -336,6 +344,7 @@ static int DRI2DrawableGone(pointer p, XID id)
} else {
pPixmap = (PixmapPtr) pDraw;
dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, NULL);
+ pDraw->pScreen->DestroyPixmap(pPixmap);
}
if (pPriv->buffers != NULL) {
@@ -696,6 +705,13 @@ DRI2WaitMSCComplete(int client_index, DRI2DrawablePtr pPriv, int frame,
{
ClientPtr client = clients[client_index];
+ pPriv->refcnt--;
+
+ if (pPriv->refcnt == 0) {
+ DRI2DrawableGone(pPriv, 0);
+ return;
+ }
+
ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec,
frame, pPriv->swap_count);
@@ -753,7 +769,12 @@ DRI2SwapComplete(int client_index, DRI2DrawablePtr pPriv, int frame,
pPriv->swapsPending--;
pPriv->swap_count++;
+ pPriv->refcnt--;
+ if (pPriv->refcnt == 0) {
+ DRI2DrawableGone(pPriv, 0);
+ return;
+ }
if (pDraw) {
BoxRec box;
@@ -837,6 +858,7 @@ DRI2SwapBuffers(ClientPtr client, DRI2DrawablePtr pPriv, CARD64 target_msc,
RegionInit(&region, &box, 0);
pPriv->swapsPending++;
+ pPriv->refcnt++;
(*ds->CopyRegion)(pDraw, &region, pDestBuffer, pSrcBuffer);
DRI2SwapComplete(client->index, pPriv, target_msc, 0, 0, DRI2_BLIT_COMPLETE,
@@ -878,10 +900,12 @@ DRI2SwapBuffers(ClientPtr client, DRI2DrawablePtr pPriv, CARD64 target_msc,
}
pPriv->swapsPending++;
+ pPriv->refcnt++;
ret = (*ds->ScheduleSwap)(client, pDraw, pDestBuffer, pSrcBuffer,
swap_target, divisor, remainder, func, data);
if (!ret) {
pPriv->swapsPending--; /* didn't schedule */
+ pPriv->refcnt--;
xf86DrvMsg(pScreen->myNum, X_ERROR,
"[DRI2] %s: driver failed to schedule swap\n", __func__);
return BadDrawable;
@@ -952,6 +976,8 @@ DRI2WaitMSC(ClientPtr client, DRI2DrawablePtr pPriv, CARD64 target_msc,
if (pDraw == NULL)
return BadDrawable;
+ pPriv->refcnt++;
+
/* Old DDX just completes immediately */
if (!ds->ScheduleWaitMSC) {
DRI2WaitMSCComplete(client->index, pPriv, target_msc, 0, 0);
@@ -960,8 +986,10 @@ DRI2WaitMSC(ClientPtr client, DRI2DrawablePtr pPriv, CARD64 target_msc,
}
ret = (*ds->ScheduleWaitMSC)(client, pDraw, target_msc, divisor, remainder);
- if (!ret)
+ if (!ret) {
+ pPriv->refcnt--;
return BadDrawable;
+ }
return Success;
}