exa: increase/rework safety checks in Prepare/FinishAccess.

This commit is contained in:
Maarten Maathuis 2009-02-28 21:59:09 +01:00
parent 3ea3d505e8
commit da8ea41a54
3 changed files with 86 additions and 16 deletions

View File

@ -450,15 +450,28 @@ exaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth,
}
}
if (pExaScr->info->ModifyPixmapHeader) {
ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
bitsPerPixel, devKind, pPixData);
if (ret == TRUE)
return ret;
/* For EXA_HANDLES_PIXMAPS, we set pPixData to NULL.
* If pPixmap->devPrivate.ptr is non-NULL, then we've got a non-offscreen pixmap.
* We need to store the pointer, because PrepareAccess won't be called.
*/
if (!pPixData && pPixmap->devPrivate.ptr && pPixmap->devKind) {
pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
pExaPixmap->sys_pitch = pPixmap->devKind;
}
return pExaScr->SavedModifyPixmapHeader(pPixmap, width, height, depth,
if (ret == TRUE)
goto out;
}
ret = pExaScr->SavedModifyPixmapHeader(pPixmap, width, height, depth,
bitsPerPixel, devKind, pPixData);
out:
/* Always NULL this, we don't want lingering pointers. */
pPixmap->devPrivate.ptr = NULL;
return ret;
}
/**
@ -526,13 +539,40 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
ScreenPtr pScreen = pDrawable->pScreen;
ExaScreenPriv (pScreen);
PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
Bool offscreen = exaPixmapIsOffscreen(pPixmap);
ExaPixmapPriv(pPixmap);
Bool offscreen;
/* Unhide pixmap pointer */
if (pPixmap->devPrivate.ptr == NULL && !(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) {
pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
return FALSE;
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)
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));
}
offscreen = exaPixmapIsOffscreen(pPixmap);
if (offscreen)
pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
else
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
/* Store so we can check SRC and DEST being the same. */
pExaScr->prepare_access[index] = pPixmap;
if (!offscreen)
return FALSE;
@ -548,9 +588,8 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
}
if (!(*pExaScr->info->PrepareAccess) (pPixmap, index)) {
ExaPixmapPriv (pPixmap);
if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
FatalError("Driver failed PrepareAccess on a pinned pixmap\n");
FatalError("Driver failed PrepareAccess on a pinned pixmap.\n");
exaMoveOutPixmap (pPixmap);
return FALSE;
@ -604,10 +643,20 @@ exaFinishAccess(DrawablePtr pDrawable, int index)
PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
ExaPixmapPriv (pPixmap);
/* Rehide pixmap pointer if we're doing that. */
if (pExaPixmap && !(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) {
if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
return;
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;
/* We always hide the devPrivate.ptr. */
pPixmap->devPrivate.ptr = NULL;
}
if (pExaScr->info->FinishAccess == NULL)
return;

View File

@ -695,6 +695,11 @@ typedef struct _ExaDriver {
/* Hooks to allow driver to its own pixmap memory management */
void *(*CreatePixmap)(ScreenPtr pScreen, int size, int align);
void (*DestroyPixmap)(ScreenPtr pScreen, void *driverPriv);
/**
* Returning a pixmap with non-NULL devPrivate.ptr implies a pixmap which is
* not offscreen, which will never be accelerated and Prepare/FinishAccess won't
* be called.
*/
Bool (*ModifyPixmapHeader)(PixmapPtr pPixmap, int width, int height,
int depth, int bitsPerPixel, int devKind,
pointer pPixData);

View File

@ -85,6 +85,18 @@ exaDrawableLocation(DrawablePtr pDrawable);
#define EXA_MAX_FB FB_OVERLAY_MAX
#endif
#ifdef DEBUG
#define EXA_FatalErrorDebug(x) FatalError x
#define EXA_FatalErrorDebugWithRet(x, ret) FatalError x
#else
#define EXA_FatalErrorDebug(x) ErrorF x
#define EXA_FatalErrorDebugWithRet(x, ret) \
do { \
ErrorF x; \
return ret; \
} while (0)
#endif
/**
* This is the list of migration heuristics supported by EXA. See
* exaDoMigration() for what their implementations do.
@ -158,6 +170,10 @@ typedef struct {
unsigned disableFbCount;
Bool optimize_migration;
unsigned offScreenCounter;
/* Store all accessed pixmaps, so we can check for duplicates. */
PixmapPtr prepare_access[6];
/* Holds information on fallbacks that cannot be relayed otherwise. */
unsigned int fallback_flags;