xserver: Branch 'master' - 4 commits

Michel Dänzer daenzer at kemper.freedesktop.org
Fri Sep 25 17:05:49 PDT 2009


 exa/exa.c                   |   92 ++++++++------------
 exa/exa_glyphs.c            |   89 ++++++++++---------
 exa/exa_migration_classic.c |   30 +++++-
 exa/exa_migration_mixed.c   |  197 +++++++++++++++++++++++++-------------------
 exa/exa_mixed.c             |   90 ++++++++------------
 exa/exa_priv.h              |   23 ++++-
 exa/exa_unaccel.c           |   52 ++++++-----
 7 files changed, 311 insertions(+), 262 deletions(-)

New commits:
commit abb8108fb44cc9b08fe4ae7d805a0a22564ca6bb
Author: Michel Dänzer <daenzer at vmware.com>
Date:   Sat Sep 26 02:05:24 2009 +0200

    EXA: Only calculate cache position once for each glyph.

diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c
index f85bbcf..5a37004 100644
--- a/exa/exa_glyphs.c
+++ b/exa/exa_glyphs.c
@@ -359,7 +359,8 @@ exaGlyphCacheHashRemove(ExaGlyphCachePtr cache,
 static void
 exaGlyphCacheUploadGlyph(ScreenPtr         pScreen,
 			 ExaGlyphCachePtr  cache,
-			 int               pos,
+			 int               x,
+			 int               y,
 			 GlyphPtr          pGlyph)
 {
     ExaScreenPriv(pScreen);
@@ -394,10 +395,10 @@ exaGlyphCacheUploadGlyph(ScreenPtr         pScreen,
     if (!exaPixmapIsOffscreen(pCachePixmap))
 	goto composite;
 
-    /* CACHE_{X,Y} are in pixmap coordinates, no need for cache{X,Y}off */
+    /* x,y are in pixmap coordinates, no need for cache{X,Y}off */
     if (pExaScr->info->UploadToScreen(pCachePixmap,
-				      CACHE_X(pos),
-				      CACHE_Y(pos),
+				      x,
+				      y,
 				      pGlyph->info.width,
 				      pGlyph->info.height,
 				      (char *)pExaPixmap->sys_ptr,
@@ -411,18 +412,18 @@ composite:
 		      cache->picture,
 		      0, 0,
 		      0, 0,
-		      CACHE_X(pos),
-		      CACHE_Y(pos),
+		      x,
+		      y,
 		      pGlyph->info.width,
 		      pGlyph->info.height);
 
 damage:
     /* The cache pixmap isn't a window, so no need to offset coordinates. */
     exaPixmapDirty (pCachePixmap,
-		    CACHE_X(pos),
-		    CACHE_Y(pos),
-		    CACHE_X(pos) + cache->glyphWidth,
-		    CACHE_Y(pos) + cache->glyphHeight);
+		    x,
+		    y,
+		    x + cache->glyphWidth,
+		    y + cache->glyphHeight);
 }
 
 static ExaGlyphCacheResult
@@ -441,6 +442,7 @@ exaGlyphCacheBufferGlyph(ScreenPtr         pScreen,
 {
     ExaCompositeRectPtr rect;
     int pos;
+    int x, y;
     
     if (buffer->mask && buffer->mask != cache->picture)
 	return ExaGlyphNeedFlush;
@@ -457,10 +459,14 @@ exaGlyphCacheBufferGlyph(ScreenPtr         pScreen,
     pos = exaGlyphCacheHashLookup(cache, pGlyph);
     if (pos != -1) {
 	DBG_GLYPH_CACHE(("  found existing glyph at %d\n", pos));
+	x = CACHE_X(pos);
+	y = CACHE_Y(pos);
     } else {
 	if (cache->glyphCount < cache->size) {
 	    /* Space remaining; we fill from the start */
 	    pos = cache->glyphCount;
+	    x = CACHE_X(pos);
+	    y = CACHE_Y(pos);
 	    cache->glyphCount++;
 	    DBG_GLYPH_CACHE(("  storing glyph in free space at %d\n", pos));
 
@@ -472,14 +478,12 @@ exaGlyphCacheBufferGlyph(ScreenPtr         pScreen,
 	     * the cache
 	     */
 	    pos = cache->evictionPosition;
+	    x = CACHE_X(pos);
+	    y = CACHE_Y(pos);
 	    DBG_GLYPH_CACHE(("  evicting glyph at %d\n", pos));
 	    if (buffer->count) {
-		int x, y;
 		int i;
 
-		x = CACHE_X(pos);
-		y = CACHE_Y(pos);
-
 		for (i = 0; i < buffer->count; i++) {
 		    if (pSrc ?
 			(buffer->rects[i].xMask == x && buffer->rects[i].yMask == y) :
@@ -498,7 +502,7 @@ exaGlyphCacheBufferGlyph(ScreenPtr         pScreen,
 	    cache->evictionPosition = rand() % cache->size;
 	}
 
-	exaGlyphCacheUploadGlyph(pScreen, cache, pos, pGlyph);
+	exaGlyphCacheUploadGlyph(pScreen, cache, x, y, pGlyph);
     }
 
     buffer->mask = cache->picture;
@@ -509,13 +513,13 @@ exaGlyphCacheBufferGlyph(ScreenPtr         pScreen,
     {
 	rect->xSrc = xSrc;
 	rect->ySrc = ySrc;
-	rect->xMask = CACHE_X(pos);
-	rect->yMask = CACHE_Y(pos);
+	rect->xMask = x;
+	rect->yMask = y;
     }
     else
     {
-	rect->xSrc = CACHE_X(pos);
-	rect->ySrc = CACHE_Y(pos);
+	rect->xSrc = x;
+	rect->ySrc = y;
 	rect->xMask = 0;
 	rect->yMask = 0;
     }
commit c11678cc189551f2a01eaa7a63969c16950739b4
Author: Michel Dänzer <daenzer at vmware.com>
Date:   Sat Sep 26 02:05:06 2009 +0200

    EXA: Accumulate arbitrary number of glyphs without flushing.

diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c
index bf097c3..f85bbcf 100644
--- a/exa/exa_glyphs.c
+++ b/exa/exa_glyphs.c
@@ -62,15 +62,10 @@
  */
 #define CACHE_PICTURE_WIDTH 1024
 
-/* Maximum number of glyphs we buffer on the stack before flushing
- * rendering to the mask or destination surface.
- */
-#define GLYPH_BUFFER_SIZE 256
-
 typedef struct {
     PicturePtr mask;
-    ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE];
     int count;
+    ExaCompositeRectRec rects[0];
 } ExaGlyphBuffer, *ExaGlyphBufferPtr;
 
 typedef enum {
@@ -553,16 +548,13 @@ exaBufferGlyph(ScreenPtr         pScreen,
 	       INT16             yDst)
 {
     ExaScreenPriv(pScreen);
-    unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format;
+    PicturePtr mask = GlyphPicture(pGlyph)[pScreen->myNum];
+    unsigned int format = mask->format;
     int width = pGlyph->info.width;
     int height = pGlyph->info.height;
     ExaCompositeRectPtr rect;
-    PicturePtr mask;
     int i;
 
-    if (buffer->count == GLYPH_BUFFER_SIZE)
-	return ExaGlyphNeedFlush;
-
     if (PICT_FORMAT_BPP(format) == 1)
 	format = PICT_a8;
     
@@ -593,7 +585,6 @@ exaBufferGlyph(ScreenPtr         pScreen,
 
     /* Couldn't find the glyph in the cache, use the glyph picture directly */
 
-    mask = GlyphPicture(pGlyph)[pScreen->myNum];
     if (buffer->mask && buffer->mask != mask)
 	return ExaGlyphNeedFlush;
 
@@ -707,12 +698,18 @@ exaGlyphs (CARD8 	 op,
     int		width = 0, height = 0;
     int		x, y;
     int		first_xOff = list->xOff, first_yOff = list->yOff;
-    int		n;
+    int		i, n;
     GlyphPtr	glyph;
     int		error;
     BoxRec	extents = {0, 0, 0, 0};
     CARD32	component_alpha;
-    ExaGlyphBuffer buffer;
+    ExaGlyphBufferPtr buffer;
+
+    for (i = 0, n = 0; i < nlist; i++)
+	n += list[i].len;
+    buffer = alloca(sizeof(ExaGlyphBuffer) + n * sizeof(ExaCompositeRectRec));
+    if (!buffer)
+	return;
 
     if (maskFormat)
     {
@@ -792,8 +789,8 @@ exaGlyphs (CARD8 	 op,
 	x = 0;
 	y = 0;
     }
-    buffer.count = 0;
-    buffer.mask = NULL;
+    buffer->count = 0;
+    buffer->mask = NULL;
     while (nlist--)
     {
 	x += list->xOff;
@@ -808,23 +805,23 @@ exaGlyphs (CARD8 	 op,
 		/* pGlyph->info.{x,y} compensate for empty space in the glyph. */
 		if (maskFormat)
 		{
-		    if (exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask,
+		    if (exaBufferGlyph(pScreen, buffer, glyph, NULL, pMask,
 				       0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y) == ExaGlyphNeedFlush)
 		    {
-			exaGlyphsToMask(pMask, &buffer);
-			exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask,
+			exaGlyphsToMask(pMask, buffer);
+			exaBufferGlyph(pScreen, buffer, glyph, NULL, pMask,
 				       0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y);
 		    }
 		}
 		else
 		{
-		    if (exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst,
+		    if (exaBufferGlyph(pScreen, buffer, glyph, pSrc, pDst,
 				       xSrc + (x - glyph->info.x) - first_xOff, ySrc + (y - glyph->info.y) - first_yOff,
 				       0, 0, x - glyph->info.x, y - glyph->info.y)
 			== ExaGlyphNeedFlush)
 		    {
-			exaGlyphsToDst(pSrc, pDst, &buffer);
-			exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst,
+			exaGlyphsToDst(pSrc, pDst, buffer);
+			exaBufferGlyph(pScreen, buffer, glyph, pSrc, pDst,
 				       xSrc + (x - glyph->info.x) - first_xOff, ySrc + (y - glyph->info.y) - first_yOff,
 				       0, 0, x - glyph->info.x, y - glyph->info.y);
 		    }
@@ -837,11 +834,11 @@ exaGlyphs (CARD8 	 op,
 	list++;
     }
     
-    if (buffer.count) {
+    if (buffer->count) {
         if (maskFormat)
-	    exaGlyphsToMask(pMask, &buffer);
+	    exaGlyphsToMask(pMask, buffer);
         else
-	    exaGlyphsToDst(pSrc, pDst, &buffer);
+	    exaGlyphsToDst(pSrc, pDst, buffer);
     }
 
     if (maskFormat)
commit 0369eeeb6bf8a808fa2df503fc8b8df81e6e07b8
Author: Michel Dänzer <daenzer at vmware.com>
Date:   Sat Sep 26 02:04:48 2009 +0200

    EXA: Try to minimize UploadToScreen calls for mixed pixmaps.
    
    If there are several software fallbacks affecting the system memory copy of the
    same pixmap, only copy the results back to the driver pixmap when it's used for
    acceleration again, or in the BlockHandler, whichever happens first.

diff --git a/exa/exa.c b/exa/exa.c
index e264d44..46e9182 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -774,10 +774,18 @@ ExaBlockHandler(int screenNum, pointer blockData, pointer pTimeout,
     ScreenPtr pScreen = screenInfo.screens[screenNum];
     ExaScreenPriv(pScreen);
 
+    /* Move any deferred results from a software fallback to the driver pixmap */
+    if (pExaScr->deferred_mixed_pixmap)
+	exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap);
+
     unwrap(pExaScr, pScreen, BlockHandler);
     (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask);
     wrap(pExaScr, pScreen, BlockHandler, ExaBlockHandler);
 
+    /* The rest only applies to classic EXA */
+    if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS)
+	return;
+
     /* Try and keep the offscreen memory area tidy every now and then (at most 
      * once per second) when the server has been idle for at least 100ms.
      */
@@ -991,10 +999,12 @@ exaDriverInit (ScreenPtr		pScreen,
      * Replace various fb screen functions
      */
     if ((pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) &&
-	!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) {
+	(!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) ||
+	 (pExaScr->info->flags & EXA_MIXED_PIXMAPS)))
 	wrap(pExaScr, pScreen, BlockHandler, ExaBlockHandler);
+    if ((pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) &&
+	!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS))
 	wrap(pExaScr, pScreen, WakeupHandler, ExaWakeupHandler);
-    }
     wrap(pExaScr, pScreen, CreateGC, exaCreateGC);
     wrap(pExaScr, pScreen, CloseScreen, exaCloseScreen);
     wrap(pExaScr, pScreen, GetImage, exaGetImage);
diff --git a/exa/exa_migration_mixed.c b/exa/exa_migration_mixed.c
index f42c9c2..6065d75 100644
--- a/exa/exa_migration_mixed.c
+++ b/exa/exa_migration_mixed.c
@@ -99,8 +99,13 @@ exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
 	    exaCreateDriverPixmap_mixed(pPixmap);
 
 	if (pExaPixmap->pDamage && exaPixmapIsOffscreen(pPixmap)) {
+	    ExaScreenPriv(pPixmap->drawable.pScreen);
+
 	    pPixmap->devKind = pExaPixmap->fb_pitch;
 	    exaCopyDirtyToFb(pixmaps + i);
+
+	    if (pExaScr->deferred_mixed_pixmap == pPixmap)
+		pExaScr->deferred_mixed_pixmap = NULL;
 	}
 
 	pExaPixmap->offscreen = exaPixmapIsOffscreen(pPixmap);
@@ -197,6 +202,9 @@ exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg)
 
 /* Move back results of software rendering on system memory copy of mixed driver
  * pixmap (see exaPrepareAccessReg_mixed).
+ *
+ * Defer moving the destination back into the driver pixmap, to try and save
+ * overhead on multiple consequent software fallbacks.
  */
 void exaFinishAccess_mixed(PixmapPtr pPixmap, int index)
 {
@@ -204,6 +212,16 @@ void exaFinishAccess_mixed(PixmapPtr pPixmap, int index)
 
     if (pExaPixmap->pDamage && exaPixmapIsOffscreen(pPixmap)) {
 	DamageRegionProcessPending(&pPixmap->drawable);
-	exaMoveInPixmap_mixed(pPixmap);
+
+	if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
+	    ExaScreenPriv(pPixmap->drawable.pScreen);
+
+	    if (pExaScr->deferred_mixed_pixmap &&
+		pExaScr->deferred_mixed_pixmap != pPixmap)
+		exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap);
+	    pExaScr->deferred_mixed_pixmap = pPixmap;
+	    pPixmap->devKind = pExaPixmap->fb_pitch;
+	} else
+	    exaMoveInPixmap_mixed(pPixmap);
     }
 }
diff --git a/exa/exa_mixed.c b/exa/exa_mixed.c
index 167ffa9..bc393c7 100644
--- a/exa/exa_mixed.c
+++ b/exa/exa_mixed.c
@@ -192,6 +192,9 @@ exaDestroyPixmap_mixed(PixmapPtr pPixmap)
     {
 	ExaPixmapPriv (pPixmap);
 
+	if (pExaScr->deferred_mixed_pixmap == pPixmap)
+	    pExaScr->deferred_mixed_pixmap = NULL;
+
 	if (pExaPixmap->driverPriv)
 	    pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
 	pExaPixmap->driverPriv = NULL;
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index 1aec8e9..5b056da 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -188,6 +188,7 @@ typedef struct {
     unsigned			 numOffscreenAvailable;
     CARD32			 lastDefragment;
     CARD32			 nextDefragment;
+    PixmapPtr			 deferred_mixed_pixmap;
 
     /* Reference counting for accessed pixmaps */
     struct {
commit 1818cbd70fc1f2e1487b4c678e67e28f1265c0ef
Author: Michel Dänzer <daenzer at vmware.com>
Date:   Sat Sep 26 01:59:39 2009 +0200

    EXA: Extend mixed pixmaps scheme to allow driver PrepareAccess hook to fail.
    
    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.

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);


More information about the xorg-commit mailing list