[PATCH 2/6] exa: increase/rework safety checks in Prepare/FinishAccess.
Maarten Maathuis
madman2003 at gmail.com
Tue Mar 3 13:29:11 PST 2009
---
exa/exa.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++--------
exa/exa.h | 5 +++
exa/exa_priv.h | 4 ++
3 files changed, 92 insertions(+), 15 deletions(-)
diff --git a/exa/exa.c b/exa/exa.c
index f4fba57..6e8a18d 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -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);
+ /* 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;
+ }
if (ret == TRUE)
- return ret;
+ goto out;
}
- return pExaScr->SavedModifyPixmapHeader(pPixmap, width, height, depth,
+ 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;
}
/**
@@ -523,16 +536,53 @@ exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp)
Bool
ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
{
- ScreenPtr pScreen = pDrawable->pScreen;
- ExaScreenPriv (pScreen);
- PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
- Bool offscreen = exaPixmapIsOffscreen(pPixmap);
+ ScreenPtr pScreen = pDrawable->pScreen;
+ ExaScreenPriv (pScreen);
+ PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
+ ExaPixmapPriv(pPixmap);
+ Bool offscreen;
+
+ if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
+ return FALSE;
+
+ if (pExaPixmap == NULL) {
+#ifdef DEBUG
+ FatalError("EXA bug: ExaDoPrepareAccess was called on a non-exa pixmap.\n");
+#else
+ ErrorF("EXA bug: ExaDoPrepareAccess was called on a non-exa pixmap.\n");
+ return FALSE;
+#endif
+ }
- /* Unhide pixmap pointer */
- if (pPixmap->devPrivate.ptr == NULL && !(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) {
- pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
+ /* 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) {
+ ErrorF("EXA bug: pPixmap->devPrivate.ptr was %p, but should have been NULL.\n",
+ pPixmap->devPrivate.ptr);
+#ifdef DEBUG
+ assert(pPixmap->devPrivate.ptr == NULL);
+#endif
+ }
}
+ 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 +598,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,11 +653,30 @@ 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)) {
- pPixmap->devPrivate.ptr = NULL;
+ if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
+ return;
+
+ if (pExaPixmap == NULL) {
+#ifdef DEBUG
+ FatalError("EXA bug: exaFinishAccesss was called on a non-exa pixmap.\n");
+#else
+ ErrorF("EXA bug: exaFinishAccess was called on a non-exa pixmap.\n");
+ return;
+#endif
}
+ /* Avoid mismatching indices. */
+ if (pExaScr->prepare_access[index] != pPixmap)
+ ErrorF("EXA bug: Calling FinishAccess on pixmap %p with index %d while "
+ "it should have been %p.\n", pPixmap, index, pExaScr->prepare_access[index]);
+#ifdef DEBUG
+ assert(pExaScr->prepare_access[index] == pPixmap);
+#endif
+ pExaScr->prepare_access[index] = NULL;
+
+ /* We always hide the devPrivate.ptr. */
+ pPixmap->devPrivate.ptr = NULL;
+
if (pExaScr->info->FinishAccess == NULL)
return;
diff --git a/exa/exa.h b/exa/exa.h
index 8339a3e..d7219f0 100644
--- a/exa/exa.h
+++ b/exa/exa.h
@@ -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);
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index a037eb0..ce2cf48 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -158,6 +158,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;
--
1.6.1.3
More information about the xorg-devel
mailing list