[PATCH v3 04/11] dri2: Add reference counting to DRI2

Pauli ext-pauli.nieminen at nokia.com
Wed Feb 16 02:21:38 PST 2011


From: Pauli Nieminen <ext-pauli.nieminen at nokia.com>

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.

v2:
* Make reference count signed and warn about underflow

Signed-off-by: Pauli Nieminen <ext-pauli.nieminen at nokia.com>
---
 hw/xfree86/dri2/dri2.c |   37 +++++++++++++++++++++++++++++++++++--
 1 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c
index 8b166d5..b628a40 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;
+    int		 	 refcnt;
 } DRI2DrawableRec;
 
 typedef struct _DRI2Screen {
@@ -195,12 +196,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);
     }
 
@@ -256,6 +259,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;
@@ -314,6 +319,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. */
@@ -324,15 +330,22 @@ 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;
 
+    if (pPriv->refcnt < 0)
+	xf86DrvMsg(pPriv->dri2_screen->screen->myNum, X_ERROR,
+		   "[DRI2] %s: DRI2Drawable reference count underflow (%d)\n",
+		   __func__, pPriv->refcnt);
+
     pDraw = pPriv->drawable;
 
     if (pDraw->type == DRAWABLE_WINDOW) {
@@ -341,6 +354,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) {
@@ -702,6 +716,13 @@ DRI2WaitMSCComplete2(DRI2DrawablePtr pPriv, int frame,
 {
     ClientPtr client = data;
 
+    pPriv->refcnt--;
+
+    if (pPriv->refcnt <= 0) {
+	DRI2DrawableGone(pPriv, 0);
+	return;
+    }
+
     ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec,
 			 frame, pPriv->swap_count);
 
@@ -760,7 +781,12 @@ DRI2SwapComplete2(DRI2DrawablePtr pPriv, int frame,
 
     pPriv->swapsPending--;
     pPriv->swap_count++;
+    pPriv->refcnt--;
 
+    if (pPriv->refcnt <= 0) {
+	DRI2DrawableGone(pPriv, 0);
+	return;
+    }
 
     if (pDraw) {
 	BoxRec          box;
@@ -855,6 +881,7 @@ DRI2SwapBuffers(ClientPtr client, DRI2DrawablePtr pPriv, CARD64 target_msc,
 	RegionInit(&region, &box, 0);
 
 	pPriv->swapsPending++;
+	pPriv->refcnt++;
 
 	(*ds->CopyRegion)(pDraw, &region, pDestBuffer, pSrcBuffer);
 	DRI2SwapComplete2(pPriv, target_msc, 0, 0, DRI2_BLIT_COMPLETE,
@@ -896,10 +923,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--;
 	free(pSwapData);
         xf86DrvMsg(pScreen->myNum, X_ERROR,
 		   "[DRI2] %s: driver failed to schedule swap\n", __func__);
@@ -971,6 +1000,8 @@ DRI2WaitMSC(ClientPtr client, DRI2DrawablePtr pPriv, CARD64 target_msc,
     if (pDraw == NULL)
 	return BadDrawable;
 
+    pPriv->refcnt++;
+
     /* Old DDX just completes immediately */
     if (!ds->ScheduleWaitMSC) {
 	DRI2WaitMSCComplete2(pPriv, target_msc, 0, 0, client);
@@ -979,8 +1010,10 @@ DRI2WaitMSC(ClientPtr client, DRI2DrawablePtr pPriv, CARD64 target_msc,
     }
 
     ret = (*ds->ScheduleWaitMSC)(client, pDraw, target_msc, divisor, remainder, client);
-    if (!ret)
+    if (!ret) {
+	pPriv->refcnt--;
 	return BadDrawable;
+    }
 
     return Success;
 }
-- 
1.7.0.4



More information about the xorg-devel mailing list