EXA bug: Calling FinishAccess on pixmap 0xaf06d008 with index 1 while it should have been (nil).
Michel Dänzer
michel at daenzer.net
Mon Jul 20 03:00:56 PDT 2009
[ Please quote what you're referring to ]
On Sun, 2009-07-19 at 12:25 +0200, Maarten Maathuis wrote:
> That would suggest creating a GC that completely bypasses exa.
I'm not sure that would really be a problem, but anyway it turns out
this doesn't work because GetScratchGC() may return a pre-allocated GC.
> The proper solution seems like adding more indices or at least
> detecting that the indices are being used.
The patch below fixes the problem by reference counting
Prepare/FinishAccess.
commit 27786a280eb7c6b852e376affb6daf4d9cca4b9e
Author: Michel Dänzer <daenzer at vmware.com>
Date: Mon Jul 20 11:57:38 2009 +0200
EXA: Make Prepare/FinishAccess tracking resilient to repeated / nested calls.
Use reference counting and do nothing unless the reference count transitions
to/from 0.
Fixes https://bugs.freedesktop.org/show_bug.cgi?id=22822 .
As a bonus, this avoids calling the driver Prepare/FinishAccess hooks more than
once per pixmap and operation.
diff --git a/exa/exa.c b/exa/exa.c
index 8d488b3..daa4a7a 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -554,6 +554,7 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
ExaPixmapPriv(pPixmap);
Bool offscreen;
+ int i;
if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
return FALSE;
@@ -561,19 +562,25 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
if (pExaPixmap == NULL)
EXA_FatalErrorDebugWithRet(("EXA bug: ExaDoPrepareAccess was called on a non-exa pixmap.\n"), FALSE);
- /* Check if we're dealing SRC == DST or similar.
- * In that case the first PrepareAccess has already set pPixmap->devPrivate.ptr.
- */
- if (pPixmap->devPrivate.ptr != NULL) {
- int i;
- for (i = 0; i < 6; i++)
- if (pExaScr->prepare_access[i] == pPixmap)
+ /* Handle repeated / nested calls. */
+ for (i = 0; i < EXA_NUM_PREPARE_INDICES; i++) {
+ if (pExaScr->access[i].pixmap == pPixmap) {
+ pExaScr->access[i].count++;
+ return TRUE;
+ }
+ }
+
+ /* If slot for this index is taken, find an empty slot */
+ if (pExaScr->access[index].pixmap) {
+ for (index = EXA_NUM_PREPARE_INDICES - 1; index >= 0; index--)
+ if (!pExaScr->access[index].pixmap)
break;
+ }
- /* No known PrepareAccess or double prepare on the same index. */
- if (i == 6 || i == index)
- EXA_FatalErrorDebug(("EXA bug: pPixmap->devPrivate.ptr was %p, but should have been NULL.\n",
- pPixmap->devPrivate.ptr));
+ /* Access to this pixmap hasn't been prepared yet, so data pointer should be NULL. */
+ if (pPixmap->devPrivate.ptr != NULL) {
+ EXA_FatalErrorDebug(("EXA bug: pPixmap->devPrivate.ptr was %p, but should have been NULL.\n",
+ pPixmap->devPrivate.ptr));
}
offscreen = exaPixmapIsOffscreen(pPixmap);
@@ -583,8 +590,9 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
else
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
- /* Store so we can check SRC and DEST being the same. */
- pExaScr->prepare_access[index] = pPixmap;
+ /* Store so we can handle repeated / nested calls. */
+ pExaScr->access[index].pixmap = pPixmap;
+ pExaScr->access[index].count = 1;
if (!offscreen)
return FALSE;
@@ -662,6 +670,7 @@ exaFinishAccess(DrawablePtr pDrawable, int index)
ExaScreenPriv (pScreen);
PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
ExaPixmapPriv (pPixmap);
+ int i;
if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
return;
@@ -669,11 +678,22 @@ exaFinishAccess(DrawablePtr pDrawable, int index)
if (pExaPixmap == NULL)
EXA_FatalErrorDebugWithRet(("EXA bug: exaFinishAccesss was called on a non-exa pixmap.\n"),);
- /* Avoid mismatching indices. */
- if (pExaScr->prepare_access[index] != pPixmap)
- EXA_FatalErrorDebug(("EXA bug: Calling FinishAccess on pixmap %p with index %d while "
- "it should have been %p.\n", pPixmap, index, pExaScr->prepare_access[index]));
- pExaScr->prepare_access[index] = NULL;
+ /* Handle repeated / nested calls. */
+ for (i = 0; i < EXA_NUM_PREPARE_INDICES; i++) {
+ if (pExaScr->access[i].pixmap == pPixmap) {
+ if (--pExaScr->access[i].count > 0)
+ return;
+ index = i;
+ break;
+ }
+ }
+
+ /* Catch unbalanced Prepare/FinishAccess calls. */
+ if (i == EXA_NUM_PREPARE_INDICES)
+ EXA_FatalErrorDebug(("EXA bug: FinishAccess called without PrepareAccess for pixmap 0x%p.\n",
+ pPixmap));
+
+ pExaScr->access[index].pixmap = NULL;
/* We always hide the devPrivate.ptr. */
pPixmap->devPrivate.ptr = NULL;
@@ -768,15 +788,7 @@ exaCreatePixmapWithPrepare(ScreenPtr pScreen, int w, int h, int depth,
* For EXA_HANDLES_PIXMAPS the driver will handle whatever is needed.
* We want to signal that the pixmaps will be used as destination.
*/
- if (pExaScr->prepare_access[EXA_PREPARE_DEST] == NULL) {
- ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_DEST);
- pExaScr->prepare_access[EXA_PREPARE_DEST] = pPixmap;
- } else if (pExaScr->prepare_access[EXA_PREPARE_AUX_DEST] == NULL) {
- ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
- pExaScr->prepare_access[EXA_PREPARE_AUX_DEST] = pPixmap;
- } else {
- FatalError("exaCreatePixmapWithPrepare can only accomodate two pixmaps, we're at three.\n");
- }
+ ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
return pPixmap;
}
@@ -786,12 +798,9 @@ exaDestroyPixmapWithFinish(PixmapPtr pPixmap)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
- int i;
Bool ret;
- for (i = 0; i < 6; i++)
- if (pExaScr->prepare_access[i] == pPixmap)
- exaFinishAccess(&pPixmap->drawable, i);
+ exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
/* This swaps between this function and the real upper layer function.
* Normally this would swap to the fb layer pointer, this is a very special case.
@@ -853,8 +862,8 @@ exaValidateGC(GCPtr pGC,
(*pGC->funcs->ValidateGC)(pGC, changes, pDrawable);
- if (pExaScr->prepare_access[EXA_PREPARE_SRC]) /* tile */
- exaFinishAccess(&pExaScr->prepare_access[EXA_PREPARE_SRC]->drawable, EXA_PREPARE_SRC);
+ if (pTile)
+ exaFinishAccess(&pTile->drawable, EXA_PREPARE_SRC);
if (pGC->stipple)
exaFinishAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK);
@@ -868,13 +877,6 @@ exaValidateGC(GCPtr pGC,
/* restore copy of fb layer pointer. */
pExaScr->SavedDestroyPixmap = old_ptr2;
- if (pExaScr->prepare_access[EXA_PREPARE_DEST])
- exaFinishAccess(&pExaScr->prepare_access[EXA_PREPARE_DEST]->drawable,
- EXA_PREPARE_DEST);
- if (pExaScr->prepare_access[EXA_PREPARE_AUX_DEST])
- exaFinishAccess(&pExaScr->prepare_access[EXA_PREPARE_AUX_DEST]->drawable,
- EXA_PREPARE_AUX_DEST);
-
EXA_GC_EPILOGUE(pGC);
}
@@ -984,10 +986,10 @@ exaChangeWindowAttributes(WindowPtr pWin, unsigned long mask)
ret = pScreen->ChangeWindowAttributes(pWin, mask);
swap(pExaScr, pScreen, ChangeWindowAttributes);
- if (pExaScr->prepare_access[EXA_PREPARE_SRC]) /* background */
- exaFinishAccess(&pExaScr->prepare_access[EXA_PREPARE_SRC]->drawable, EXA_PREPARE_SRC);
- if (pExaScr->prepare_access[EXA_PREPARE_MASK]) /* border */
- exaFinishAccess(&pExaScr->prepare_access[EXA_PREPARE_MASK]->drawable, EXA_PREPARE_MASK);
+ if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap)
+ exaFinishAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC);
+ if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE)
+ exaFinishAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK);
/* switch back to the normal upper layer. */
unwrap(pExaScr, pScreen, CreatePixmap);
@@ -999,13 +1001,6 @@ exaChangeWindowAttributes(WindowPtr pWin, unsigned long mask)
/* restore copy of fb layer pointer. */
pExaScr->SavedDestroyPixmap = old_ptr2;
- if (pExaScr->prepare_access[EXA_PREPARE_DEST])
- exaFinishAccess(&pExaScr->prepare_access[EXA_PREPARE_DEST]->drawable,
- EXA_PREPARE_DEST);
- if (pExaScr->prepare_access[EXA_PREPARE_AUX_DEST])
- exaFinishAccess(&pExaScr->prepare_access[EXA_PREPARE_AUX_DEST]->drawable,
- EXA_PREPARE_AUX_DEST);
-
return ret;
}
diff --git a/exa/exa.h b/exa/exa.h
index 0701ec9..9dea57c 100644
--- a/exa/exa.h
+++ b/exa/exa.h
@@ -663,6 +663,7 @@ typedef struct _ExaDriver {
#define EXA_PREPARE_AUX_DEST 3
#define EXA_PREPARE_AUX_SRC 4
#define EXA_PREPARE_AUX_MASK 5
+ #define EXA_NUM_PREPARE_INDICES 6
/** @} */
/**
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index b3df1a5..f67a9cb 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -176,8 +176,11 @@ typedef struct {
CARD32 lastDefragment;
CARD32 nextDefragment;
- /* Store all accessed pixmaps, so we can check for duplicates. */
- PixmapPtr prepare_access[6];
+ /* Reference counting for accessed pixmaps */
+ struct {
+ PixmapPtr pixmap;
+ int count;
+ } access[EXA_NUM_PREPARE_INDICES];
/* Holds information on fallbacks that cannot be relayed otherwise. */
unsigned int fallback_flags;
--
Earthling Michel Dänzer | http://www.vmware.com
Libre software enthusiast | Debian, X and DRI developer
More information about the xorg
mailing list