[PATCH 1/2] EXA: Extend mixed pixmaps scheme to allow driver PrepareAccess hook to fail.

Michel Dänzer michel at daenzer.net
Wed Sep 23 03:13:47 PDT 2009


From: Michel Dänzer <daenzer at vmware.com>

If the PrepareAccess hook fails, use the DownloadFromScreen hook to retrieve
driver pixmap contents to a system RAM copy, perform software rendering on that
and copy the results back using the UploadToScreen hook. Use the classic
migration logic to minimize transfers (which as a bonus allows slightly
cleaning up some of the existing mixed pixmap code).

This enables things that weren't possible before with driver-allocated pixmap
storage: If some (or all) GPU pixmap storage can't be mapped directly by the
CPU, this can be handled between the PrepareAccess and
DownloadFrom/UploadToScreen hooks, e.g.:

* Radeon KMS on big endian machines can fail PrepareAccess if the pixmap
  requires byte-swapping and swap bytes in DownloadFrom/UploadToScreen.
* Environments where GPU and CPU don't have a shared address space at all.
  Here the driver PrepareAccess hook will always fail and leave all transfers
  between GPU / CPU storage to the Download/From/UploadToScreen hooks.

Drivers which can handle all pixmaps in the PrepareAccess hook should notice
little if any difference.
---
 exa/exa.c                   |   78 +++++++------------
 exa/exa_migration_classic.c |   30 ++++++-
 exa/exa_migration_mixed.c   |  179 +++++++++++++++++++++++--------------------
 exa/exa_mixed.c             |   87 +++++++++-------------
 exa/exa_priv.h              |   22 +++++-
 exa/exa_unaccel.c           |   52 +++++++-----
 6 files changed, 232 insertions(+), 216 deletions(-)

diff --git a/exa/exa.c b/exa/exa.c
index 483e3b4..e264d44 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -286,11 +286,10 @@ exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp)
  * Returns TRUE if pixmap can be accessed offscreen.
  */
 Bool
-ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
+ExaDoPrepareAccess(PixmapPtr pPixmap, int index)
 {
-    ScreenPtr pScreen = pDrawable->pScreen;
+    ScreenPtr pScreen = pPixmap->drawable.pScreen;
     ExaScreenPriv (pScreen);
-    PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
     ExaPixmapPriv(pPixmap);
     Bool offscreen;
     int i;
@@ -324,7 +323,7 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
 
     offscreen = exaPixmapIsOffscreen(pPixmap);
 
-    if (offscreen)
+    if (offscreen && pExaPixmap->fb_ptr)
 	pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
     else
 	pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
@@ -333,20 +332,10 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
     pExaScr->access[index].pixmap = pPixmap;
     pExaScr->access[index].count = 1;
 
-    if (!offscreen) {
-	/* Do we need to allocate our system buffer? */
-	if ((pExaScr->info->flags & EXA_HANDLES_PIXMAPS) && (pExaScr->info->flags & EXA_MIXED_PIXMAPS)) {
-	    if (!pExaPixmap->sys_ptr && !exaPixmapIsPinned(pPixmap)) {
-		pExaPixmap->sys_ptr = malloc(pExaPixmap->sys_pitch * pDrawable->height);
-		if (!pExaPixmap->sys_ptr)
-		    FatalError("EXA: malloc failed for size %d bytes\n", pExaPixmap->sys_pitch * pDrawable->height);
-		pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
-	    }
-	}
+    if (!offscreen)
 	return FALSE;
-    }
 
-    exaWaitSync (pDrawable->pScreen);
+    exaWaitSync (pScreen);
 
     if (pExaScr->info->PrepareAccess == NULL)
 	return TRUE;
@@ -360,7 +349,8 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
     }
 
     if (!(*pExaScr->info->PrepareAccess) (pPixmap, index)) {
-	if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
+	if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED &&
+	    !(pExaScr->info->flags & EXA_MIXED_PIXMAPS))
 	    FatalError("Driver failed PrepareAccess on a pinned pixmap.\n");
 	exaMoveOutPixmap (pPixmap);
 
@@ -370,31 +360,6 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
     return TRUE;
 }
 
-void
-exaPrepareAccessReg(DrawablePtr pDrawable, int index, RegionPtr pReg)
-{
-    PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
-    ExaScreenPriv(pPixmap->drawable.pScreen);
-
-    if (pExaScr->do_migration) {
-	ExaMigrationRec pixmaps[1];
-
-	if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
-	    pixmaps[0].as_dst = TRUE;
-	    pixmaps[0].as_src = FALSE;
-	} else {
-	    pixmaps[0].as_dst = FALSE;
-	    pixmaps[0].as_src = TRUE;
-	}
-	pixmaps[0].pPix = pPixmap;
-	pixmaps[0].pReg = pReg;
-
-	exaDoMigration(pixmaps, 1, FALSE);
-    }
-
-    ExaDoPrepareAccess(pDrawable, index);
-}
-
 /**
  * exaPrepareAccess() is EXA's wrapper for the driver's PrepareAccess() handler.
  *
@@ -404,7 +369,13 @@ exaPrepareAccessReg(DrawablePtr pDrawable, int index, RegionPtr pReg)
 void
 exaPrepareAccess(DrawablePtr pDrawable, int index)
 {
-    exaPrepareAccessReg(pDrawable, index, NULL);
+    PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
+    ExaScreenPriv(pDrawable->pScreen);
+
+    if (pExaScr->prepare_access_reg)
+	pExaScr->prepare_access_reg(pPixmap, index, NULL);
+    else
+	(void)ExaDoPrepareAccess(pPixmap, index);
 }
 
 /**
@@ -432,7 +403,6 @@ exaFinishAccess(DrawablePtr pDrawable, int index)
 	if (pExaScr->access[i].pixmap == pPixmap) {
 	    if (--pExaScr->access[i].count > 0)
 		return;
-	    index = i;
 	    break;
 	}
     }
@@ -442,25 +412,25 @@ exaFinishAccess(DrawablePtr pDrawable, int index)
 	EXA_FatalErrorDebug(("EXA bug: FinishAccess called without PrepareAccess for pixmap 0x%p.\n",
 			     pPixmap));
 
-    pExaScr->access[index].pixmap = NULL;
+    pExaScr->access[i].pixmap = NULL;
 
     /* We always hide the devPrivate.ptr. */
     pPixmap->devPrivate.ptr = NULL;
 
-    if (pExaScr->info->FinishAccess == NULL)
-	return;
+    if (pExaScr->finish_access)
+	pExaScr->finish_access(pPixmap, index);
 
-    if (!exaPixmapIsOffscreen (pPixmap))
+    if (!pExaScr->info->FinishAccess || !exaPixmapIsOffscreen(pPixmap))
 	return;
 
-    if (index >= EXA_PREPARE_AUX_DEST &&
+    if (i >= EXA_PREPARE_AUX_DEST &&
 	!(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) {
 	ErrorF("EXA bug: Trying to call driver FinishAccess hook with "
 	       "unsupported index EXA_PREPARE_AUX*\n");
 	return;
     }
 
-    (*pExaScr->info->FinishAccess) (pPixmap, index);
+    (*pExaScr->info->FinishAccess) (pPixmap, i);
 }
 
 /**
@@ -537,7 +507,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.
      */
-    ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
+    ExaDoPrepareAccess(pPixmap, EXA_PREPARE_AUX_DEST);
 
     return pPixmap;
 }
@@ -1071,6 +1041,8 @@ exaDriverInit (ScreenPtr		pScreen,
 		pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_mixed;
 		pExaScr->do_move_in_pixmap = exaMoveInPixmap_mixed;
 		pExaScr->do_move_out_pixmap = NULL;
+		pExaScr->prepare_access_reg = exaPrepareAccessReg_mixed;
+		pExaScr->finish_access = exaFinishAccess_mixed;
 	    } else {
 		wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_driver);
 		wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_driver);
@@ -1079,6 +1051,8 @@ exaDriverInit (ScreenPtr		pScreen,
 		pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_driver;
 		pExaScr->do_move_in_pixmap = NULL;
 		pExaScr->do_move_out_pixmap = NULL;
+		pExaScr->prepare_access_reg = NULL;
+		pExaScr->finish_access = NULL;
 	    }
 	} else {
 	    wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_classic);
@@ -1088,6 +1062,8 @@ exaDriverInit (ScreenPtr		pScreen,
 	    pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_classic;
 	    pExaScr->do_move_in_pixmap = exaMoveInPixmap_classic;
 	    pExaScr->do_move_out_pixmap = exaMoveOutPixmap_classic;
+	    pExaScr->prepare_access_reg = exaPrepareAccessReg_classic;
+	    pExaScr->finish_access = NULL;
 	}
 	if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) {
 	    LogMessage(X_INFO, "EXA(%d): Offscreen pixmap area of %lu bytes\n",
diff --git a/exa/exa_migration_classic.c b/exa/exa_migration_classic.c
index d8e1e86..0032f02 100644
--- a/exa/exa_migration_classic.c
+++ b/exa/exa_migration_classic.c
@@ -120,7 +120,7 @@ exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc,
     Bool need_sync = FALSE;
 
     /* Damaged bits are valid in current copy but invalid in other one */
-    if (exaPixmapIsOffscreen(pPixmap)) {
+    if (pExaPixmap->offscreen) {
 	REGION_UNION(pScreen, &pExaPixmap->validFB, &pExaPixmap->validFB,
 		     damage);
 	REGION_SUBTRACT(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys,
@@ -225,7 +225,7 @@ exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc,
 				    pExaPixmap->sys_pitch))
 	{
 	    if (!access_prepared) {
-		ExaDoPrepareAccess(&pPixmap->drawable, fallback_index);
+		ExaDoPrepareAccess(pPixmap, fallback_index);
 		access_prepared = TRUE;
 	    }
 	    exaMemcpyBox (pPixmap, pBox,
@@ -263,7 +263,7 @@ exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc,
  * the framebuffer  memory copy to the system memory copy.  Both areas must be
  * allocated.
  */
-static void
+void
 exaCopyDirtyToSys (ExaMigrationPtr migrate)
 {
     PixmapPtr pPixmap = migrate->pPix;
@@ -281,7 +281,7 @@ exaCopyDirtyToSys (ExaMigrationPtr migrate)
  * the system memory copy to the framebuffer memory copy.  Both areas must be
  * allocated.
  */
-static void
+void
 exaCopyDirtyToFb (ExaMigrationPtr migrate)
 {
     PixmapPtr pPixmap = migrate->pPix;
@@ -545,7 +545,7 @@ exaAssertNotDirty (PixmapPtr pPixmap)
     pExaPixmap->offscreen = TRUE;
     pPixmap->devKind = pExaPixmap->fb_pitch;
 
-    if (!ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC))
+    if (!ExaDoPrepareAccess(pPixmap, EXA_PREPARE_SRC))
 	goto skip;
 
     while (nbox--) {
@@ -718,3 +718,23 @@ exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
 	}
     }
 }
+
+void
+exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg)
+{
+    ExaMigrationRec pixmaps[1];
+
+    if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
+	pixmaps[0].as_dst = TRUE;
+	pixmaps[0].as_src = FALSE;
+    } else {
+	pixmaps[0].as_dst = FALSE;
+	pixmaps[0].as_src = TRUE;
+    }
+    pixmaps[0].pPix = pPixmap;
+    pixmaps[0].pReg = pReg;
+
+    exaDoMigration(pixmaps, 1, FALSE);
+
+    (void)ExaDoPrepareAccess(pPixmap, index);
+}
diff --git a/exa/exa_migration_mixed.c b/exa/exa_migration_mixed.c
index d1ee987..f42c9c2 100644
--- a/exa/exa_migration_mixed.c
+++ b/exa/exa_migration_mixed.c
@@ -31,55 +31,16 @@
 #include "exa_priv.h"
 #include "exa.h"
 
-static void
-exaUploadFallback(PixmapPtr pPixmap, CARD8 *src, int src_pitch)
-{
-    ExaPixmapPriv(pPixmap);
-    RegionPtr damage = DamageRegion (pExaPixmap->pDamage);
-    GCPtr pGC = GetScratchGC (pPixmap->drawable.depth,
-		pPixmap->drawable.pScreen);
-    int nbox, cpp = pPixmap->drawable.bitsPerPixel / 8;
-    DamagePtr backup = pExaPixmap->pDamage;
-    BoxPtr pbox;
-    CARD8 *src2;
-
-    /* We don't want damage optimisations. */
-    pExaPixmap->pDamage = NULL;
-    ValidateGC (&pPixmap->drawable, pGC);
-
-    pbox = REGION_RECTS(damage);
-    nbox = REGION_NUM_RECTS(damage);
-
-    while (nbox--) {
-	src2 = src + pbox->y1 * src_pitch + pbox->x1 * cpp;
-
-	ExaCheckPutImage(&pPixmap->drawable, pGC,
-	    pPixmap->drawable.depth, pbox->x1, pbox->y1,
-	    pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, 0,
-	    ZPixmap, (char*) src2);
-
-	pbox++;
-    }
-
-    FreeScratchGC (pGC);
-    pExaPixmap->pDamage = backup;
-}
-
 void
 exaCreateDriverPixmap_mixed(PixmapPtr pPixmap)
 {
     ScreenPtr pScreen = pPixmap->drawable.pScreen;
     ExaScreenPriv(pScreen);
     ExaPixmapPriv(pPixmap);
-    RegionPtr damage = DamageRegion (pExaPixmap->pDamage);
-    void *sys_buffer = pExaPixmap->sys_ptr;
     int w = pPixmap->drawable.width, h = pPixmap->drawable.height;
     int depth = pPixmap->drawable.depth, bpp = pPixmap->drawable.bitsPerPixel;
     int usage_hint = pPixmap->usage_hint;
-    int sys_pitch = pExaPixmap->sys_pitch;
-    int paddedWidth = sys_pitch;
-    int nbox;
-    BoxPtr pbox;
+    int paddedWidth = pExaPixmap->sys_pitch;
 
     /* Already done. */
     if (pExaPixmap->driverPriv)
@@ -105,50 +66,8 @@ exaCreateDriverPixmap_mixed(PixmapPtr pPixmap)
     if (!pExaPixmap->driverPriv)
 	return;
 
-    pExaPixmap->offscreen = TRUE;
-    pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr = NULL;
-    pExaPixmap->sys_pitch = pPixmap->devKind = 0;
-
-    pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
     (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
 				paddedWidth, NULL);
-
-    /* scratch pixmaps */
-    if (!w || !h)
-	goto finish;
-
-    /* we do not malloc memory by default. */
-    if (!sys_buffer)
-	goto finish;
-
-    if (!pExaScr->info->UploadToScreen)
-	goto fallback;
-
-    pbox = REGION_RECTS(damage);
-    nbox = REGION_NUM_RECTS(damage);
-
-    while (nbox--) {
-	if (!pExaScr->info->UploadToScreen(pPixmap, pbox->x1, pbox->y1, pbox->x2 - pbox->x1,
-		pbox->y2 - pbox->y1, (char *) (sys_buffer) + pbox->y1 * sys_pitch + pbox->x1 * (bpp / 8), sys_pitch))
-	    goto fallback;
-
-	pbox++;
-    }
-
-    goto finish;
-
-fallback:
-    exaUploadFallback(pPixmap, sys_buffer, sys_pitch);
-
-finish:
-    free(sys_buffer);
-
-    /* We no longer need this. */
-    if (pExaPixmap->pDamage) {
-	DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage);
-	DamageDestroy(pExaPixmap->pDamage);
-	pExaPixmap->pDamage = NULL;
-    }
 }
 
 void
@@ -175,8 +94,16 @@ exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
     for (i = 0; i < npixmaps; i++) {
 	PixmapPtr pPixmap = pixmaps[i].pPix;
 	ExaPixmapPriv(pPixmap);
+
 	if (!pExaPixmap->driverPriv)
 	    exaCreateDriverPixmap_mixed(pPixmap);
+
+	if (pExaPixmap->pDamage && exaPixmapIsOffscreen(pPixmap)) {
+	    pPixmap->devKind = pExaPixmap->fb_pitch;
+	    exaCopyDirtyToFb(pixmaps + i);
+	}
+
+	pExaPixmap->offscreen = exaPixmapIsOffscreen(pPixmap);
     }
 }
 
@@ -192,3 +119,91 @@ exaMoveInPixmap_mixed(PixmapPtr pPixmap)
 
     exaDoMigration(pixmaps, 1, TRUE);
 }
+
+/* With mixed pixmaps, if we fail to get direct access to the driver pixmap, we
+ * use the DownloadFromScreen hook to retrieve contents to a copy in system
+ * memory, perform software rendering on that and move back the results with the
+ * UploadToScreen hook (see exaFinishAccess_mixed).
+ */
+void
+exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg)
+{
+    if (!ExaDoPrepareAccess(pPixmap, index)) {
+	ExaPixmapPriv(pPixmap);
+	Bool is_offscreen = exaPixmapIsOffscreen(pPixmap);
+	ExaMigrationRec pixmaps[1];
+
+	/* Do we need to allocate our system buffer? */
+	if (!pExaPixmap->sys_ptr) {
+	    pExaPixmap->sys_ptr = malloc(pExaPixmap->sys_pitch *
+					 pPixmap->drawable.height);
+	    if (!pExaPixmap->sys_ptr)
+		FatalError("EXA: malloc failed for size %d bytes\n",
+			   pExaPixmap->sys_pitch * pPixmap->drawable.height);
+	}
+
+	if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
+	    pixmaps[0].as_dst = TRUE;
+	    pixmaps[0].as_src = FALSE;
+	} else {
+	    pixmaps[0].as_dst = FALSE;
+	    pixmaps[0].as_src = TRUE;
+	}
+	pixmaps[0].pPix = pPixmap;
+	pixmaps[0].pReg = pReg;
+
+	if (!pExaPixmap->pDamage && (is_offscreen || !exaPixmapIsPinned(pPixmap))) {
+	    Bool as_dst = pixmaps[0].as_dst;
+
+	    /* Set up damage tracking */
+	    pExaPixmap->pDamage = DamageCreate(NULL, NULL, DamageReportNone,
+					       TRUE, pPixmap->drawable.pScreen,
+					       pPixmap);
+
+	    DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
+	    /* This ensures that pending damage reflects the current operation. */
+	    /* This is used by exa to optimize migration. */
+	    DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
+
+	    if (is_offscreen) {
+		exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
+			       pPixmap->drawable.height);
+
+		/* We don't know which region of the destination will be damaged,
+		 * have to assume all of it
+		 */
+		if (as_dst) {
+		    pixmaps[0].as_dst = FALSE;
+		    pixmaps[0].as_src = TRUE;
+		    pixmaps[0].pReg = NULL;
+		}
+		pPixmap->devKind = pExaPixmap->fb_pitch;
+		exaCopyDirtyToSys(pixmaps);
+	    }
+
+	    if (as_dst)
+		exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
+			       pPixmap->drawable.height);
+	} else if (is_offscreen) {
+	    pPixmap->devKind = pExaPixmap->fb_pitch;
+	    exaCopyDirtyToSys(pixmaps);
+	}
+
+	pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
+	pPixmap->devKind = pExaPixmap->sys_pitch;
+	pExaPixmap->offscreen = FALSE;
+    }
+}
+
+/* Move back results of software rendering on system memory copy of mixed driver
+ * pixmap (see exaPrepareAccessReg_mixed).
+ */
+void exaFinishAccess_mixed(PixmapPtr pPixmap, int index)
+{
+    ExaPixmapPriv(pPixmap);
+
+    if (pExaPixmap->pDamage && exaPixmapIsOffscreen(pPixmap)) {
+	DamageRegionProcessPending(&pPixmap->drawable);
+	exaMoveInPixmap_mixed(pPixmap);
+    }
+}
diff --git a/exa/exa_mixed.c b/exa/exa_mixed.c
index 6aa73f2..167ffa9 100644
--- a/exa/exa_mixed.c
+++ b/exa/exa_mixed.c
@@ -32,8 +32,6 @@
 #include "exa.h"
 
 /* This file holds the driver allocated pixmaps + better initial placement code.
- * A pinned pixmap implies one that is either driver based already or otherwise altered.
- * Proper care is taken to free the initially allocated buffer.
  */
 
 static _X_INLINE void*
@@ -46,9 +44,6 @@ ExaGetPixmapAddress(PixmapPtr p)
 
 /**
  * exaCreatePixmap() creates a new pixmap.
- *
- * Pixmaps are always marked as pinned, unless the pixmap can still be transfered to a
- * driver pixmaps.
  */
 PixmapPtr
 exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
@@ -85,7 +80,6 @@ exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
     pExaPixmap->sys_pitch = paddedWidth;
 
     pExaPixmap->area = NULL;
-    pExaPixmap->offscreen = FALSE;
     pExaPixmap->fb_ptr = NULL;
     pExaPixmap->pDamage = NULL;
 
@@ -93,36 +87,15 @@ exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
     exaSetAccelBlock(pExaScr, pExaPixmap,
 	w, h, bpp);
 
-    /* Avoid freeing sys_ptr. */
-    pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
-
     (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
 				    paddedWidth, NULL);
 
-    /* We want to be able to transfer the pixmap to driver memory later on. */
-    pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
-
     /* A scratch pixmap will become a driver pixmap right away. */
     if (!w || !h) {
 	exaCreateDriverPixmap_mixed(pPixmap);
-    } else {
-	/* Set up damage tracking */
-	pExaPixmap->pDamage = DamageCreate (NULL, NULL,
-					    DamageReportNone, TRUE,
-					    pScreen, pPixmap);
-
-	if (pExaPixmap->pDamage == NULL) {
-	    swap(pExaScr, pScreen, DestroyPixmap);
-	    pScreen->DestroyPixmap (pPixmap);
-	    swap(pExaScr, pScreen, DestroyPixmap);
-	    return NULL;
-	}
-
-	DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage);
-	/* This ensures that pending damage reflects the current operation. */
-	/* This is used by exa to optimize migration. */
-	DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE);
-    }
+	pExaPixmap->offscreen = exaPixmapIsOffscreen(pPixmap);
+    } else
+	pExaPixmap->offscreen = FALSE;
 
     return pPixmap;
 }
@@ -134,7 +107,7 @@ exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
     ScreenPtr pScreen = pPixmap->drawable.pScreen;
     ExaScreenPrivPtr pExaScr;
     ExaPixmapPrivPtr pExaPixmap;
-    Bool ret;
+    Bool ret, is_offscreen;
 
     if (!pPixmap)
         return FALSE;
@@ -142,26 +115,23 @@ exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
     pExaScr = ExaGetScreenPriv(pScreen);
     pExaPixmap = ExaGetPixmapPriv(pPixmap);
 
-    if (pExaPixmap) {
-	if (!exaPixmapIsPinned(pPixmap)) {
-	    free(pExaPixmap->sys_ptr);
-	    pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr = NULL;
-	    pExaPixmap->sys_pitch = pPixmap->devKind = 0;
-
-	    /* We no longer need this. */
+    if (pPixData) {
+	if (pExaPixmap->driverPriv) {
 	    if (pExaPixmap->pDamage) {
 		DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage);
 		DamageDestroy(pExaPixmap->pDamage);
 		pExaPixmap->pDamage = NULL;
 	    }
-	}
 
-        if (pPixData)
-            pExaPixmap->sys_ptr = pPixData;
+	    pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
+	    pExaPixmap->driverPriv = NULL;
+	}
 
-        if (devKind > 0)
-            pExaPixmap->sys_pitch = devKind;
+	pExaPixmap->offscreen = FALSE;
+	pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
+    }
 
+    if (pExaPixmap->driverPriv) {
         if (width > 0 && height > 0 && bitsPerPixel > 0) {
             exaSetFbPitch(pExaScr, pExaPixmap,
                           width, height, bitsPerPixel);
@@ -169,9 +139,15 @@ exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
             exaSetAccelBlock(pExaScr, pExaPixmap,
                              width, height, bitsPerPixel);
         }
+    }
 
-	/* Anything can happen, don't try to predict it all. */
-	pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
+    is_offscreen = exaPixmapIsOffscreen(pPixmap);
+    if (is_offscreen) {
+	pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
+	pPixmap->devKind = pExaPixmap->fb_pitch;
+    } else {
+	pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
+	pPixmap->devKind = pExaPixmap->sys_pitch;
     }
 
     /* Only pass driver pixmaps to the driver. */
@@ -182,10 +158,6 @@ exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
 	 * 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)
 	    goto out;
     }
@@ -196,6 +168,13 @@ exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
     swap(pExaScr, pScreen, ModifyPixmapHeader);
 
 out:
+    if (is_offscreen) {
+	pExaPixmap->fb_ptr = pPixmap->devPrivate.ptr;
+	pExaPixmap->fb_pitch = pPixmap->devKind;
+    } else {
+	pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
+	pExaPixmap->sys_pitch = pPixmap->devKind;
+    }
     /* Always NULL this, we don't want lingering pointers. */
     pPixmap->devPrivate.ptr = NULL;
 
@@ -215,10 +194,14 @@ exaDestroyPixmap_mixed(PixmapPtr pPixmap)
 
 	if (pExaPixmap->driverPriv)
 	    pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
-	else if (pExaPixmap->sys_ptr && !exaPixmapIsPinned(pPixmap))
-	    free(pExaPixmap->sys_ptr);
 	pExaPixmap->driverPriv = NULL;
-	pExaPixmap->sys_ptr = NULL;
+
+	if (pExaPixmap->pDamage) {
+	    if (pExaPixmap->sys_ptr)
+		free(pExaPixmap->sys_ptr);
+	    pExaPixmap->sys_ptr = NULL;
+	    pExaPixmap->pDamage = NULL;
+	}
     }
 
     swap(pExaScr, pScreen, DestroyPixmap);
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index 869cf17..1aec8e9 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -176,6 +176,8 @@ typedef struct {
     Bool (*pixmap_is_offscreen) (PixmapPtr pPixmap);
     void (*do_move_in_pixmap) (PixmapPtr pPixmap);
     void (*do_move_out_pixmap) (PixmapPtr pPixmap);
+    void (*prepare_access_reg)(PixmapPtr pPixmap, int index, RegionPtr pReg);
+    void (*finish_access)(PixmapPtr pPixmap, int index);
 
     Bool			 swappedOut;
     enum ExaMigrationHeuristic	 migration;
@@ -511,10 +513,7 @@ ExaOffscreenFini (ScreenPtr pScreen);
 
 /* exa.c */
 Bool
-ExaDoPrepareAccess(DrawablePtr pDrawable, int index);
-
-void
-exaPrepareAccessReg(DrawablePtr pDrawable, int index, RegionPtr pReg);
+ExaDoPrepareAccess(PixmapPtr pPixmap, int index);
 
 void
 exaPrepareAccess(DrawablePtr pDrawable, int index);
@@ -609,6 +608,12 @@ exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
 void
 exaMoveInPixmap_mixed(PixmapPtr pPixmap);
 
+void
+exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg);
+
+void
+exaFinishAccess_mixed(PixmapPtr pPixmap, int index);
+
 /* exa_render.c */
 Bool
 exaOpReadsDestination (CARD8 op);
@@ -665,6 +670,12 @@ exaGlyphs (CARD8	op,
 
 /* exa_migration_classic.c */
 void
+exaCopyDirtyToSys (ExaMigrationPtr migrate);
+
+void
+exaCopyDirtyToFb (ExaMigrationPtr migrate);
+
+void
 exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
 
 void
@@ -676,4 +687,7 @@ exaMoveOutPixmap_classic (PixmapPtr pPixmap);
 void
 exaMoveInPixmap_classic (PixmapPtr pPixmap);
 
+void
+exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg);
+
 #endif /* EXAPRIV_H */
diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c
index f4700ad..c8f0172 100644
--- a/exa/exa_unaccel.c
+++ b/exa/exa_unaccel.c
@@ -101,16 +101,19 @@ ExaCheckPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth,
 		 int x, int y, int w, int h, int leftPad, int format,
 		 char *bits)
 {
-    ExaPixmapPriv(exaGetDrawablePixmap(pDrawable));
+    PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
+    ExaPixmapPriv(pPixmap);
+    ExaScreenPriv(pDrawable->pScreen);
 
     EXA_GC_PROLOGUE(pGC);
     EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
-    if (exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle,
+    if (!pExaScr->prepare_access_reg || !pExaPixmap->pDamage ||
+	exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle,
 			      pGC->alu, pGC->clientClipType))
 	exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
     else
-	exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pExaPixmap->pDamage ?
-			     DamagePendingRegion(pExaPixmap->pDamage) : NULL);
+	pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_DEST,
+				    DamagePendingRegion(pExaPixmap->pDamage));
     pGC->ops->PutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits);
     exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
     EXA_GC_EPILOGUE(pGC);
@@ -323,9 +326,6 @@ void
 ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
 		unsigned int format, unsigned long planeMask, char *d)
 {
-    BoxRec Box;
-    RegionRec Reg;
-    int xoff, yoff;
     ScreenPtr pScreen = pDrawable->pScreen;
     PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
     ExaScreenPriv(pScreen);
@@ -333,16 +333,24 @@ ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
     EXA_FALLBACK(("from %p (%c)\n", pDrawable,
 		  exaDrawableLocation(pDrawable)));
 
-    exaGetDrawableDeltas(pDrawable, pPix, &xoff, &yoff);
+    if (pExaScr->prepare_access_reg) {
+	int xoff, yoff;
+	BoxRec Box;
+	RegionRec Reg;
+
+	exaGetDrawableDeltas(pDrawable, pPix, &xoff, &yoff);
+
+	Box.x1 = pDrawable->y + x + xoff;
+	Box.y1 = pDrawable->y + y + yoff;
+	Box.x2 = Box.x1 + w;
+	Box.y2 = Box.y1 + h;
 
-    Box.x1 = pDrawable->y + x + xoff;
-    Box.y1 = pDrawable->y + y + yoff;
-    Box.x2 = Box.x1 + w;
-    Box.y2 = Box.y1 + h;
+	REGION_INIT(pScreen, &Reg, &Box, 1);
 
-    REGION_INIT(pScreen, &Reg, &Box, 1);
+	pExaScr->prepare_access_reg(pPix, EXA_PREPARE_SRC, &Reg);
+    } else
+	exaPrepareAccess(pDrawable, EXA_PREPARE_SRC);
 
-    exaPrepareAccessReg (pDrawable, EXA_PREPARE_SRC, &Reg);
     swap(pExaScr, pScreen, GetImage);
     pScreen->GetImage (pDrawable, x, y, w, h, format, planeMask, d);
     swap(pExaScr, pScreen, GetImage);
@@ -401,23 +409,23 @@ ExaCheckComposite (CARD8      op,
     if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
 	exaPrepareAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX_MASK);
 
-    if (!exaOpReadsDestination(op)) {
+    if (!exaOpReadsDestination(op) && pExaScr->prepare_access_reg) {
+	PixmapPtr pDstPix;
+
 	if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
 				       xSrc, ySrc, xMask, yMask, xDst, yDst,
 				       width, height))
 	    goto skip;
 
-	exaGetDrawableDeltas (pDst->pDrawable,
-			      exaGetDrawablePixmap(pDst->pDrawable),
-			      &xoff, &yoff);
-
+	pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
+	exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &xoff, &yoff);
 	REGION_TRANSLATE(pScreen, &region, xoff, yoff);
 
 	if (pDst->alphaMap && pDst->alphaMap->pDrawable)
-	    exaPrepareAccessReg(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST,
-				&region);
+	    pExaScr->prepare_access_reg(exaGetDrawablePixmap(pDst->alphaMap->pDrawable),
+					EXA_PREPARE_AUX_DEST, &region);
 
-	exaPrepareAccessReg (pDst->pDrawable, EXA_PREPARE_DEST, &region);
+	pExaScr->prepare_access_reg(pDstPix, EXA_PREPARE_DEST, &region);
     } else {
 	if (pDst->alphaMap && pDst->alphaMap->pDrawable)
 	    exaPrepareAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST);
-- 
1.6.4.3



More information about the xorg-devel mailing list