summaryrefslogtreecommitdiff
path: root/hw/kdrive
diff options
context:
space:
mode:
authorEric Anholt <anholt@freebsd.org>2006-03-31 19:41:28 +0000
committerEric Anholt <anholt@freebsd.org>2006-03-31 19:41:28 +0000
commit2e38fedd29e7e55d01e3edce6a73b8ceaac17911 (patch)
tree3f6b1c560c62ff862cf6b07cc898804968159528 /hw/kdrive
parentf480dc797b51f080f912efc7867d6d8e50be074c (diff)
Add an option to EXA for the DDX to request that EXA hide the pixmap's
devPrivate.ptr when pointing at offscreen memory, outside of exaPrepare/FinishAccess(). This was used with fakexa to find (by NULL dereference) many instances of un-Prepared CPU access to the framebuffer: - GC tiles used in several ops when fillStyle == FillTiled were never Prepared. - Migration could lead to un-Prepared access to mask data in render's Trapezoids and Triangles - PutImage's UploadToScreen failure fallback failed to Prepare.
Diffstat (limited to 'hw/kdrive')
-rw-r--r--hw/kdrive/ephyr/ephyr.h3
-rw-r--r--hw/kdrive/ephyr/ephyr_draw.c95
2 files changed, 93 insertions, 5 deletions
diff --git a/hw/kdrive/ephyr/ephyr.h b/hw/kdrive/ephyr/ephyr.h
index 3d468afd9..707cb0168 100644
--- a/hw/kdrive/ephyr/ephyr.h
+++ b/hw/kdrive/ephyr/ephyr.h
@@ -55,7 +55,8 @@ typedef struct _ephyrFakexaPriv {
*/
int op;
PicturePtr pSrcPicture, pMaskPicture, pDstPicture;
- PixmapPtr pSrc, pDst;
+ void *saved_ptrs[3];
+ PixmapPtr pDst, pSrc, pMask;
GCPtr pGC;
} EphyrFakexaPriv;
diff --git a/hw/kdrive/ephyr/ephyr_draw.c b/hw/kdrive/ephyr/ephyr_draw.c
index f4bb2a1b0..b155c6f6e 100644
--- a/hw/kdrive/ephyr/ephyr_draw.c
+++ b/hw/kdrive/ephyr/ephyr_draw.c
@@ -28,6 +28,7 @@
#ifdef HAVE_CONFIG_H
#include <kdrive-config.h>
#endif
+#undef NDEBUG /* No, really. The whole point of this module is to crash. */
#include "ephyr.h"
#include "exa_priv.h"
@@ -49,6 +50,44 @@
#define EPHYR_OFFSCREEN_BASE (1 * 1024 * 1024)
/**
+ * Forces a real devPrivate.ptr for hidden pixmaps, so that we can call down to
+ * fb functions.
+ */
+static void
+ephyrPreparePipelinedAccess(PixmapPtr pPix, int index)
+{
+ KdScreenPriv(pPix->drawable.pScreen);
+ KdScreenInfo *screen = pScreenPriv->screen;
+ EphyrScrPriv *scrpriv = screen->driver;
+ EphyrFakexaPriv *fakexa = scrpriv->fakexa;
+
+ assert(fakexa->saved_ptrs[index] == NULL);
+ fakexa->saved_ptrs[index] = pPix->devPrivate.ptr;
+
+ if (pPix->devPrivate.ptr != NULL)
+ return;
+
+ pPix->devPrivate.ptr = fakexa->exa->memoryBase + exaGetPixmapOffset(pPix);
+}
+
+/**
+ * Restores the original devPrivate.ptr of the pixmap from before we messed with
+ * it.
+ */
+static void
+ephyrFinishPipelinedAccess(PixmapPtr pPix, int index)
+{
+ KdScreenPriv(pPix->drawable.pScreen);
+ KdScreenInfo *screen = pScreenPriv->screen;
+ EphyrScrPriv *scrpriv = screen->driver;
+ EphyrFakexaPriv *fakexa = scrpriv->fakexa;
+ void *offscreen_begin, *offscreen_end;
+
+ pPix->devPrivate.ptr = fakexa->saved_ptrs[index];
+ fakexa->saved_ptrs[index] = NULL;
+}
+
+/**
* Sets up a scratch GC for fbFill, and saves other parameters for the
* ephyrSolid implementation.
*/
@@ -62,6 +101,8 @@ ephyrPrepareSolid(PixmapPtr pPix, int alu, Pixel pm, Pixel fg)
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
CARD32 tmpval[3];
+ ephyrPreparePipelinedAccess(pPix, EXA_PREPARE_DEST);
+
fakexa->pDst = pPix;
fakexa->pGC = GetScratchGC(pPix->drawable.depth, pScreen);
@@ -106,6 +147,8 @@ ephyrDoneSolid(PixmapPtr pPix)
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
FreeScratchGC(fakexa->pGC);
+
+ ephyrFinishPipelinedAccess(pPix, EXA_PREPARE_DEST);
}
/**
@@ -123,6 +166,9 @@ ephyrPrepareCopy(PixmapPtr pSrc, PixmapPtr pDst, int dx, int dy, int alu,
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
CARD32 tmpval[2];
+ ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
+ ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
+
fakexa->pSrc = pSrc;
fakexa->pDst = pDst;
fakexa->pGC = GetScratchGC(pDst->drawable.depth, pScreen);
@@ -167,6 +213,9 @@ ephyrDoneCopy(PixmapPtr pDst)
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
FreeScratchGC (fakexa->pGC);
+
+ ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC);
+ ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST);
}
/**
@@ -194,10 +243,18 @@ ephyrPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
EphyrScrPriv *scrpriv = screen->driver;
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
+ ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
+ ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
+ if (pMask != NULL)
+ ephyrPreparePipelinedAccess(pMask, EXA_PREPARE_MASK);
+
fakexa->op = op;
fakexa->pSrcPicture = pSrcPicture;
fakexa->pMaskPicture = pMaskPicture;
fakexa->pDstPicture = pDstPicture;
+ fakexa->pSrc = pSrc;
+ fakexa->pMask = pMask;
+ fakexa->pDst = pDst;
TRACE_DRAW();
@@ -224,6 +281,15 @@ ephyrComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY,
static void
ephyrDoneComposite(PixmapPtr pDst)
{
+ KdScreenPriv(pDst->drawable.pScreen);
+ KdScreenInfo *screen = pScreenPriv->screen;
+ EphyrScrPriv *scrpriv = screen->driver;
+ EphyrFakexaPriv *fakexa = scrpriv->fakexa;
+
+ if (fakexa->pMask != NULL)
+ ephyrFinishPipelinedAccess(fakexa->pMask, EXA_PREPARE_MASK);
+ ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC);
+ ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST);
}
/**
@@ -243,6 +309,8 @@ ephyrDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h, char *dst,
if (pSrc->drawable.bitsPerPixel < 8)
return FALSE;
+ ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
+
cpp = pSrc->drawable.bitsPerPixel / 8;
src_pitch = exaGetPixmapPitch(pSrc);
src = fakexa->exa->memoryBase + exaGetPixmapOffset(pSrc);
@@ -256,6 +324,8 @@ ephyrDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h, char *dst,
exaMarkSync(pSrc->drawable.pScreen);
+ ephyrFinishPipelinedAccess(pSrc, EXA_PREPARE_SRC);
+
return TRUE;
}
@@ -276,11 +346,13 @@ ephyrUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, char *src,
if (pDst->drawable.bitsPerPixel < 8)
return FALSE;
+ ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
+
cpp = pDst->drawable.bitsPerPixel / 8;
dst_pitch = exaGetPixmapPitch(pDst);
dst = fakexa->exa->memoryBase + exaGetPixmapOffset(pDst);
dst += y * dst_pitch + x * cpp;
-
+ ErrorF("uts %d,%d, %dx%d, %dbpp %p/%x\n", x, y, w, h, pDst->drawable.bitsPerPixel, dst, dst_pitch);
for (; h > 0; h--) {
memcpy(dst, src, w * cpp);
dst += dst_pitch;
@@ -289,14 +361,26 @@ ephyrUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, char *src,
exaMarkSync(pDst->drawable.pScreen);
+ ephyrFinishPipelinedAccess(pDst, EXA_PREPARE_DEST);
+
+ return TRUE;
+}
+
+static Bool
+ephyrPrepareAccess(PixmapPtr pPix, int index)
+{
+ /* Make sure we don't somehow end up with a pointer that is in framebuffer
+ * and hasn't been readied for us.
+ */
+ assert(pPix->devPrivate.ptr != NULL);
+
return TRUE;
}
/**
* In fakexa, we currently only track whether we have synced to the latest
- * "accelerated" drawing that has happened or not. This will be used by an
- * ephyrPrepareAccess for the purpose of reliably providing garbage when
- * reading/writing when we haven't synced.
+ * "accelerated" drawing that has happened or not. It's not used for anything
+ * yet.
*/
static int
ephyrMarkSync(ScreenPtr pScreen)
@@ -382,6 +466,8 @@ ephyrDrawInit(ScreenPtr pScreen)
fakexa->exa->MarkSync = ephyrMarkSync;
fakexa->exa->WaitMarker = ephyrWaitMarker;
+ fakexa->exa->PrepareAccess = ephyrPrepareAccess;
+
fakexa->exa->pixmapOffsetAlign = EPHYR_OFFSET_ALIGN;
fakexa->exa->pixmapPitchAlign = EPHYR_PITCH_ALIGN;
@@ -429,4 +515,5 @@ exaDDXDriverInit(ScreenPtr pScreen)
ExaScreenPriv(pScreen);
pExaScr->migration = ExaMigrationAlways;
+ pExaScr->hideOffscreenPixmapData = TRUE;
}