xserver: Branch 'no-pci-rework' - 16 commits

Michel Daenzer daenzer at kemper.freedesktop.org
Fri Sep 7 15:20:37 PDT 2007


 exa/exa.c             |  210 ++++++++++++----
 exa/exa_accel.c       |  627 +++++++++++++++++++++++++-------------------------
 exa/exa_migration.c   |  352 +++++++++++++++-------------
 exa/exa_priv.h        |   65 +++--
 exa/exa_render.c      |  320 ++++++++++++++-----------
 exa/exa_unaccel.c     |   89 ++++---
 miext/damage/damage.c |    6 
 miext/damage/damage.h |    3 
 8 files changed, 965 insertions(+), 707 deletions(-)

New commits:
diff-tree 032c729bb8d925d7b8a4a81ddc9dd03e9031cf91 (from 19149c6669e3a72f81e7c773df734ea98a009d0c)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Mon Sep 3 13:52:29 2007 +0200

    EXA: Exclude bits that will be overwritten from migration in exaCopyNtoN.
    
    Also plug a region leak in exaPolyFillRect.

diff --git a/exa/exa_accel.c b/exa/exa_accel.c
index 0a03d71..232ec99 100644
--- a/exa/exa_accel.c
+++ b/exa/exa_accel.c
@@ -483,14 +483,48 @@ exaCopyNtoN (DrawablePtr    pSrcDrawable
     int	    src_off_x, src_off_y;
     int	    dst_off_x, dst_off_y;
     ExaMigrationRec pixmaps[2];
+    RegionPtr region = NULL;
+
+    pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
+    pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
+
+    exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
+    exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);
+
+    if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask,
+				       pGC->fillStyle, pGC->alu)) {
+	xRectangle *rects = ALLOCATE_LOCAL(nbox * sizeof(xRectangle));
+
+	if (rects) {
+	    int i;
+
+	    for (i = 0; i < nbox; i++) {
+		rects[i].x = pbox[i].x1 + dst_off_x;
+		rects[i].y = pbox[i].y1 + dst_off_y;
+		rects[i].width = pbox[i].x2 - pbox[i].x1;
+		rects[i].height = pbox[i].y2 - pbox[i].y1;
+	    }
+
+	    region  = RECTS_TO_REGION(pScreen, nbox, rects, CT_YXBANDED);
+	    DEALLOCATE_LOCAL(rects);
+
+	    if (region) {
+		src_off_x -= dst_off_x;
+		src_off_y -= dst_off_y;
+		dst_off_x = dst_off_y = 0;
+		pbox = REGION_RECTS(region);
+		nbox = REGION_NUM_RECTS(region);
+	    }
+	}
+    }
 
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = FALSE;
-    pixmaps[0].pPix = pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
-    pixmaps[0].pReg = NULL;
+    pixmaps[0].pPix = pDstPixmap;
+    pixmaps[0].pReg = region;
     pixmaps[1].as_dst = FALSE;
     pixmaps[1].as_src = TRUE;
-    pixmaps[1].pPix = pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
+    pixmaps[1].pPix = pSrcPixmap;
     pixmaps[1].pReg = NULL;
 
     /* Respect maxX/maxY in a trivial way: don't set up drawing when we might
@@ -512,16 +546,10 @@ exaCopyNtoN (DrawablePtr    pSrcDrawable
 	reverse != upsidedown) {
 	if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
 			       dx, dy))
-	    return;
+	    goto out;
 	goto fallback;
     }
 
-    pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
-    pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
-
-    exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
-    exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);
-
     if (!exaPixmapIsOffscreen(pSrcPixmap) ||
 	!exaPixmapIsOffscreen(pDstPixmap) ||
 	!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1,
@@ -544,18 +572,24 @@ exaCopyNtoN (DrawablePtr    pSrcDrawable
     (*pExaScr->info->DoneCopy) (pDstPixmap);
     exaMarkSync (pDstDrawable->pScreen);
 
-    return;
+    goto out;
 
 fallback:
     EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable,
 		  exaDrawableLocation(pSrcDrawable),
 		  exaDrawableLocation(pDstDrawable)));
-    exaPrepareAccessReg (pDstDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
+    exaPrepareAccessReg (pDstDrawable, EXA_PREPARE_DEST, region);
     exaPrepareAccess (pSrcDrawable, EXA_PREPARE_SRC);
     fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse,
 		upsidedown, bitplane, closure);
     exaFinishAccess (pSrcDrawable, EXA_PREPARE_SRC);
     exaFinishAccess (pDstDrawable, EXA_PREPARE_DEST);
+
+out:
+    if (region) {
+	REGION_UNINIT(pScreen, region);
+	REGION_DESTROY(pScreen, region);
+    }
 }
 
 RegionPtr
@@ -870,6 +904,7 @@ fallback:
     exaMarkSync(pDrawable->pScreen);
 
 out:
+    REGION_UNINIT(pScreen, pReg);
     REGION_DESTROY(pScreen, pReg);
 }
 
diff-tree 19149c6669e3a72f81e7c773df734ea98a009d0c (from fac68373b2d5a758a852d58cc91329dba721b221)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Mon Sep 3 13:14:29 2007 +0200

    EXA: exaFillRegion{Solid,Tiled} improvements.
    
    Use region to exclude bits that will be overwritten from migration.
    
    Also make exaFillRegionSolid use the same logic as exaFillRegionTiled.

diff --git a/exa/exa_accel.c b/exa/exa_accel.c
index e44ce60..0a03d71 100644
--- a/exa/exa_accel.c
+++ b/exa/exa_accel.c
@@ -1074,7 +1074,11 @@ exaFillRegionSolid (DrawablePtr	pDrawabl
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = FALSE;
     pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
-    pixmaps[0].pReg = NULL;
+    pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid,
+					    alu) ? NULL : pRegion;
+
+    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
+    REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);
 
     if (pPixmap->drawable.width > pExaScr->info->maxX ||
 	pPixmap->drawable.height > pExaScr->info->maxY)
@@ -1090,8 +1094,6 @@ exaFillRegionSolid (DrawablePtr	pDrawabl
 	int nbox;
 	BoxPtr pBox;
 
-	REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);
-
 	nbox = REGION_NUM_RECTS (pRegion);
 	pBox = REGION_RECTS (pRegion);
 
@@ -1124,19 +1126,21 @@ exaFillRegionSolid (DrawablePtr	pDrawabl
 	}
 
 	REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
+	return TRUE;
     }
-    else
-    {
+
 fallback:
-	if (alu != GXcopy || planemask != FB_ALLONES)
-	    return FALSE;
-	EXA_FALLBACK(("to %p (%c)\n", pDrawable,
-		      exaDrawableLocation(pDrawable)));
-	exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
-	fbFillRegionSolid (pDrawable, pRegion, 0,
-			   fbReplicatePixel (pixel, pDrawable->bitsPerPixel));
-	exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
+    if (alu != GXcopy || !EXA_PM_IS_SOLID(pDrawable, planemask)) {
+	REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
+	return FALSE;
     }
+    EXA_FALLBACK(("to %p (%c)\n", pDrawable,
+		  exaDrawableLocation(pDrawable)));
+    exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
+    REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
+    fbFillRegionSolid (pDrawable, pRegion, 0,
+		       fbReplicatePixel (pixel, pDrawable->bitsPerPixel));
+    exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
 
     return TRUE;
 }
@@ -1174,12 +1178,16 @@ exaFillRegionTiled (DrawablePtr	pDrawabl
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = FALSE;
     pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
-    pixmaps[0].pReg = NULL;
+    pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled,
+					    alu) ? NULL : pRegion;
     pixmaps[1].as_dst = FALSE;
     pixmaps[1].as_src = TRUE;
     pixmaps[1].pPix = pTile;
     pixmaps[1].pReg = NULL;
 
+    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
+    REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);
+
     if (pPixmap->drawable.width > pExaScr->info->maxX ||
 	pPixmap->drawable.height > pExaScr->info->maxY ||
 	tileWidth > pExaScr->info->maxX ||
@@ -1208,7 +1216,7 @@ exaFillRegionTiled (DrawablePtr	pDrawabl
 	    int dstY = pBox->y1;
 	    int tileY;
 
-	    tileY = (dstY - pDrawable->y - pPatOrg->y) % tileHeight;
+	    tileY = (dstY - yoff - pDrawable->y - pPatOrg->y) % tileHeight;
 	    while (height > 0) {
 		int width = pBox->x2 - pBox->x1;
 		int dstX = pBox->x1;
@@ -1219,7 +1227,7 @@ exaFillRegionTiled (DrawablePtr	pDrawabl
 		    h = height;
 		height -= h;
 
-		tileX = (dstX - pDrawable->x - pPatOrg->x) % tileWidth;
+		tileX = (dstX - xoff - pDrawable->x - pPatOrg->x) % tileWidth;
 		while (width > 0) {
 		    int w = tileWidth - tileX;
 		    if (w > width)
@@ -1228,8 +1236,7 @@ exaFillRegionTiled (DrawablePtr	pDrawabl
 
 		    (*pExaScr->info->Copy) (pPixmap,
 					    tileX + tileXoff, tileY + tileYoff,
-					    dstX + xoff, dstY + yoff,
-					    w, h);
+					    dstX, dstY, w, h);
 		    dstX += w;
 		    tileX = 0;
 		}
@@ -1240,16 +1247,20 @@ exaFillRegionTiled (DrawablePtr	pDrawabl
 	}
 	(*pExaScr->info->DoneCopy) (pPixmap);
 	exaMarkSync(pDrawable->pScreen);
+	REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
 	return TRUE;
     }
 
 fallback:
-    if (alu != GXcopy || planemask != FB_ALLONES)
+    if (alu != GXcopy || !EXA_PM_IS_SOLID(pDrawable, planemask)) {
+	REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
 	return FALSE;
+    }
     EXA_FALLBACK(("from %p to %p (%c,%c)\n", pTile, pDrawable,
 		  exaDrawableLocation(&pTile->drawable),
 		  exaDrawableLocation(pDrawable)));
     exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
+    REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
     exaPrepareAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC);
     fbFillRegionTiled (pDrawable, pRegion, pTile);
     exaFinishAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC);
diff-tree fac68373b2d5a758a852d58cc91329dba721b221 (from fc18cbbc5c1eb1787c116eb3c4b6f3d9cf5f219a)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Fri Aug 31 16:59:28 2007 +0200

    EXA: Use exaShmPutImage for pushing glyphs to scratch pixmap in exaGlyphs.

diff --git a/exa/exa_accel.c b/exa/exa_accel.c
index 136fca2..e44ce60 100644
--- a/exa/exa_accel.c
+++ b/exa/exa_accel.c
@@ -287,7 +287,7 @@ exaDoShmPutImage(DrawablePtr pDrawable, 
  * We also need to set the pending damage to ensure correct migration in all
  * cases.
  */
-static void
+void
 exaShmPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, unsigned int format,
 	       int w, int h, int sx, int sy, int sw, int sh, int dx, int dy,
 	       char *data)
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index a6ac921..02371d7 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -300,6 +300,11 @@ void
 exaPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what);
 
 void
+exaShmPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, unsigned int format,
+	       int w, int h, int sx, int sy, int sw, int sh, int dx, int dy,
+	       char *data);
+
+void
 exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
 	     unsigned int format, unsigned long planeMask, char *d);
 
diff --git a/exa/exa_render.c b/exa/exa_render.c
index 9df795f..943a4c8 100644
--- a/exa/exa_render.c
+++ b/exa/exa_render.c
@@ -1282,6 +1282,15 @@ exaGlyphs (CARD8	op,
 		    pScratchPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
 		}
 
+#ifdef MITSHM
+		if (pExaScr->info->PrepareComposite)
+		    exaShmPutImage(&pPixmap->drawable, pGC,
+				   pPixmap->drawable.depth, ZPixmap,
+				   glyph->info.width, glyph->info.height, 0, 0,
+				   glyph->info.width, glyph->info.height, 0, 0,
+				   glyphdata);
+		else
+#endif
 		exaCopyArea (&pScratchPixmap->drawable, &pPixmap->drawable, pGC,
 			     0, 0, glyph->info.width, glyph->info.height, 0, 0);
 	    }
diff-tree fc18cbbc5c1eb1787c116eb3c4b6f3d9cf5f219a (from bf8686b002f2965fc8873f46beeadb83cec7d788)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Thu Aug 30 13:59:07 2007 +0200

    EXA: exa(Shm)PutImage improvements.
    
    Improve exaShmPutImage performance and reuse its core in exaPutImage as it
    seems faster than the previous code when the driver doesn't provide an
    UploadToScreen hook.
    
    Make sure all damage records are notified of the damage incurred by actual
    ShmPutImage calls.
    
    Remove superfluous manual damage tracking for actual PutImage calls.

diff --git a/exa/exa_accel.c b/exa/exa_accel.c
index df6a62d..136fca2 100644
--- a/exa/exa_accel.c
+++ b/exa/exa_accel.c
@@ -139,10 +139,11 @@ exaFillSpans(DrawablePtr pDrawable, GCPt
 
 static Bool
 exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
-	       int w, int h, int leftPad, int format, char *bits, int src_stride)
+	       int w, int h, int format, char *bits, int src_stride)
 {
     ExaScreenPriv (pDrawable->pScreen);
-    PixmapPtr pPix;
+    PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
+    ExaPixmapPriv(pPix);
     ExaMigrationRec pixmaps[1];
     RegionPtr pClip;
     BoxPtr pbox;
@@ -151,26 +152,28 @@ exaDoPutImage (DrawablePtr pDrawable, GC
     int bpp = pDrawable->bitsPerPixel;
     Bool access_prepared = FALSE;
 
-    pixmaps[0].as_dst = TRUE;
-    pixmaps[0].as_src = FALSE;
-    pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
-    pixmaps[0].pReg = NULL;
-
     /* Don't bother with under 8bpp, XYPixmaps. */
     if (format != ZPixmap || bpp < 8)
-	goto fallback;
+	return FALSE;
 
     /* Only accelerate copies: no rop or planemask. */
     if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
-	goto fallback;
+	return FALSE;
 
     if (pExaScr->swappedOut)
-	goto fallback;
+	return FALSE;
 
+    pixmaps[0].as_dst = TRUE;
+    pixmaps[0].as_src = FALSE;
+    pixmaps[0].pPix = pPix;
+    pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage);
     exaDoMigration (pixmaps, 1, TRUE);
 
     pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
 
+    if (!pPix || !pExaScr->info->UploadToScreen)
+	return FALSE;
+
     x += pDrawable->x;
     y += pDrawable->y;
 
@@ -199,10 +202,8 @@ exaDoPutImage (DrawablePtr pDrawable, GC
 	    continue;
 
 	src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
-	ok = (pPix && pExaScr->info->UploadToScreen) ?
-	     pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff,
-					   x2 - x1, y2 - y1, src, src_stride) :
-	     FALSE;
+	ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff,
+					   x2 - x1, y2 - y1, src, src_stride);
 	/* If we fail to accelerate the upload, fall back to using unaccelerated
 	 * fb calls.
 	 */
@@ -231,8 +232,6 @@ exaDoPutImage (DrawablePtr pDrawable, GC
 		      y2 - y1,
 		      GXcopy, FB_ALLONES, dstBpp);
 	}
-
-	exaPixmapDirty(pixmaps[0].pPix, x1 + xoff, y1 + yoff, x2 + xoff, y2 + yoff);
     }
 
     if (access_prepared)
@@ -241,45 +240,110 @@ exaDoPutImage (DrawablePtr pDrawable, GC
 	exaMarkSync(pDrawable->pScreen);
 
     return TRUE;
-
-fallback:
-    return FALSE;
 }
 
-static void
-exaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
-	     int w, int h, int leftPad, int format, char *bits)
+#ifdef MITSHM
+
+static Bool
+exaDoShmPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
+		 unsigned int format, int w, int h, int sx, int sy, int sw,
+		 int sh, int dx, int dy, char *data)
 {
-    if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits,
-		       PixmapBytePad(w, pDrawable->depth)))
-	ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
-			 bits);
-}
+    int src_stride = PixmapBytePad(w, depth);
 
-#ifdef MITSHM
+    if (exaDoPutImage(pDrawable, pGC, depth, dx, dy, sw, sh, format, data +
+		      sy * src_stride + sx * BitsPerPixel(depth) / 8,
+		      src_stride))
+	return TRUE;
+
+    if (format == ZPixmap)
+    {
+	PixmapPtr pPixmap;
+
+	pPixmap = GetScratchPixmapHeader(pDrawable->pScreen, w, h, depth,
+		BitsPerPixel(depth), PixmapBytePad(w, depth), (pointer)data);
+	if (!pPixmap)
+	    return FALSE;
 
+	if (exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle,
+				  pGC->alu))
+	    exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
+	else
+	    ExaDoPrepareAccess (pDrawable, EXA_PREPARE_DEST);
+	fbCopyArea((DrawablePtr)pPixmap, pDrawable, pGC, sx, sy, sw, sh, dx, dy);
+	exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
+
+	FreeScratchPixmapHeader(pPixmap);
+
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
+/* The actual ShmPutImage isn't wrapped by the damage layer, so we need to
+ * inform any interested parties of the damage incurred to the drawable.
+ *
+ * We also need to set the pending damage to ensure correct migration in all
+ * cases.
+ */
 static void
 exaShmPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, unsigned int format,
 	       int w, int h, int sx, int sy, int sw, int sh, int dx, int dy,
 	       char *data)
 {
-    int src_stride = PixmapBytePad(w, depth);
+    PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
+    ExaPixmapPriv(pPixmap);
+    BoxRec box = { .x1 = pDrawable->x + dx, .y1 = pDrawable->y + dy,
+		   .x2 = pDrawable->x + dx + sw, .y2 = pDrawable->y + dy + sh };
+    RegionRec region;
+    int xoff, yoff;
+    RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
 
-    if (exaDoPutImage(pDrawable, pGC, depth, dx, dy, sw, sh, 0, format, data +
-		      sy * src_stride + sx * BitsPerPixel(depth) / 8,
-		      src_stride))
-	return;
+    REGION_INIT(pScreen, &region, &box, 1);
 
-    exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
-    fbShmPutImage(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy,
-		  data);
-    exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
+    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
+
+    REGION_TRANSLATE(pScreen, &region, xoff, yoff);
+    REGION_UNION(pScreen, pending_damage, pending_damage, &region);
+
+    if (!exaDoShmPutImage(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh,
+			  dx, dy, data)) {
+	if (exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle,
+				  pGC->alu))
+	    exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
+	else
+	    ExaDoPrepareAccess (pDrawable, EXA_PREPARE_DEST);
+	fbShmPutImage(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy,
+		      data);
+	exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
+    }
+
+    REGION_TRANSLATE(pScreen, &region, -xoff, -yoff);
+    DamageDamageRegion(pDrawable, &region);
+
+    REGION_UNINIT(pScreen, &region);
 }
 
 ShmFuncs exaShmFuncs = { NULL, exaShmPutImage };
 
 #endif
 
+static void
+exaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
+	     int w, int h, int leftPad, int format, char *bits)
+{
+#ifdef MITSHM
+    if (!exaDoShmPutImage(pDrawable, pGC, depth, format, w, h, 0, 0, w, h, x, y,
+			  bits))
+#else
+    if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, format, bits,
+		       PixmapBytePad(w, pDrawable->depth)))
+#endif
+	ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
+			 bits);
+}
+
 static Bool inline
 exaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
 		   GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index 8e51f5d..a6ac921 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -279,6 +279,16 @@ CARD32
 exaGetPixmapFirstPixel (PixmapPtr pPixmap); 
 
 /* exa_accel.c */
+
+static _X_INLINE Bool
+exaGCReadsDestination(DrawablePtr pDrawable, unsigned long planemask,
+		      unsigned int fillStyle, unsigned char alu)
+{
+    return ((alu != GXcopy && alu != GXclear &&alu != GXset &&
+	     alu != GXcopyInverted) || fillStyle == FillStippled ||
+	    !EXA_PM_IS_SOLID(pDrawable, planemask));
+}
+
 void
 exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc);
 
diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c
index 8fb7b52..f4d453e 100644
--- a/exa/exa_unaccel.c
+++ b/exa/exa_unaccel.c
@@ -97,14 +97,14 @@ ExaCheckPutImage (DrawablePtr pDrawable,
 		 int x, int y, int w, int h, int leftPad, int format,
 		 char *bits)
 {
-    PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
-    int xoff, yoff;
-
     EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
-    exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
+    if (exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle,
+			      pGC->alu))
+	exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
+    else
+	ExaDoPrepareAccess (pDrawable, EXA_PREPARE_DEST);
     fbPutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits);
     exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
-    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
 }
 
 RegionPtr
diff-tree bf8686b002f2965fc8873f46beeadb83cec7d788 (from dbf000df439e99371d65a3b4e90be7f7d123d467)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Thu Aug 30 13:54:18 2007 +0200

    EXA: exaGetImage improvements.
    
    Use the new migration infrastructure to cache FB bits we need in the system
    copy, for the benefit of repeated calls.

diff --git a/exa/exa_accel.c b/exa/exa_accel.c
index 36815e2..df6a62d 100644
--- a/exa/exa_accel.c
+++ b/exa/exa_accel.c
@@ -1247,22 +1247,43 @@ exaPaintWindow(WindowPtr pWin, RegionPtr
  * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
  *
  * This is probably the only case we actually care about.  The rest fall through
- * to migration and ExaCheckGetImage, which hopefully will result in migration
- * pushing the pixmap out of framebuffer.
+ * to migration and fbGetImage, which hopefully will result in migration pushing
+ * the pixmap out of framebuffer.
  */
 void
 exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
 	     unsigned int format, unsigned long planeMask, char *d)
 {
     ExaScreenPriv (pDrawable->pScreen);
+    ExaMigrationRec pixmaps[1];
+    BoxRec Box;
+    RegionRec Reg;
     PixmapPtr pPix;
     int xoff, yoff;
     Bool ok;
 
-    if (pExaScr->swappedOut || (w == 1 && h == 1))
+    if (pExaScr->swappedOut)
 	goto fallback;
 
-    if (pExaScr->info->DownloadFromScreen == NULL)
+    pixmaps[0].as_dst = FALSE;
+    pixmaps[0].as_src = TRUE;
+    pixmaps[0].pPix = pPix = exaGetDrawablePixmap (pDrawable);
+    pixmaps[0].pReg = &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;
+
+    REGION_INIT(pScreen, &Reg, &Box, 1);
+
+    exaDoMigration(pixmaps, 1, FALSE);
+
+    pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
+
+    if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL)
 	goto fallback;
 
     /* Only cover the ZPixmap, solid copy case. */
@@ -1275,20 +1296,22 @@ exaGetImage (DrawablePtr pDrawable, int 
     if (pDrawable->bitsPerPixel < 8)
 	goto fallback;
 
-    pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
-    if (pPix == NULL)
-	goto fallback;
-
-    xoff += pDrawable->x;
-    yoff += pDrawable->y;
-
-    ok = pExaScr->info->DownloadFromScreen(pPix, x + xoff, y + yoff, w, h, d,
+    ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff,
+					   pDrawable->y + y + yoff, w, h, d,
 					   PixmapBytePad(w, pDrawable->depth));
     if (ok) {
 	exaWaitSync(pDrawable->pScreen);
-	return;
+	goto out;
     }
 
 fallback:
-    ExaCheckGetImage (pDrawable, x, y, w, h, format, planeMask, d);
+    EXA_FALLBACK(("from %p (%c)\n", pDrawable,
+		  exaDrawableLocation(pDrawable)));
+
+    exaPrepareAccessReg (pDrawable, EXA_PREPARE_SRC, &Reg);
+    fbGetImage (pDrawable, x, y, w, h, format, planeMask, d);
+    exaFinishAccess (pDrawable, EXA_PREPARE_SRC);
+
+out:
+    REGION_UNINIT(pScreen, &Reg);
 }
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index a8bdbd6..8e51f5d 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -265,12 +265,6 @@ ExaCheckPushPixels (GCPtr pGC, PixmapPtr
 		   int w, int h, int x, int y);
 
 void
-ExaCheckGetImage (DrawablePtr pDrawable,
-		 int x, int y, int w, int h,
-		 unsigned int format, unsigned long planeMask,
-		 char *d);
-
-void
 ExaCheckGetSpans (DrawablePtr pDrawable,
 		 int wMax,
 		 DDXPointPtr ppt,
diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c
index 970c2cb..8fb7b52 100644
--- a/exa/exa_unaccel.c
+++ b/exa/exa_unaccel.c
@@ -265,19 +265,6 @@ ExaCheckPushPixels (GCPtr pGC, PixmapPtr
 }
 
 void
-ExaCheckGetImage (DrawablePtr pDrawable,
-		 int x, int y, int w, int h,
-		 unsigned int format, unsigned long planeMask,
-		 char *d)
-{
-    EXA_FALLBACK(("from %p (%c)\n", pDrawable,
-		  exaDrawableLocation(pDrawable)));
-    exaPrepareAccess (pDrawable, EXA_PREPARE_SRC);
-    fbGetImage (pDrawable, x, y, w, h, format, planeMask, d);
-    exaFinishAccess (pDrawable, EXA_PREPARE_SRC);
-}
-
-void
 ExaCheckGetSpans (DrawablePtr pDrawable,
 		 int wMax,
 		 DDXPointPtr ppt,
diff-tree dbf000df439e99371d65a3b4e90be7f7d123d467 (from 23da2c0da3817300272933de979572da0feaa698)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Thu Aug 30 13:50:42 2007 +0200

    EXA: Remove superfluous manual damage tracking.
    
    These should all be covered by damage wrappers.

diff --git a/exa/exa_accel.c b/exa/exa_accel.c
index 4cae198..36815e2 100644
--- a/exa/exa_accel.c
+++ b/exa/exa_accel.c
@@ -394,8 +394,6 @@ exaCopyNtoNTwoDir (DrawablePtr pSrcDrawa
 				       dst_off_y + pbox->y1 + i,
 				       pbox->x2 - pbox->x1, 1);
 	}
-	exaPixmapDirty(pDstPixmap, dst_off_x + pbox->x1, dst_off_y + pbox->y1,
-		       dst_off_x + pbox->x2, dst_off_y + pbox->y2);
     }
     if (dirsetup != 0)
 	pExaScr->info->DoneCopy(pDstPixmap);
@@ -421,7 +419,6 @@ exaCopyNtoN (DrawablePtr    pSrcDrawable
     int	    src_off_x, src_off_y;
     int	    dst_off_x, dst_off_y;
     ExaMigrationRec pixmaps[2];
-    Bool fallback = FALSE;
 
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = FALSE;
@@ -441,18 +438,18 @@ exaCopyNtoN (DrawablePtr    pSrcDrawable
 	pDstPixmap->drawable.width > pExaScr->info->maxX ||
 	pDstPixmap->drawable.height > pExaScr->info->maxY)
     {
-	fallback = TRUE;
+	goto fallback;
     } else {
 	exaDoMigration (pixmaps, 2, TRUE);
     }
 
     /* Mixed directions must be handled specially if the card is lame */
-    if (!fallback && (pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) &&
+    if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) &&
 	reverse != upsidedown) {
 	if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
 			       dx, dy))
 	    return;
-	fallback = TRUE;
+	goto fallback;
     }
 
     pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
@@ -461,43 +458,40 @@ exaCopyNtoN (DrawablePtr    pSrcDrawable
     exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
     exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);
 
-    if (fallback || !exaPixmapIsOffscreen(pSrcPixmap) ||
+    if (!exaPixmapIsOffscreen(pSrcPixmap) ||
 	!exaPixmapIsOffscreen(pDstPixmap) ||
 	!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1,
 					upsidedown ? -1 : 1,
 					pGC ? pGC->alu : GXcopy,
 					pGC ? pGC->planemask : FB_ALLONES)) {
-	fallback = TRUE;
-	EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable,
-		      exaDrawableLocation(pSrcDrawable),
-		      exaDrawableLocation(pDstDrawable)));
-	exaPrepareAccessReg (pDstDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
-	exaPrepareAccess (pSrcDrawable, EXA_PREPARE_SRC);
-	fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC,
-		    pbox, nbox, dx, dy, reverse, upsidedown,
-		    bitplane, closure);
-	exaFinishAccess (pSrcDrawable, EXA_PREPARE_SRC);
-	exaFinishAccess (pDstDrawable, EXA_PREPARE_DEST);
+	goto fallback;
     }
 
     while (nbox--)
     {
-	if (!fallback)
-	    (*pExaScr->info->Copy) (pDstPixmap,
-				    pbox->x1 + dx + src_off_x,
-				    pbox->y1 + dy + src_off_y,
-				    pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
-				    pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
-	exaPixmapDirty (pDstPixmap, pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
-			pbox->x2  + dst_off_x, pbox->y2 + dst_off_y);
+	(*pExaScr->info->Copy) (pDstPixmap,
+				pbox->x1 + dx + src_off_x,
+				pbox->y1 + dy + src_off_y,
+				pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
+				pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
 	pbox++;
     }
 
-    if (fallback)
-	return;
-
     (*pExaScr->info->DoneCopy) (pDstPixmap);
     exaMarkSync (pDstDrawable->pScreen);
+
+    return;
+
+fallback:
+    EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable,
+		  exaDrawableLocation(pSrcDrawable),
+		  exaDrawableLocation(pDstDrawable)));
+    exaPrepareAccessReg (pDstDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
+    exaPrepareAccess (pSrcDrawable, EXA_PREPARE_SRC);
+    fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse,
+		upsidedown, bitplane, closure);
+    exaFinishAccess (pSrcDrawable, EXA_PREPARE_SRC);
+    exaFinishAccess (pDstDrawable, EXA_PREPARE_DEST);
 }
 
 RegionPtr
@@ -1204,12 +1198,8 @@ void
 exaPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what)
 {
     ExaScreenPriv (pWin->drawable.pScreen);
-    PixmapPtr pPixmap = exaGetDrawablePixmap((DrawablePtr)pWin);
-    int xoff, yoff;
-    BoxPtr pBox;
-    int nbox = REGION_NUM_RECTS(pRegion);
 
-    if (!nbox)
+    if (REGION_NIL(pRegion))
 	return;
 
     if (!pExaScr->swappedOut) {
@@ -1230,39 +1220,27 @@ exaPaintWindow(WindowPtr pWin, RegionPtr
             case BackgroundPixel:
 		exaFillRegionSolid((DrawablePtr)pWin, pRegion, pWin->background.pixel,
 				   FB_ALLONES, GXcopy);
-                goto damage;
+                return;
             case BackgroundPixmap:
                 exaFillRegionTiled((DrawablePtr)pWin, pRegion, pWin->background.pixmap,
 				   &zeros, FB_ALLONES, GXcopy);
-                goto damage;
+                return;
             }
             break;
         case PW_BORDER:
             if (pWin->borderIsPixel) {
                 exaFillRegionSolid((DrawablePtr)pWin, pRegion, pWin->border.pixel,
 				   FB_ALLONES, GXcopy);
-                goto damage;
+                return;
             } else {
                 exaFillRegionTiled((DrawablePtr)pWin, pRegion, pWin->border.pixmap,
 				   &zeros, FB_ALLONES, GXcopy);
-                goto damage;
+                return;
             }
             break;
         }
     }
     ExaCheckPaintWindow (pWin, pRegion, what);
-
-damage:
-    exaGetDrawableDeltas((DrawablePtr)pWin, pPixmap, &xoff, &yoff);
-
-    pBox = REGION_RECTS(pRegion);
-
-    while (nbox--)
-    {
-	exaPixmapDirty (pPixmap, pBox->x1 + xoff, pBox->y1 + yoff,
-			pBox->x2 + xoff, pBox->y2 + yoff);
-	pBox++;
-    }
 }
 
 /**
diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c
index 24d5e3f..970c2cb 100644
--- a/exa/exa_unaccel.c
+++ b/exa/exa_unaccel.c
@@ -105,7 +105,6 @@ ExaCheckPutImage (DrawablePtr pDrawable,
     fbPutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits);
     exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
     exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
-    exaPixmapDirty(pPixmap, x + xoff, y + yoff, x + xoff + w, y + yoff + h);
 }
 
 RegionPtr
diff-tree 23da2c0da3817300272933de979572da0feaa698 (from 062f66818d7d125fada919b9f93b23d37b01a23f)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Thu Aug 30 13:48:03 2007 +0200

    EXA: RENDER improvements.
    
    Exclude bits that will be overwritten from migration.
    
    Use exaGlyphs even when Composite can't be accelerated, to avoid PolyFillRect
    roundtrip via offscreen memory.
    
    Initialize mask pixmap in exaGlyphs in FB in addition to system if the driver
    provides Composite hooks to avoid migration overhead.
    
    Remove manual damage tracking where superfluous.

diff --git a/exa/exa.c b/exa/exa.c
index ad8d967..458272d 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -285,15 +285,19 @@ static Bool
 exaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth,
 		      int bitsPerPixel, int devKind, pointer pPixData)
 {
-    ExaScreenPriv(pPixmap->drawable.pScreen);
-    ExaPixmapPriv(pPixmap);
+    ExaScreenPrivPtr pExaScr;
+    ExaPixmapPrivPtr pExaPixmap;
 
     if (!pPixmap)
         return FALSE;
 
+    pExaPixmap = ExaGetPixmapPriv(pPixmap);
+
     if (pExaPixmap)
 	pExaPixmap->sys_ptr = pPixData;
 
+    pExaScr = ExaGetScreenPriv(pPixmap->drawable.pScreen);
+
     return pExaScr->SavedModifyPixmapHeader(pPixmap, width, height, depth,
 					    bitsPerPixel, devKind, pPixData);
 }
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index db5bd02..a8bdbd6 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -384,6 +384,9 @@ exaCopyNtoN (DrawablePtr    pSrcDrawable
 	     void	    *closure);
 
 /* exa_render.c */
+Bool
+exaOpReadsDestination (CARD8 op);
+
 void
 exaComposite(CARD8	op,
 	     PicturePtr pSrc,
diff --git a/exa/exa_render.c b/exa/exa_render.c
index 3cfa81e..9df795f 100644
--- a/exa/exa_render.c
+++ b/exa/exa_render.c
@@ -111,7 +111,7 @@ exaPrintCompositeFallback(CARD8 op,
 }
 #endif /* DEBUG_TRACE_FALL */
 
-static Bool
+Bool
 exaOpReadsDestination (CARD8 op)
 {
     /* FALSE (does not read destination) is the list of ops in the protocol
@@ -261,17 +261,21 @@ exaTryDriverSolidFill(PicturePtr	pSrc,
 				   width, height))
 	return 1;
 
+    pDstPix = exaGetDrawablePixmap (pDst->pDrawable);
+    exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
+
+    REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
+
     pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable);
     pixel = exaGetPixmapFirstPixel (pSrcPix);
 
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = FALSE;
-    pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
-    pixmaps[0].pReg = NULL;
+    pixmaps[0].pPix = pDstPix;
+    pixmaps[0].pReg = &region;
     exaDoMigration(pixmaps, 1, TRUE);
 
-    pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
-    if (!pDstPix) {
+    if (!exaPixmapIsOffscreen(pDstPix)) {
 	REGION_UNINIT(pDst->pDrawable->pScreen, &region);
 	return 0;
     }
@@ -301,9 +305,7 @@ exaTryDriverSolidFill(PicturePtr	pSrc,
 
     while (nbox--)
     {
-	(*pExaScr->info->Solid) (pDstPix,
-				 pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
-				 pbox->x2 + dst_off_x, pbox->y2 + dst_off_y);
+	(*pExaScr->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, pbox->y2);
 	pbox++;
     }
 
@@ -367,22 +369,26 @@ exaTryDriverComposite(CARD8		op,
     xSrc += pSrc->pDrawable->x;
     ySrc += pSrc->pDrawable->y;
 
-    if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
-				   xSrc, ySrc, xMask, yMask, xDst, yDst,
-				   width, height))
-	return 1;
-
     if (pExaScr->info->CheckComposite &&
 	!(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst))
     {
-	REGION_UNINIT(pDst->pDrawable->pScreen, &region);
 	return -1;
     }
 
+    if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
+				   xSrc, ySrc, xMask, yMask, xDst, yDst,
+				   width, height))
+	return 1;
+
+    pDstPix = exaGetDrawablePixmap (pDst->pDrawable);
+    exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
+
+    REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
+
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = exaOpReadsDestination(op);
-    pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
-    pixmaps[0].pReg = NULL;
+    pixmaps[0].pPix = pDstPix;
+    pixmaps[0].pReg = pixmaps[0].as_src ? NULL : &region;
     pixmaps[1].as_dst = FALSE;
     pixmaps[1].as_src = TRUE;
     pixmaps[1].pPix = exaGetDrawablePixmap (pSrc->pDrawable);
@@ -401,9 +407,8 @@ exaTryDriverComposite(CARD8		op,
     if (pMask)
 	pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x,
 					  &mask_off_y);
-    pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
 
-    if (!pDstPix) {
+    if (!exaPixmapIsOffscreen(pDstPix)) {
 	REGION_UNINIT(pDst->pDrawable->pScreen, &region);
 	return 0;
     }
@@ -433,21 +438,21 @@ exaTryDriverComposite(CARD8		op,
     nbox = REGION_NUM_RECTS(&region);
     pbox = REGION_RECTS(&region);
 
-    xMask -= xDst;
-    yMask -= yDst;
+    xMask = xMask + mask_off_x - xDst - dst_off_x;
+    yMask = yMask + mask_off_y - yDst - dst_off_y;
 
-    xSrc -= xDst;
-    ySrc -= yDst;
+    xSrc = xSrc + src_off_x - xDst - dst_off_x;
+    ySrc = ySrc + src_off_y - yDst - dst_off_y;
 
     while (nbox--)
     {
 	(*pExaScr->info->Composite) (pDstPix,
-				     pbox->x1 + xSrc + src_off_x,
-				     pbox->y1 + ySrc + src_off_y,
-				     pbox->x1 + xMask + mask_off_x,
-				     pbox->y1 + yMask + mask_off_y,
-				     pbox->x1 + dst_off_x,
-				     pbox->y1 + dst_off_y,
+				     pbox->x1 + xSrc,
+				     pbox->y1 + ySrc,
+				     pbox->x1 + xMask,
+				     pbox->y1 + yMask,
+				     pbox->x1,
+				     pbox->y1,
 				     pbox->x2 - pbox->x1,
 				     pbox->y2 - pbox->y1);
 	pbox++;
@@ -523,9 +528,6 @@ exaTryMagicTwoPassCompositeHelper(CARD8 
 				  CARD16 height)
 {
     ExaScreenPriv (pDst->pDrawable->pScreen);
-    DrawablePtr pDstDraw = pDst->pDrawable;
-    PixmapPtr pDstPixmap = exaGetDrawablePixmap(pDstDraw);
-    int xoff, yoff;
 
     assert(op == PictOpOver);
 
@@ -544,12 +546,6 @@ exaTryMagicTwoPassCompositeHelper(CARD8 
     exaComposite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
 		 xDst, yDst, width, height);
 
-    exaGetDrawableDeltas(pDstDraw, pDstPixmap, &xoff, &yoff);
-    xoff += pDstDraw->x;
-    yoff += pDstDraw->y;
-    exaPixmapDirty(pDstPixmap, xDst + xoff, yDst + yoff, xDst + xoff + width,
-		   yDst + yoff + height);
-
     /* Then, add in the source value times the destination alpha factors (1.0).
      */
     exaComposite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
@@ -576,31 +572,8 @@ exaComposite(CARD8	op,
     int ret = -1;
     Bool saveSrcRepeat = pSrc->repeat;
     Bool saveMaskRepeat = pMask ? pMask->repeat : 0;
-    ExaMigrationRec pixmaps[3];
-    int npixmaps = 1;
     PixmapPtr pSrcPixmap = NULL;
-
-    pixmaps[0].as_dst = TRUE;
-    pixmaps[0].as_src = exaOpReadsDestination(op);
-    pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
-    pixmaps[0].pReg = NULL;
-
-    if (pSrc->pDrawable) {
-	pSrcPixmap = exaGetDrawablePixmap (pSrc->pDrawable);
-	pixmaps[npixmaps].as_dst = FALSE;
-	pixmaps[npixmaps].as_src = TRUE;
-	pixmaps[npixmaps].pPix = pSrcPixmap;
-	pixmaps[npixmaps].pReg = NULL;
-	npixmaps++;
-    }
-
-    if (pMask && pMask->pDrawable) {
-	pixmaps[npixmaps].as_dst = FALSE;
-	pixmaps[npixmaps].as_src = TRUE;
-	pixmaps[npixmaps].pPix = exaGetDrawablePixmap (pMask->pDrawable);
-	pixmaps[npixmaps].pReg = NULL;
-	npixmaps++;
-    }
+    RegionRec region;
 
     /* We currently don't support acceleration of gradients, or other pictures
      * with a NULL pDrawable.
@@ -638,8 +611,6 @@ exaComposite(CARD8	op,
 	    }
 	    else if (pSrcPixmap && !pSrc->repeat && !pSrc->transform)
 	    {
-		RegionRec	region;
-
 		xDst += pDst->pDrawable->x;
 		yDst += pDst->pDrawable->y;
 		xSrc += pSrc->pDrawable->x;
@@ -661,7 +632,6 @@ exaComposite(CARD8	op,
 	    else if (pSrcPixmap && !pSrc->transform &&
 		     pSrc->repeatType == RepeatNormal)
 	    {
-		RegionRec region;
 		DDXPointRec srcOrg;
 
 		/* Let's see if the driver can do the repeat in one go */
@@ -1092,6 +1062,9 @@ exaGlyphsIntersect(int nlist, GlyphListP
  * issue is that miGlyphs' use of ModifyPixmapHeader makes it impossible to
  * migrate these pixmaps.  So, instead we create a pixmap at the beginning of
  * the loop and upload each glyph into the pixmap before compositing.
+ *
+ * This is now used even when Composite can't be accelerated for better
+ * migration control.
  */
 void
 exaGlyphs (CARD8	op,
@@ -1108,11 +1081,10 @@ exaGlyphs (CARD8	op,
     PixmapPtr	pPixmap = NULL;
     PicturePtr	pPicture;
     PixmapPtr   pMaskPixmap = NULL;
-    PixmapPtr   pDstPixmap = exaGetDrawablePixmap(pDst->pDrawable);
     PicturePtr  pMask;
     ScreenPtr   pScreen = pDst->pDrawable->pScreen;
     int		width = 0, height = 0;
-    int		x, y, x1, y1, xoff, yoff;
+    int		x, y, x1, y1;
     int		xDst = list->xOff, yDst = list->yOff;
     int		n;
     int		error;
@@ -1140,16 +1112,6 @@ exaGlyphs (CARD8	op,
 	}
     }
 
-    /* If the driver doesn't support accelerated composite, there's no point in
-     * going to this extra work.  Assume that any driver that supports Composite
-     * will be able to support component alpha using the two-pass helper.
-     */
-    if (!pExaScr->info->PrepareComposite)
-    {
-	miGlyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
-	return;
-    }
-
     if (maskFormat)
     {
 	GCPtr	    pGC;
@@ -1186,8 +1148,11 @@ exaGlyphs (CARD8	op,
 	rect.y = 0;
 	rect.width = width;
 	rect.height = height;
-	(*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
-	exaPixmapDirty(pMaskPixmap, 0, 0, width, height);
+	ExaCheckPolyFillRect (&pMaskPixmap->drawable, pGC, 1, &rect);
+	if (pExaScr->info->PrepareComposite)
+	    (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
+	else
+	    exaPixmapDirty(pMaskPixmap, 0, 0, width, height);
 	FreeScratchGC (pGC);
 	x = -extents.x1;
 	y = -extents.y1;
@@ -1199,8 +1164,6 @@ exaGlyphs (CARD8	op,
 	y = 0;
     }
 
-    exaGetDrawableDeltas(pDst->pDrawable, pDstPixmap, &xoff, &yoff);
-
     while (nlist--)
     {
 	GCPtr pGC = NULL;
@@ -1339,10 +1302,6 @@ exaGlyphs (CARD8	op,
 			      xSrc + x1 - xDst, ySrc + y1 - yDst,
 			      0, 0, x1, y1, glyph->info.width,
 			      glyph->info.height);
-		x1 += pDst->pDrawable->x + xoff;
-		y1 += pDst->pDrawable->y + yoff;
-		exaPixmapDirty(pDstPixmap, x1, y1, x1 + glyph->info.width,
-			       y1 + glyph->info.height);
 	    }
 nextglyph:
 	    x += glyph->info.xOff;
diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c
index fbc48dd..24d5e3f 100644
--- a/exa/exa_unaccel.c
+++ b/exa/exa_unaccel.c
@@ -23,6 +23,10 @@
 
 #include "exa_priv.h"
 
+#ifdef RENDER
+#include "mipict.h"
+#endif
+
 /*
  * These functions wrap the low-level fb rendering functions and
  * synchronize framebuffer/accelerated drawing by stalling until
@@ -319,9 +323,30 @@ ExaCheckComposite (CARD8      op,
                    CARD16     width,
                    CARD16     height)
 {
+    RegionRec region;
+    int xoff, yoff;
+
+    REGION_NULL(pScreen, &region);
+
+    if (!exaOpReadsDestination(op)) {
+	if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
+				       xSrc, ySrc, xMask, yMask, xDst, yDst,
+				       width, height))
+	    return;
+
+	exaGetDrawableDeltas (pDst->pDrawable,
+			      exaGetDrawablePixmap(pDst->pDrawable),
+			      &xoff, &yoff);
+
+	REGION_TRANSLATE(pScreen, &region, xoff, yoff);
+
+	exaPrepareAccessReg (pDst->pDrawable, EXA_PREPARE_DEST, &region);
+    } else
+	exaPrepareAccess (pDst->pDrawable, EXA_PREPARE_DEST);
+
     EXA_FALLBACK(("from picts %p/%p to pict %p\n",
 		 pSrc, pMask, pDst));
-    exaPrepareAccess (pDst->pDrawable, EXA_PREPARE_DEST);
+
     if (pSrc->pDrawable != NULL)
 	exaPrepareAccess (pSrc->pDrawable, EXA_PREPARE_SRC);
     if (pMask && pMask->pDrawable != NULL)
@@ -343,6 +368,8 @@ ExaCheckComposite (CARD8      op,
     if (pSrc->pDrawable != NULL)
 	exaFinishAccess (pSrc->pDrawable, EXA_PREPARE_SRC);
     exaFinishAccess (pDst->pDrawable, EXA_PREPARE_DEST);
+
+    REGION_UNINIT(pScreen, &region);
 }
 
 /**
diff-tree 062f66818d7d125fada919b9f93b23d37b01a23f (from eec06c0074f9744d524b27a29db65bba3e221229)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Thu Aug 30 13:44:20 2007 +0200

    EXA: Improvements for 1x1 pixmaps.
    
    Initialize system and FB copy in exaFillRegionSolid and adapt
    exaGetPixmapFirstPixel to the new migration infrastructure.
    
    This should mostly eliminate migration overhead for these, whether they are
    used for acceleration or fallbacks.

diff --git a/exa/exa_accel.c b/exa/exa_accel.c
index e9ca472..4cae198 100644
--- a/exa/exa_accel.c
+++ b/exa/exa_accel.c
@@ -1012,8 +1012,6 @@ exaFillRegionSolid (DrawablePtr	pDrawabl
     PixmapPtr pPixmap;
     int xoff, yoff;
     ExaMigrationRec pixmaps[1];
-    int nbox = REGION_NUM_RECTS (pRegion);
-    BoxPtr pBox = REGION_RECTS (pRegion);
 
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = FALSE;
@@ -1031,15 +1029,43 @@ exaFillRegionSolid (DrawablePtr	pDrawabl
     if ((pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) &&
 	(*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel))
     {
+	int nbox;
+	BoxPtr pBox;
+
+	REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);
+
+	nbox = REGION_NUM_RECTS (pRegion);
+	pBox = REGION_RECTS (pRegion);
+
 	while (nbox--)
 	{
-	    (*pExaScr->info->Solid) (pPixmap,
-				     pBox->x1 + xoff, pBox->y1 + yoff,
-				     pBox->x2 + xoff, pBox->y2 + yoff);
+	    (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2,
+				     pBox->y2);
 	    pBox++;
 	}
 	(*pExaScr->info->DoneSolid) (pPixmap);
 	exaMarkSync(pDrawable->pScreen);
+
+	if (pDrawable->width == 1 && pDrawable->height == 1 &&
+	    pDrawable->bitsPerPixel != 24) {
+	    ExaPixmapPriv(pPixmap);
+
+	    switch (pDrawable->bitsPerPixel) {
+	    case 32:
+		*(CARD32*)pExaPixmap->sys_ptr = pixel;
+		break;
+	    case 16:
+		*(CARD16*)pExaPixmap->sys_ptr = pixel;
+		break;
+	    case 8:
+		*(CARD8*)pExaPixmap->sys_ptr = pixel;
+	    }
+
+	    REGION_UNION(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys,
+			 pRegion);
+	}
+
+	REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
     }
     else
     {
diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c
index 8dadd06..fbc48dd 100644
--- a/exa/exa_unaccel.c
+++ b/exa/exa_unaccel.c
@@ -358,16 +358,28 @@ exaGetPixmapFirstPixel (PixmapPtr pPixma
     void *fb;
     Bool need_finish = FALSE;
     BoxRec box;
+    RegionRec migration;
     ExaPixmapPriv (pPixmap);
+    Bool sys_valid = !miPointInRegion(&pExaPixmap->validSys, 0, 0,  &box);
+    Bool damaged = miPointInRegion(DamageRegion(pExaPixmap->pDamage), 0, 0,
+				   &box);
+    Bool offscreen = exaPixmapIsOffscreen(pPixmap);
 
     fb = pExaPixmap->sys_ptr;
 
     /* Try to avoid framebuffer readbacks */
-    if (exaPixmapIsOffscreen(pPixmap) &&
-        miPointInRegion(DamageRegion(pExaPixmap->pDamage), 0, 0,  &box))
+    if ((!offscreen && !sys_valid && !damaged) ||
+	(offscreen && (!sys_valid || damaged)))
     {
+	box.x1 = 0;
+	box.y1 = 0;
+	box.x2 = 1;
+	box.y2 = 1;
+	REGION_INIT(pScreen, &migration, &box, 1);
+
 	need_finish = TRUE;
-	exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
+
+	exaPrepareAccessReg(&pPixmap->drawable, EXA_PREPARE_SRC, &migration);
 	fb = pPixmap->devPrivate.ptr;
     }
 
@@ -383,8 +395,10 @@ exaGetPixmapFirstPixel (PixmapPtr pPixma
 	break;
     }
 
-    if (need_finish)
+    if (need_finish) {
 	exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
+	REGION_UNINIT(pScreen, &migration);
+    }
 
     return pixel;
 }
diff-tree eec06c0074f9744d524b27a29db65bba3e221229 (from 7b585e228d86321c6c86149913452225e5ad6189)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Thu Aug 30 13:37:53 2007 +0200

    EXA: exaImageGlyphBlt improvements.
    
    As we can't actually accelerate anything interesting here, just migrate out
    once and call fbSolidBoxClipped instead of taking a round trip via offscreen
    memory with exaSolidBoxClipped.
    
    Reuse pending damage region for extents and to prevent any actual migration of
    pixmap contents when we're overwriting the whole pending damage region.
    
    Remove superfluous manual damage tracking.

diff --git a/exa/exa_accel.c b/exa/exa_accel.c
index 1fd299e..e9ca472 100644
--- a/exa/exa_accel.c
+++ b/exa/exa_accel.c
@@ -816,97 +816,6 @@ out:
 }
 
 static void
-exaSolidBoxClipped (DrawablePtr	pDrawable,
-		    RegionPtr	pClip,
-		    FbBits	pm,
-		    FbBits	fg,
-		    int		x1,
-		    int		y1,
-		    int		x2,
-		    int		y2)
-{
-    ExaScreenPriv (pDrawable->pScreen);
-    PixmapPtr   pPixmap;
-    BoxPtr	pbox;
-    int		nbox;
-    int		xoff, yoff;
-    int		partX1, partX2, partY1, partY2;
-    ExaMigrationRec pixmaps[1];
-    Bool	fallback = FALSE;
-
-    pixmaps[0].as_dst = TRUE;
-    pixmaps[0].as_src = FALSE;
-    pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
-    pixmaps[0].pReg = NULL;
-
-    if (pExaScr->swappedOut ||
-	pPixmap->drawable.width > pExaScr->info->maxX ||
-	pPixmap->drawable.height > pExaScr->info->maxY)
-    {
-	fallback = TRUE;
-    } else {
-	exaDoMigration (pixmaps, 1, TRUE);
-    }
-
-    exaGetDrawableDeltas (pDrawable, pPixmap, &xoff, &yoff);
-
-    if (fallback || !exaPixmapIsOffscreen(pPixmap) ||
-	!(*pExaScr->info->PrepareSolid) (pPixmap, GXcopy, pm, fg))
-    {
-	EXA_FALLBACK(("to %p (%c)\n", pDrawable,
-		      exaDrawableLocation(pDrawable)));
-	fallback = TRUE;
-	exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
-	fg = fbReplicatePixel (fg, pDrawable->bitsPerPixel);
-	fbSolidBoxClipped (pDrawable, pClip, x1, y1, x2, y2,
-			   fbAnd (GXcopy, fg, pm),
-			   fbXor (GXcopy, fg, pm));
-	exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
-    }
-    for (nbox = REGION_NUM_RECTS(pClip), pbox = REGION_RECTS(pClip);
-	 nbox--;
-	 pbox++)
-    {
-	partX1 = pbox->x1;
-	if (partX1 < x1)
-	    partX1 = x1;
-
-	partX2 = pbox->x2;
-	if (partX2 > x2)
-	    partX2 = x2;
-
-	if (partX2 <= partX1)
-	    continue;
-
-	partY1 = pbox->y1;
-	if (partY1 < y1)
-	    partY1 = y1;
-
-	partY2 = pbox->y2;
-	if (partY2 > y2)
-	    partY2 = y2;
-
-	if (partY2 <= partY1)
-	    continue;
-
-	if (!fallback) {
-	    (*pExaScr->info->Solid) (pPixmap,
-				     partX1 + xoff, partY1 + yoff,
-				     partX2 + xoff, partY2 + yoff);
-	}
-
-	exaPixmapDirty (pPixmap, partX1 + xoff, partY1 + yoff, partX2 + xoff,
-			partY2 + yoff);
-    }
-
-    if (fallback)
-	return;
-
-    (*pExaScr->info->DoneSolid) (pPixmap);
-    exaMarkSync(pDrawable->pScreen);
-}
-
-static void
 exaImageGlyphBlt (DrawablePtr	pDrawable,
 		  GCPtr		pGC,
 		  int		x,
@@ -922,7 +831,6 @@ exaImageGlyphBlt (DrawablePtr	pDrawable,
     int		    gWidth, gHeight;	/* width and height of glyph */
     FbStride	    gStride;		/* stride of glyph */
     Bool	    opaque;
-    int		    n;
     int		    gx, gy;
     void	    (*glyph) (FbBits *,
 			      FbStride,
@@ -936,37 +844,33 @@ exaImageGlyphBlt (DrawablePtr	pDrawable,
     int		    dstBpp;
     int		    dstXoff, dstYoff;
     FbBits	    depthMask;
+    Bool	    fallback;
     PixmapPtr	    pPixmap = exaGetDrawablePixmap(pDrawable);
+    ExaPixmapPriv(pPixmap);
     ExaMigrationRec pixmaps[1];
-    int		    xBack, widthBack, yBack, heightBack;
-
-    for (ppci = ppciInit, n = nglyph, widthBack = 0; n; n--)
-	widthBack += (*ppci++)->metrics.characterWidth;
-
-    xBack = x;
-    if (widthBack < 0)
-    {
-	xBack += widthBack;
-	widthBack = -widthBack;
-    }
-    yBack = y - FONTASCENT(pGC->font);
-    heightBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
+    RegionPtr	    pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
+    BoxRec	    extents = *REGION_EXTENTS(pScreen, pending_damage);
+    int		    xoff, yoff;
 
-    if (xBack >= pDrawable->width || yBack >= pDrawable->height ||
-	(xBack + widthBack) <= 0 || (yBack + heightBack) <= 0)
+    if (extents.x1 >= extents.x2 || extents.y1 >= extents.y2)
 	return;
 
+    depthMask = FbFullMask(pDrawable->depth);
+    fallback = (pGC->planemask & depthMask) != depthMask;
+
     pixmaps[0].as_dst = TRUE;
-    pixmaps[0].as_src = TRUE;
+    pixmaps[0].as_src = FALSE;
     pixmaps[0].pPix = pPixmap;
-    pixmaps[0].pReg = NULL;
+    pixmaps[0].pReg = fallback ? NULL : pending_damage;
 
-    depthMask = FbFullMask(pDrawable->depth);
-    if ((pGC->planemask & depthMask) != depthMask)
+    exaDoMigration(pixmaps, 1, FALSE);
+
+    if (fallback)
     {
 	ExaCheckImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppciInit, pglyphBase);
-	goto damage;
+	return;
     }
+
     glyph = NULL;
     switch (pDrawable->bitsPerPixel) {
     case 8:	glyph = fbGlyph8; break;
@@ -977,8 +881,14 @@ exaImageGlyphBlt (DrawablePtr	pDrawable,
 
     x += pDrawable->x;
     y += pDrawable->y;
-    xBack += pDrawable->x;
-    yBack += pDrawable->y;
+
+    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
+    extents.x1 -= xoff;
+    extents.x2 -= xoff;
+    extents.y1 -= yoff;
+    extents.y2 -= yoff;
+
+    exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
 
     if (TERMINALFONT (pGC->font) && !glyph)
     {
@@ -986,19 +896,22 @@ exaImageGlyphBlt (DrawablePtr	pDrawable,
     }
     else
     {
-        exaSolidBoxClipped (pDrawable,
-			    fbGetCompositeClip(pGC),
-			    pGC->planemask,
-			    pGC->bgPixel,
-			    xBack,
-			    yBack,
-			    xBack + widthBack,
-			    yBack + heightBack);
+	FbBits fg = fbReplicatePixel (pGC->bgPixel, pDrawable->bitsPerPixel);
+
+	fbSolidBoxClipped (pDrawable,
+			   fbGetCompositeClip(pGC),
+			   extents.x1,
+			   extents.y1,
+			   extents.x2,
+			   extents.y2,
+			   fbAnd (GXcopy, fg, pGC->planemask),
+			   fbXor (GXcopy, fg, pGC->planemask));
+
 	opaque = FALSE;
     }
 
     EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
-    exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
+
     exaPrepareAccessGC (pGC);
 
     fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
@@ -1011,9 +924,9 @@ exaImageGlyphBlt (DrawablePtr	pDrawable,
 	gx = x + pci->metrics.leftSideBearing;
 	gy = y - pci->metrics.ascent;
 
-	if (!gWidth || !gHeight || (gx + gWidth) <= xBack ||
-	    (gy + gHeight) <= yBack || gx >= (xBack + widthBack) ||
-	    gy >= (yBack + heightBack))
+	if (!gWidth || !gHeight || (gx + gWidth) <= extents.x1 ||
+	    (gy + gHeight) <= extents.y1 || gx >= extents.x2 ||
+	    gy >= extents.y2)
 	    continue;
 
 	pglyph = FONTGLYPHBITS(pglyphBase, pci);
@@ -1036,11 +949,6 @@ exaImageGlyphBlt (DrawablePtr	pDrawable,
     }
     exaFinishAccessGC (pGC);
     exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
-
-damage:
-    exaGetDrawableDeltas(pDrawable, pPixmap, &dstXoff, &dstYoff);
-    exaPixmapDirty(pPixmap, xBack + dstXoff, yBack + dstYoff,
-		   xBack + dstXoff + widthBack, yBack + dstYoff + heightBack);
 }
 
 const GCOps exaOps = {
diff-tree 7b585e228d86321c6c86149913452225e5ad6189 (from 0b342aa682a5aac383b674a15c937735ae7047b2)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Thu Aug 30 13:30:03 2007 +0200

    EXA: Improvements for trapezoids and triangles.
    
    Only migrate once in exaTrapezoids/Triangles instead of every time in
    exaRasterizeTrapezoid/AddTriangles. Adapt manual damage tracking to new
    infrastructure.
    
    Also move definition of NeedsComponent() closer to where it's used.

diff --git a/exa/exa.c b/exa/exa.c
index 5a85037..ad8d967 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -766,11 +766,8 @@ exaDriverInit (ScreenPtr		pScreen,
         pExaScr->SavedComposite = ps->Composite;
 	ps->Composite = exaComposite;
 
-	pExaScr->SavedRasterizeTrapezoid = ps->RasterizeTrapezoid;
-	ps->RasterizeTrapezoid = exaRasterizeTrapezoid;
-
-	pExaScr->SavedAddTriangles = ps->AddTriangles;
-	ps->AddTriangles = exaAddTriangles;
+	pExaScr->SavedTriangles = ps->Triangles;
+	ps->Triangles = exaTriangles;
 
 	pExaScr->SavedGlyphs = ps->Glyphs;
 	ps->Glyphs = exaGlyphs;
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index da5e459..db5bd02 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -111,8 +111,7 @@ typedef struct {
     ModifyPixmapHeaderProcPtr    SavedModifyPixmapHeader;
 #ifdef RENDER
     CompositeProcPtr             SavedComposite;
-    RasterizeTrapezoidProcPtr	 SavedRasterizeTrapezoid;
-    AddTrianglesProcPtr		 SavedAddTriangles;
+    TrianglesProcPtr		 SavedTriangles;
     GlyphsProcPtr                SavedGlyphs;
     TrapezoidsProcPtr            SavedTrapezoids;
 #endif
@@ -405,12 +404,9 @@ exaTrapezoids (CARD8 op, PicturePtr pSrc
                int ntrap, xTrapezoid *traps);
 
 void
-exaRasterizeTrapezoid (PicturePtr pPicture, xTrapezoid  *trap,
-		       int x_off, int y_off);
-
-void
-exaAddTriangles (PicturePtr pPicture, INT16 x_off, INT16 y_off, int ntri,
-		 xTriangle *tris);
+exaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
+	      PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+	      int ntri, xTriangle *tris);
 
 void
 exaGlyphs (CARD8	op,
diff --git a/exa/exa_render.c b/exa/exa_render.c
index 067f88b..3cfa81e 100644
--- a/exa/exa_render.c
+++ b/exa/exa_render.c
@@ -760,7 +760,7 @@ done:
  * of PolyFillRect to initialize the pixmap after creating it, to prevent
  * the pixmap from being migrated.
  *
- * See the comments about exaTrapezoids.
+ * See the comments about exaTrapezoids and exaTriangles.
  */
 static PicturePtr
 exaCreateAlphaPicture (ScreenPtr     pScreen,
@@ -832,36 +832,70 @@ exaTrapezoids (CARD8 op, PicturePtr pSrc
 {
     ScreenPtr		pScreen = pDst->pDrawable->pScreen;
     PictureScreenPtr    ps = GetPictureScreen(pScreen);
+    BoxRec		bounds;
+    Bool		direct = op == PictOpAdd && miIsSolidAlpha (pSrc);
+
+    if (maskFormat || direct) {
+	miTrapezoidBounds (ntrap, traps, &bounds);
+
+	if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
+	    return;
+    }
 
     /*
      * Check for solid alpha add
      */
-    if (op == PictOpAdd && miIsSolidAlpha (pSrc))
+    if (direct)
     {
+	DrawablePtr pDraw = pDst->pDrawable;
+	PixmapPtr pixmap = exaGetDrawablePixmap (pDraw);
+	ExaPixmapPriv (pixmap);
+	RegionRec migration;
+	RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
+	int xoff, yoff;
+
+	exaGetDrawableDeltas(pDraw, pixmap, &xoff, &yoff);
+
+	xoff += pDraw->x;
+	yoff += pDraw->y;
+
+	bounds.x1 += xoff;
+	bounds.y1 += yoff;
+	bounds.x2 += xoff;
+	bounds.y2 += yoff;
+
+	REGION_INIT(pScreen, &migration, &bounds, 1);
+	REGION_UNION(pScreen, pending_damage, pending_damage, &migration);
+	REGION_UNINIT(pScreen, &migration);
+
+	exaPrepareAccess(pDraw, EXA_PREPARE_DEST);
+
 	for (; ntrap; ntrap--, traps++)
 	    (*ps->RasterizeTrapezoid) (pDst, traps, 0, 0);
+
+	exaFinishAccess(pDraw, EXA_PREPARE_DEST);
     }
     else if (maskFormat)
     {
 	PicturePtr	pPicture;
-	BoxRec		bounds;
 	INT16		xDst, yDst;
 	INT16		xRel, yRel;
 
 	xDst = traps[0].left.p1.x >> 16;
 	yDst = traps[0].left.p1.y >> 16;
 
-	miTrapezoidBounds (ntrap, traps, &bounds);
-	if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
-	    return;
 	pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat,
 	                                  bounds.x2 - bounds.x1,
 	                                  bounds.y2 - bounds.y1);
 	if (!pPicture)
 	    return;
+
+	exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
 	for (; ntrap; ntrap--, traps++)
 	    (*ps->RasterizeTrapezoid) (pPicture, traps,
 				       -bounds.x1, -bounds.y1);
+	exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
+
 	xRel = bounds.x1 + xSrc - xDst;
 	yRel = bounds.y1 + ySrc - yDst;
 	CompositePicture (op, pSrc, pPicture, pDst,
@@ -881,51 +915,102 @@ exaTrapezoids (CARD8 op, PicturePtr pSrc
     }
 }
 
-#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
-
 /**
- * exaRasterizeTrapezoid is just a wrapper around the software implementation.
+ * exaTriangles is essentially a copy of miTriangles that uses
+ * exaCreateAlphaPicture instead of miCreateAlphaPicture.
  *
- * The trapezoid specification is basically too hard to be done in hardware (at
- * the very least, without programmability), so we just do the appropriate
- * Prepare/FinishAccess for it before using fbtrap.c.
+ * The problem with miCreateAlphaPicture is that it calls PolyFillRect
+ * to initialize the contents after creating the pixmap, which
+ * causes the pixmap to be moved in for acceleration. The subsequent
+ * call to AddTriangles won't be accelerated however, which forces the pixmap
+ * to be moved out again.
+ *
+ * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect
+ * to initialize the contents.
  */
 void
-exaRasterizeTrapezoid (PicturePtr pPicture, xTrapezoid  *trap,
-		       int x_off, int y_off)
+exaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
+	      PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+	      int ntri, xTriangle *tris)
 {
-    DrawablePtr pDraw = pPicture->pDrawable;
-    PixmapPtr pPixmap = exaGetDrawablePixmap(pDraw);
-    int xoff, yoff;
-
-    exaPrepareAccess(pDraw, EXA_PREPARE_DEST);
-    fbRasterizeTrapezoid(pPicture, trap, x_off, y_off);
-    exaGetDrawableDeltas(pDraw, pPixmap, &xoff, &yoff);
-    exaPixmapDirty(pPixmap, pDraw->x + xoff, pDraw->y + yoff,
-		   pDraw->x + xoff + pDraw->width,
-		   pDraw->y + yoff + pDraw->height);
-    exaFinishAccess(pDraw, EXA_PREPARE_DEST);
-}
+    ScreenPtr		pScreen = pDst->pDrawable->pScreen;
+    PictureScreenPtr    ps = GetPictureScreen(pScreen);
+    BoxRec		bounds;
+    Bool		direct = op == PictOpAdd && miIsSolidAlpha (pSrc);
 
-/**
- * exaAddTriangles does migration and syncing before dumping down to the
- * software implementation.
- */
-void
-exaAddTriangles (PicturePtr pPicture, INT16 x_off, INT16 y_off, int ntri,
-		 xTriangle *tris)
-{
-    DrawablePtr pDraw = pPicture->pDrawable;
-    PixmapPtr pPixmap = exaGetDrawablePixmap(pDraw);
-    int xoff, yoff;
-
-    exaPrepareAccess(pDraw, EXA_PREPARE_DEST);
-    fbAddTriangles(pPicture, x_off, y_off, ntri, tris);
-    exaGetDrawableDeltas(pDraw, pPixmap, &xoff, &yoff);
-    exaPixmapDirty(pPixmap, pDraw->x + xoff, pDraw->y + yoff,
-		   pDraw->x + xoff + pDraw->width,
-		   pDraw->y + yoff + pDraw->height);
-    exaFinishAccess(pDraw, EXA_PREPARE_DEST);
+    if (maskFormat || direct) {
+	miTriangleBounds (ntri, tris, &bounds);
+
+	if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
+	    return;
+    }
+
+    /*
+     * Check for solid alpha add
+     */
+    if (direct)
+    {
+	DrawablePtr pDraw = pDst->pDrawable;
+	PixmapPtr pixmap = exaGetDrawablePixmap (pDraw);
+	ExaPixmapPriv (pixmap);
+	RegionRec migration;
+	RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
+	int xoff, yoff;
+
+	exaGetDrawableDeltas(pDraw, pixmap, &xoff, &yoff);
+
+	xoff += pDraw->x;
+	yoff += pDraw->y;
+
+	bounds.x1 += xoff;
+	bounds.y1 += yoff;
+	bounds.x2 += xoff;
+	bounds.y2 += yoff;
+
+	REGION_INIT(pScreen, &migration, &bounds, 1);
+	REGION_UNION(pScreen, pending_damage, pending_damage, &migration);
+	REGION_UNINIT(pScreen, &migration);
+
+	exaPrepareAccess(pDraw, EXA_PREPARE_DEST);
+	(*ps->AddTriangles) (pDst, 0, 0, ntri, tris);
+	exaFinishAccess(pDraw, EXA_PREPARE_DEST);
+    }
+    else if (maskFormat)
+    {
+	PicturePtr	pPicture;
+	INT16		xDst, yDst;
+	INT16		xRel, yRel;
+	
+	xDst = tris[0].p1.x >> 16;
+	yDst = tris[0].p1.y >> 16;
+
+	pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat,
+					  bounds.x2 - bounds.x1,
+					  bounds.y2 - bounds.y1);
+	if (!pPicture)
+	    return;
+
+	exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
+	(*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris);
+	exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
+	
+	xRel = bounds.x1 + xSrc - xDst;
+	yRel = bounds.y1 + ySrc - yDst;
+	CompositePicture (op, pSrc, pPicture, pDst,
+			  xRel, yRel, 0, 0, bounds.x1, bounds.y1,
+			  bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
+	FreePicture (pPicture, 0);
+    }
+    else
+    {
+	if (pDst->polyEdge == PolyEdgeSharp)
+	    maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
+	else
+	    maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
+	
+	for (; ntri; ntri--, tris++)
+	    exaTriangles (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris);
+    }
 }
 
 /**
@@ -1001,6 +1086,8 @@ exaGlyphsIntersect(int nlist, GlyphListP
     return FALSE;
 }
 
+#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
+
 /* exaGlyphs is a slight variation on miGlyphs, to support acceleration.  The
  * issue is that miGlyphs' use of ModifyPixmapHeader makes it impossible to
  * migrate these pixmaps.  So, instead we create a pixmap at the beginning of
diff-tree 0b342aa682a5aac383b674a15c937735ae7047b2 (from 320777ddecbe9f5933eb759678204d2cdd8fe289)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Thu Sep 6 13:10:16 2007 +0200

    EXA: Hide pixmap pointer outside of exaPrepare/FinishAccess whenever possible.
    
    We finally want to catch all cases where the pixmap pointer is dereferenced
    outside of exaPrepare/FinishAccess.
    
    Also fix a couple of such cases exposed by this change.

diff --git a/exa/exa.c b/exa/exa.c
index 145d5b2..5a85037 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -44,6 +44,17 @@ static int exaGeneration;
 int exaScreenPrivateIndex;
 int exaPixmapPrivateIndex;
 
+static _X_INLINE void*
+ExaGetPixmapAddress(PixmapPtr p)
+{
+    ExaPixmapPriv(p);
+
+    if (pExaPixmap->offscreen && pExaPixmap->fb_ptr)
+	return pExaPixmap->fb_ptr;
+    else
+	return pExaPixmap->sys_ptr;
+}
+
 /**
  * exaGetPixmapOffset() returns the offset (in bytes) within the framebuffer of
  * the beginning of the given pixmap.
@@ -58,16 +69,9 @@ unsigned long
 exaGetPixmapOffset(PixmapPtr pPix)
 {
     ExaScreenPriv (pPix->drawable.pScreen);
-    ExaPixmapPriv (pPix);
-    void *ptr;
 
-    /* Return the offscreen pointer if we've hidden the data. */
-    if (pPix->devPrivate.ptr == NULL)
-	ptr = pExaPixmap->fb_ptr;
-    else
-	ptr = pPix->devPrivate.ptr;
-
-    return ((unsigned long)ptr - (unsigned long)pExaScr->info->memoryBase);
+    return ((unsigned long)ExaGetPixmapAddress(pPix) -
+	    (unsigned long)pExaScr->info->memoryBase);
 }
 
 /**
@@ -241,6 +245,9 @@ exaCreatePixmap(ScreenPtr pScreen, int w
     pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
     pExaPixmap->sys_pitch = pPixmap->devKind;
 
+    pPixmap->devPrivate.ptr = NULL;
+    pExaPixmap->offscreen = FALSE;
+
     pExaPixmap->fb_ptr = NULL;
     if (pExaScr->info->flags & EXA_OFFSCREEN_ALIGN_POT && w != 1)
 	pExaPixmap->fb_pitch = (1 << (exaLog2(w - 1) + 1)) * bpp / 8;
@@ -274,6 +281,23 @@ exaCreatePixmap(ScreenPtr pScreen, int w
     return pPixmap;
 }
 
+static Bool
+exaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth,
+		      int bitsPerPixel, int devKind, pointer pPixData)
+{
+    ExaScreenPriv(pPixmap->drawable.pScreen);
+    ExaPixmapPriv(pPixmap);
+
+    if (!pPixmap)
+        return FALSE;
+
+    if (pExaPixmap)
+	pExaPixmap->sys_ptr = pPixData;
+
+    return pExaScr->SavedModifyPixmapHeader(pPixmap, width, height, depth,
+					    bitsPerPixel, devKind, pPixData);
+}
+
 /**
  * exaPixmapIsOffscreen() is used to determine if a pixmap is in offscreen
  * memory, meaning that acceleration could probably be done to it, and that it
@@ -291,18 +315,25 @@ exaPixmapIsOffscreen(PixmapPtr p)
 {
     ScreenPtr	pScreen = p->drawable.pScreen;
     ExaScreenPriv(pScreen);
+    ExaPixmapPriv(p);
+    void *save_ptr;
+    Bool ret;
 
-    /* If the devPrivate.ptr is NULL, it's offscreen but we've hidden the data.
-     */
-    if (p->devPrivate.ptr == NULL)
-	return TRUE;
+    save_ptr = p->devPrivate.ptr;
+
+    if (!save_ptr && pExaPixmap)
+	p->devPrivate.ptr = ExaGetPixmapAddress(p);
 
     if (pExaScr->info->PixmapIsOffscreen)
-	return pExaScr->info->PixmapIsOffscreen(p);
+	ret = pExaScr->info->PixmapIsOffscreen(p);
+    else
+       ret = ((unsigned long) ((CARD8 *) p->devPrivate.ptr -
+			       (CARD8 *) pExaScr->info->memoryBase) <
+	      pExaScr->info->memorySize);
+
+    p->devPrivate.ptr = save_ptr;
 
-    return ((unsigned long) ((CARD8 *) p->devPrivate.ptr -
-			     (CARD8 *) pExaScr->info->memoryBase) <
-	    pExaScr->info->memorySize);
+    return ret;
 }
 
 /**
@@ -336,22 +367,19 @@ ExaDoPrepareAccess(DrawablePtr pDrawable
 {
     ScreenPtr	    pScreen = pDrawable->pScreen;
     ExaScreenPriv  (pScreen);
-    PixmapPtr	    pPixmap;
-
-    pPixmap = exaGetDrawablePixmap (pDrawable);
-
-    if (exaPixmapIsOffscreen (pPixmap))
-	exaWaitSync (pDrawable->pScreen);
-    else
-	return;
+    PixmapPtr	    pPixmap = exaGetDrawablePixmap (pDrawable);
+    Bool	    offscreen = exaPixmapIsOffscreen(pPixmap);
 
     /* Unhide pixmap pointer */
     if (pPixmap->devPrivate.ptr == NULL) {
-	ExaPixmapPriv (pPixmap);
-
-	pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
+	pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
     }
 
+    if (!offscreen)
+	return;
+
+    exaWaitSync (pDrawable->pScreen);
+
     if (pExaScr->info->PrepareAccess == NULL)
 	return;
 
@@ -400,18 +428,13 @@ exaFinishAccess(DrawablePtr pDrawable, i
 {
     ScreenPtr	    pScreen = pDrawable->pScreen;
     ExaScreenPriv  (pScreen);
-    PixmapPtr	    pPixmap;
-    ExaPixmapPrivPtr pExaPixmap;
-
-    pPixmap = exaGetDrawablePixmap (pDrawable);
-
-    pExaPixmap = ExaGetPixmapPriv(pPixmap);
+    PixmapPtr	    pPixmap = exaGetDrawablePixmap (pDrawable);
+    ExaPixmapPriv  (pPixmap);
 
     /* Rehide pixmap pointer if we're doing that. */
-    if (pExaPixmap != NULL && pExaScr->hideOffscreenPixmapData &&
-	pExaPixmap->fb_ptr == pPixmap->devPrivate.ptr)
+    if (pExaPixmap)
     {
-	pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
+	pPixmap->devPrivate.ptr = NULL;
     }
 
     if (pExaScr->info->FinishAccess == NULL)
@@ -783,6 +806,8 @@ exaDriverInit (ScreenPtr		pScreen,
         pExaScr->SavedDestroyPixmap = pScreen->DestroyPixmap;
 	pScreen->DestroyPixmap = exaDestroyPixmap;
 
+	pExaScr->SavedModifyPixmapHeader = pScreen->ModifyPixmapHeader;
+	pScreen->ModifyPixmapHeader = exaModifyPixmapHeader;
 	LogMessage(X_INFO, "EXA(%d): Offscreen pixmap area of %d bytes\n",
 		   pScreen->myNum,
 		   pExaScr->info->memorySize - pExaScr->info->offScreenBase);
diff --git a/exa/exa_accel.c b/exa/exa_accel.c
index ceb6c7b..1fd299e 100644
--- a/exa/exa_accel.c
+++ b/exa/exa_accel.c
@@ -213,8 +213,7 @@ exaDoPutImage (DrawablePtr pDrawable, GC
 	    int	dstXoff, dstYoff;
 
 	    if (!access_prepared) {
-		exaPrepareAccessReg(pDrawable, EXA_PREPARE_DEST,
-				    pixmaps[0].pReg);
+		ExaDoPrepareAccess(pDrawable, EXA_PREPARE_DEST);
 
 		access_prepared = TRUE;
 	    }
@@ -233,14 +232,14 @@ exaDoPutImage (DrawablePtr pDrawable, GC
 		      GXcopy, FB_ALLONES, dstBpp);
 	}
 
-	if (access_prepared)
-	    exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
-	else
-	    exaMarkSync(pDrawable->pScreen);
-
 	exaPixmapDirty(pixmaps[0].pPix, x1 + xoff, y1 + yoff, x2 + xoff, y2 + yoff);
     }
 
+    if (access_prepared)
+	exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
+    else
+	exaMarkSync(pDrawable->pScreen);
+
     return TRUE;
 
 fallback:
@@ -271,8 +270,10 @@ exaShmPutImage(DrawablePtr pDrawable, GC
 		      src_stride))
 	return;
 
+    exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
     fbShmPutImage(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy,
 		  data);
+    exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
 }
 
 ShmFuncs exaShmFuncs = { NULL, exaShmPutImage };
diff --git a/exa/exa_migration.c b/exa/exa_migration.c
index f48e93a..ace9076 100644
--- a/exa/exa_migration.c
+++ b/exa/exa_migration.c
@@ -323,10 +323,8 @@ exaDoMoveInPixmap (ExaMigrationPtr migra
 		  pPixmap->drawable.height,
 		  exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
 
-    if (pExaScr->hideOffscreenPixmapData)
-	pPixmap->devPrivate.ptr = NULL;
-    else
-	pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
+    pExaPixmap->offscreen = TRUE;
+
     pPixmap->devKind = pExaPixmap->fb_pitch;
     pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
 }
@@ -365,7 +363,8 @@ exaDoMoveOutPixmap (ExaMigrationPtr migr
 		      pPixmap->drawable.height,
 		      exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
 
-	pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
+	pExaPixmap->offscreen = FALSE;
+
 	pPixmap->devKind = pExaPixmap->sys_pitch;
 	pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
     }
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index 491d80b..da5e459 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -108,6 +108,7 @@ typedef struct {
     CopyWindowProcPtr 		 SavedCopyWindow;
     ChangeWindowAttributesProcPtr SavedChangeWindowAttributes;
     BitmapToRegionProcPtr        SavedBitmapToRegion;
+    ModifyPixmapHeaderProcPtr    SavedModifyPixmapHeader;
 #ifdef RENDER
     CompositeProcPtr             SavedComposite;
     RasterizeTrapezoidProcPtr	 SavedRasterizeTrapezoid;
@@ -118,7 +119,6 @@ typedef struct {
   
     Bool			 swappedOut;
     enum ExaMigrationHeuristic	 migration;
-    Bool			 hideOffscreenPixmapData;
     Bool			 checkDirtyCorrectness;
     unsigned			 disableFbCount;
 } ExaScreenPrivRec, *ExaScreenPrivPtr;
@@ -160,6 +160,7 @@ extern int exaPixmapPrivateIndex;
 typedef struct {
     ExaOffscreenArea *area;
     int		    score;	/**< score for the move-in vs move-out heuristic */
+    Bool	    offscreen;
 
     CARD8	    *sys_ptr;	/**< pointer to pixmap data in system memory */
     int		    sys_pitch;	/**< pitch of pixmap in system memory */
diff-tree 320777ddecbe9f5933eb759678204d2cdd8fe289 (from 19ca0ab22f9bd5a29716259ac230fee62c1afc10)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Wed Aug 29 19:55:22 2007 +0200

    EXA: Support partial migration of pixmap contents between Sys and FB.
    
    The initiator of migration can pass in a region that defines the relevant area
    of each source pixmap or the irrelevant area of the destination pixmap. By
    default, the pending damage region is assumed relevant for the destination
    pixmap, and everything for source pixmaps.
    
    Thanks to Jarno Manninen for reassuring me that my own ideas for this were
    feasible and for providing additional ideas.

diff --git a/exa/exa.c b/exa/exa.c
index ecdb761..145d5b2 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -363,20 +363,15 @@ ExaDoPrepareAccess(DrawablePtr pDrawable
     }
 }
 
-/**
- * exaPrepareAccess() is EXA's wrapper for the driver's PrepareAccess() handler.
- *
- * It deals with waiting for synchronization with the card, determining if
- * PrepareAccess() is necessary, and working around PrepareAccess() failure.
- */
 void
-exaPrepareAccess(DrawablePtr pDrawable, int index)
+exaPrepareAccessReg(DrawablePtr pDrawable, int index, RegionPtr pReg)
 {
     ExaMigrationRec pixmaps[1];
 
     pixmaps[0].as_dst = index == EXA_PREPARE_DEST;
     pixmaps[0].as_src = index != EXA_PREPARE_DEST;
     pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
+    pixmaps[0].pReg = pReg;
 
     exaDoMigration(pixmaps, 1, FALSE);
 
@@ -384,6 +379,18 @@ exaPrepareAccess(DrawablePtr pDrawable, 
 }
 
 /**
+ * exaPrepareAccess() is EXA's wrapper for the driver's PrepareAccess() handler.
+ *
+ * It deals with waiting for synchronization with the card, determining if
+ * PrepareAccess() is necessary, and working around PrepareAccess() failure.
+ */
+void
+exaPrepareAccess(DrawablePtr pDrawable, int index)
+{
+    exaPrepareAccessReg(pDrawable, index, NULL);
+}
+
+/**
  * exaFinishAccess() is EXA's wrapper for the driver's FinishAccess() handler.
  *
  * It deals with calling the driver's FinishAccess() only if necessary.
diff --git a/exa/exa_accel.c b/exa/exa_accel.c
index 07ada15..ceb6c7b 100644
--- a/exa/exa_accel.c
+++ b/exa/exa_accel.c
@@ -55,6 +55,7 @@ exaFillSpans(DrawablePtr pDrawable, GCPt
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = FALSE;
     pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
+    pixmaps[0].pReg = NULL;
 
     if (pExaScr->swappedOut ||
 	pGC->fillStyle != FillSolid ||
@@ -153,6 +154,7 @@ exaDoPutImage (DrawablePtr pDrawable, GC
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = FALSE;
     pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
+    pixmaps[0].pReg = NULL;
 
     /* Don't bother with under 8bpp, XYPixmaps. */
     if (format != ZPixmap || bpp < 8)
@@ -211,7 +213,8 @@ exaDoPutImage (DrawablePtr pDrawable, GC
 	    int	dstXoff, dstYoff;
 
 	    if (!access_prepared) {
-		exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
+		exaPrepareAccessReg(pDrawable, EXA_PREPARE_DEST,
+				    pixmaps[0].pReg);
 
 		access_prepared = TRUE;
 	    }
@@ -232,6 +235,8 @@ exaDoPutImage (DrawablePtr pDrawable, GC
 
 	if (access_prepared)
 	    exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
+	else
+	    exaMarkSync(pDrawable->pScreen);
 
 	exaPixmapDirty(pixmaps[0].pPix, x1 + xoff, y1 + yoff, x2 + xoff, y2 + yoff);
     }
@@ -420,9 +425,11 @@ exaCopyNtoN (DrawablePtr    pSrcDrawable
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = FALSE;
     pixmaps[0].pPix = pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
+    pixmaps[0].pReg = NULL;
     pixmaps[1].as_dst = FALSE;
     pixmaps[1].as_src = TRUE;
     pixmaps[1].pPix = pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
+    pixmaps[1].pReg = NULL;
 
     /* Respect maxX/maxY in a trivial way: don't set up drawing when we might
      * violate the limits.  The proper solution would be a temporary pixmap
@@ -463,7 +470,7 @@ exaCopyNtoN (DrawablePtr    pSrcDrawable
 	EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable,
 		      exaDrawableLocation(pSrcDrawable),
 		      exaDrawableLocation(pDstDrawable)));
-	exaPrepareAccess (pDstDrawable, EXA_PREPARE_DEST);
+	exaPrepareAccessReg (pDstDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
 	exaPrepareAccess (pSrcDrawable, EXA_PREPARE_SRC);
 	fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC,
 		    pbox, nbox, dx, dy, reverse, upsidedown,
@@ -682,7 +689,8 @@ exaPolyFillRect(DrawablePtr pDrawable,
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = FALSE;
     pixmaps[0].pPix = pPixmap;
- 
+    pixmaps[0].pReg = NULL;
+
     exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
 
     if (pExaScr->swappedOut ||
@@ -828,6 +836,7 @@ exaSolidBoxClipped (DrawablePtr	pDrawabl
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = FALSE;
     pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
+    pixmaps[0].pReg = NULL;
 
     if (pExaScr->swappedOut ||
 	pPixmap->drawable.width > pExaScr->info->maxX ||
@@ -846,7 +855,7 @@ exaSolidBoxClipped (DrawablePtr	pDrawabl
 	EXA_FALLBACK(("to %p (%c)\n", pDrawable,
 		      exaDrawableLocation(pDrawable)));
 	fallback = TRUE;
-	exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
+	exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
 	fg = fbReplicatePixel (fg, pDrawable->bitsPerPixel);
 	fbSolidBoxClipped (pDrawable, pClip, x1, y1, x2, y2,
 			   fbAnd (GXcopy, fg, pm),
@@ -949,6 +958,7 @@ exaImageGlyphBlt (DrawablePtr	pDrawable,
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = TRUE;
     pixmaps[0].pPix = pPixmap;
+    pixmaps[0].pReg = NULL;
 
     depthMask = FbFullMask(pDrawable->depth);
     if ((pGC->planemask & depthMask) != depthMask)
@@ -987,7 +997,7 @@ exaImageGlyphBlt (DrawablePtr	pDrawable,
     }
 
     EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
-    exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
+    exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
     exaPrepareAccessGC (pGC);
 
     fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
@@ -1099,7 +1109,8 @@ exaFillRegionSolid (DrawablePtr	pDrawabl
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = FALSE;
     pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
- 
+    pixmaps[0].pReg = NULL;
+
     if (pPixmap->drawable.width > pExaScr->info->maxX ||
 	pPixmap->drawable.height > pExaScr->info->maxY)
     {
@@ -1128,7 +1139,7 @@ fallback:
 	    return FALSE;
 	EXA_FALLBACK(("to %p (%c)\n", pDrawable,
 		      exaDrawableLocation(pDrawable)));
-	exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
+	exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
 	fbFillRegionSolid (pDrawable, pRegion, 0,
 			   fbReplicatePixel (pixel, pDrawable->bitsPerPixel));
 	exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
@@ -1170,9 +1181,11 @@ exaFillRegionTiled (DrawablePtr	pDrawabl
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = FALSE;
     pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
+    pixmaps[0].pReg = NULL;
     pixmaps[1].as_dst = FALSE;
     pixmaps[1].as_src = TRUE;
     pixmaps[1].pPix = pTile;
+    pixmaps[1].pReg = NULL;
 
     if (pPixmap->drawable.width > pExaScr->info->maxX ||
 	pPixmap->drawable.height > pExaScr->info->maxY ||
@@ -1243,7 +1256,7 @@ fallback:
     EXA_FALLBACK(("from %p to %p (%c,%c)\n", pTile, pDrawable,
 		  exaDrawableLocation(&pTile->drawable),
 		  exaDrawableLocation(pDrawable)));
-    exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
+    exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
     exaPrepareAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC);
     fbFillRegionTiled (pDrawable, pRegion, pTile);
     exaFinishAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC);
diff --git a/exa/exa_migration.c b/exa/exa_migration.c
index 99058f1..f48e93a 100644
--- a/exa/exa_migration.c
+++ b/exa/exa_migration.c
@@ -117,28 +117,62 @@ exaPixmapShouldBeInFB (PixmapPtr pPix)
  * FB to system or vice versa.  Both areas must be allocated.
  */
 static _X_INLINE void
-exaCopyDirty(PixmapPtr pPixmap, RegionPtr pValidDst, RegionPtr pValidSrc,
+exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc,
 	     Bool (*transfer) (PixmapPtr pPix, int x, int y, int w, int h,
 			       char *sys, int sys_pitch), CARD8 *fallback_src,
 	     CARD8 *fallback_dst, int fallback_srcpitch, int fallback_dstpitch,
 	     int fallback_index, void (*sync) (ScreenPtr pScreen))
 {
+    PixmapPtr pPixmap = migrate->pPix;
     ExaPixmapPriv (pPixmap);
-    RegionPtr pDamageReg = DamageRegion (pExaPixmap->pDamage);
+    RegionPtr damage = DamageRegion (pExaPixmap->pDamage);
     RegionRec CopyReg;
     CARD8 *save_ptr;
     int save_pitch;
     BoxPtr pBox;
     int nbox;
-    Bool do_sync = FALSE;
+    Bool access_prepared = FALSE;
 
-    /* Damaged bits are valid in source but invalid in destination */
-    REGION_UNION(pScreen, pValidSrc, pValidSrc, pDamageReg);
-    REGION_SUBTRACT(pScreen, pValidDst, pValidDst, pDamageReg);
+    /* Damaged bits are valid in current copy but invalid in other one */
+    if (exaPixmapIsOffscreen(pPixmap)) {
+	REGION_UNION(pScreen, &pExaPixmap->validFB, &pExaPixmap->validFB,
+		     damage);
+	REGION_SUBTRACT(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys,
+			damage);
+    } else {
+	REGION_UNION(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys,
+		     damage);
+	REGION_SUBTRACT(pScreen, &pExaPixmap->validFB, &pExaPixmap->validFB,
+			damage);
+    }
+
+    REGION_EMPTY(pScreen, damage);
 
-    /* Copy bits valid in ssource but not in destination */
+    /* Copy bits valid in source but not in destination */
     REGION_NULL(pScreen, &CopyReg);
     REGION_SUBTRACT(pScreen, &CopyReg, pValidSrc, pValidDst);
+
+    if (migrate->as_dst) {
+	RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
+
+	if (REGION_NIL(pending_damage)) {
+	    static Bool firsttime = TRUE;
+
+	    if (firsttime) {
+		ErrorF("%s: Pending damage region empty!\n", __func__);
+		firsttime = FALSE;
+	    }
+	}
+
+	REGION_INTERSECT(pScreen, &CopyReg, &CopyReg, pending_damage);
+
+	if (migrate->pReg)
+	    REGION_SUBTRACT(pScreen, &CopyReg, &CopyReg, migrate->pReg);
+    } else {
+	if (migrate->pReg)
+	    REGION_INTERSECT(pScreen, &CopyReg, &CopyReg, migrate->pReg);
+    }
+
     pBox = REGION_RECTS(&CopyReg);
     nbox = REGION_NUM_RECTS(&CopyReg);
 
@@ -165,29 +199,30 @@ exaCopyDirty(PixmapPtr pPixmap, RegionPt
 				    + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8,
 				    pExaPixmap->sys_pitch))
 	{
-	    ExaDoPrepareAccess(&pPixmap->drawable, fallback_index);
+	    if (!access_prepared) {
+		ExaDoPrepareAccess(&pPixmap->drawable, fallback_index);
+		access_prepared = TRUE;
+	    }
 	    exaMemcpyBox (pPixmap, pBox,
 			  fallback_src, fallback_srcpitch,
 			  fallback_dst, fallback_dstpitch);
-	    exaFinishAccess(&pPixmap->drawable, fallback_index);
 	}
-	else
-	    do_sync = TRUE;
 
 	pBox++;
     }
 
-    if (do_sync)
+    if (access_prepared)
+	exaFinishAccess(&pPixmap->drawable, fallback_index);
+    else
 	sync (pPixmap->drawable.pScreen);
 
     pPixmap->devPrivate.ptr = save_ptr;
     pPixmap->devKind = save_pitch;
 
-    /* The copied bits are now no longer damaged but valid in destination */
+    /* The copied bits are now valid in destination */
     REGION_UNION(pScreen, pValidDst, pValidDst, &CopyReg);
-    REGION_SUBTRACT(pScreen, pDamageReg, pDamageReg, &CopyReg);
 
-    REGION_NULL(pScreen, &CopyReg);
+    REGION_UNINIT(pScreen, &CopyReg);
 }
 
 /**
@@ -196,12 +231,13 @@ exaCopyDirty(PixmapPtr pPixmap, RegionPt
  * allocated.
  */
 static void
-exaCopyDirtyToSys (PixmapPtr pPixmap)
+exaCopyDirtyToSys (ExaMigrationPtr migrate)
 {
+    PixmapPtr pPixmap = migrate->pPix;
     ExaScreenPriv (pPixmap->drawable.pScreen);
     ExaPixmapPriv (pPixmap);
 
-    exaCopyDirty(pPixmap, &pExaPixmap->validSys, &pExaPixmap->validFB,
+    exaCopyDirty(migrate, &pExaPixmap->validSys, &pExaPixmap->validFB,
 		 pExaScr->info->DownloadFromScreen, pExaPixmap->fb_ptr,
 		 pExaPixmap->sys_ptr, pExaPixmap->fb_pitch,
 		 pExaPixmap->sys_pitch, EXA_PREPARE_SRC, exaWaitSync);
@@ -213,51 +249,19 @@ exaCopyDirtyToSys (PixmapPtr pPixmap)
  * allocated.
  */
 static void
-exaCopyDirtyToFb (PixmapPtr pPixmap)
+exaCopyDirtyToFb (ExaMigrationPtr migrate)
 {
+    PixmapPtr pPixmap = migrate->pPix;
     ExaScreenPriv (pPixmap->drawable.pScreen);
     ExaPixmapPriv (pPixmap);
 
-    exaCopyDirty(pPixmap, &pExaPixmap->validFB, &pExaPixmap->validSys,
+    exaCopyDirty(migrate, &pExaPixmap->validFB, &pExaPixmap->validSys,
 		 pExaScr->info->UploadToScreen, pExaPixmap->sys_ptr,
 		 pExaPixmap->fb_ptr, pExaPixmap->sys_pitch,
 		 pExaPixmap->fb_pitch, EXA_PREPARE_DEST, exaMarkSync);
 }
 
 /**
- * Copies out important pixmap data and removes references to framebuffer area.
- * Called when the memory manager decides it's time to kick the pixmap out of
- * framebuffer entirely.
- */
-void
-exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area)
-{
-    PixmapPtr pPixmap = area->privData;
-    ExaPixmapPriv(pPixmap);
-
-    DBG_MIGRATE (("Save %p (%p) (%dx%d) (%c)\n", pPixmap,
-		  (void*)(ExaGetPixmapPriv(pPixmap)->area ?
-                          ExaGetPixmapPriv(pPixmap)->area->offset : 0),
-		  pPixmap->drawable.width,
-		  pPixmap->drawable.height,
-		  exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
-
-    if (exaPixmapIsOffscreen(pPixmap)) {
-	exaCopyDirtyToSys (pPixmap);
-	pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
-	pPixmap->devKind = pExaPixmap->sys_pitch;
-	pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
-    }
-
-    pExaPixmap->fb_ptr = NULL;
-    pExaPixmap->area = NULL;
-
-    /* Mark all FB bits as invalid, so all valid system bits get copied to FB
-     * next time */
-    REGION_NULL(pPixmap->drawable.pScreen, &pExaPixmap->validFB);
-}
-
-/**
  * Allocates a framebuffer copy of the pixmap if necessary, and then copies
  * any necessary pixmap data into the framebuffer copy and points the pixmap at
  * it.
@@ -272,10 +276,11 @@ exaPixmapSave (ScreenPtr pScreen, ExaOff
  * we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move
  * all the data, since it's almost surely all valid now.
  */
-void
-exaMoveInPixmap (PixmapPtr pPixmap)
+static void
+exaDoMoveInPixmap (ExaMigrationPtr migrate)
 {
-    ScreenPtr	pScreen = pPixmap->drawable.pScreen;
+    PixmapPtr pPixmap = migrate->pPix;
+    ScreenPtr pScreen = pPixmap->drawable.pScreen;
     ExaScreenPriv (pScreen);
     ExaPixmapPriv (pPixmap);
 
@@ -283,10 +288,6 @@ exaMoveInPixmap (PixmapPtr pPixmap)
     if (pExaScr->swappedOut)
 	return;
 
-    /* If we're already in FB, our work is done. */
-    if (exaPixmapIsOffscreen(pPixmap))
-	return;
-
     /* If we're not allowed to move, then fail. */
     if (exaPixmapIsPinned(pPixmap))
 	return;
@@ -310,6 +311,11 @@ exaMoveInPixmap (PixmapPtr pPixmap)
 				       pExaPixmap->area->offset;
     }
 
+    exaCopyDirtyToFb (migrate);
+
+    if (exaPixmapIsOffscreen(pPixmap))
+	return;
+
     DBG_MIGRATE (("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap,
 		  (ExaGetPixmapPriv(pPixmap)->area ?
                    ExaGetPixmapPriv(pPixmap)->area->offset : 0),
@@ -317,8 +323,6 @@ exaMoveInPixmap (PixmapPtr pPixmap)
 		  pPixmap->drawable.height,
 		  exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
 
-    exaCopyDirtyToFb (pPixmap);
-
     if (pExaScr->hideOffscreenPixmapData)
 	pPixmap->devPrivate.ptr = NULL;
     else
@@ -327,18 +331,31 @@ exaMoveInPixmap (PixmapPtr pPixmap)
     pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
 }
 
+void
+exaMoveInPixmap (PixmapPtr pPixmap)
+{
+    static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE,
+				       .pReg = NULL };
+
+    migrate.pPix = pPixmap;
+    exaDoMoveInPixmap (&migrate);
+}
+
 /**
  * Switches the current active location of the pixmap to system memory, copying
  * updated data out if necessary.
  */
-void
-exaMoveOutPixmap (PixmapPtr pPixmap)
+static void
+exaDoMoveOutPixmap (ExaMigrationPtr migrate)
 {
+    PixmapPtr pPixmap = migrate->pPix;
     ExaPixmapPriv (pPixmap);
 
-    if (exaPixmapIsPinned(pPixmap))
+    if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap))
 	return;
 
+    exaCopyDirtyToSys (migrate);
+
     if (exaPixmapIsOffscreen(pPixmap)) {
 
 	DBG_MIGRATE (("<- %p (%p) (%dx%d) (%c)\n", pPixmap,
@@ -348,21 +365,52 @@ exaMoveOutPixmap (PixmapPtr pPixmap)
 		      pPixmap->drawable.height,
 		      exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
 
-	exaCopyDirtyToSys (pPixmap);
-
 	pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
 	pPixmap->devKind = pExaPixmap->sys_pitch;
 	pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
     }
 }
 
+void
+exaMoveOutPixmap (PixmapPtr pPixmap)
+{
+    static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE,
+				       .pReg = NULL };
+
+    migrate.pPix = pPixmap;
+    exaDoMoveOutPixmap (&migrate);
+}
+
+
+/**
+ * Copies out important pixmap data and removes references to framebuffer area.
+ * Called when the memory manager decides it's time to kick the pixmap out of
+ * framebuffer entirely.
+ */
+void
+exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area)
+{
+    PixmapPtr pPixmap = area->privData;
+    ExaPixmapPriv(pPixmap);
+
+    exaMoveOutPixmap(pPixmap);
+
+    pExaPixmap->fb_ptr = NULL;
+    pExaPixmap->area = NULL;
+
+    /* Mark all FB bits as invalid, so all valid system bits get copied to FB
+     * next time */
+    REGION_EMPTY(pPixmap->drawable.pScreen, &pExaPixmap->validFB);
+}
+
 /**
  * For the "greedy" migration scheme, pushes the pixmap toward being located in
  * framebuffer memory.
  */
 static void
-exaMigrateTowardFb (PixmapPtr pPixmap)
+exaMigrateTowardFb (ExaMigrationPtr migrate)
 {
+    PixmapPtr pPixmap = migrate->pPix;
     ExaPixmapPriv (pPixmap);
 
     if (pExaPixmap == NULL) {
@@ -382,7 +430,7 @@ exaMigrateTowardFb (PixmapPtr pPixmap)
 		 (pointer)pPixmap, pExaPixmap->score));
 
     if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) {
-	exaMoveInPixmap(pPixmap);
+	exaDoMoveInPixmap(migrate);
 	pExaPixmap->score = 0;
     }
 
@@ -392,7 +440,7 @@ exaMigrateTowardFb (PixmapPtr pPixmap)
     if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN &&
 	!exaPixmapIsOffscreen(pPixmap))
     {
-	exaMoveInPixmap (pPixmap);
+	exaDoMoveInPixmap(migrate);
     }
 
     ExaOffscreenMarkUsed (pPixmap);
@@ -403,8 +451,9 @@ exaMigrateTowardFb (PixmapPtr pPixmap)
  * system memory.
  */
 static void
-exaMigrateTowardSys (PixmapPtr pPixmap)
+exaMigrateTowardSys (ExaMigrationPtr migrate)
 {
+    PixmapPtr pPixmap = migrate->pPix;
     ExaPixmapPriv (pPixmap);
 
     if (pExaPixmap == NULL) {
@@ -426,7 +475,7 @@ exaMigrateTowardSys (PixmapPtr pPixmap)
 	pExaPixmap->score--;
 
     if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area)
-	exaMoveOutPixmap (pPixmap);
+	exaDoMoveOutPixmap(migrate);
 }
 
 /**
@@ -438,15 +487,24 @@ exaAssertNotDirty (PixmapPtr pPixmap)
 {
     ExaPixmapPriv (pPixmap);
     CARD8 *dst, *src;
-    RegionPtr pValidReg = exaPixmapIsOffscreen(pPixmap) ? &pExaPixmap->validFB :
-			  &pExaPixmap->validSys;
-    int dst_pitch, src_pitch, cpp, y, nbox = REGION_NUM_RECTS(pValidReg);
-    BoxPtr pBox = REGION_RECTS(pValidReg);
+    RegionRec ValidReg;
+    int dst_pitch, src_pitch, cpp, y, nbox;
+    BoxPtr pBox;
     Bool ret = TRUE;
 
-    if (!nbox || exaPixmapIsPinned(pPixmap) || pExaPixmap->fb_ptr == NULL)
+    if (exaPixmapIsPinned(pPixmap) || pExaPixmap->area == NULL)
 	return ret;
 
+    REGION_NULL(pScreen, &ValidReg);
+    REGION_INTERSECT(pScreen, &ValidReg, &pExaPixmap->validFB,
+		     &pExaPixmap->validSys);
+    nbox = REGION_NUM_RECTS(&ValidReg);
+
+    if (!nbox)
+	goto out;
+
+    pBox = REGION_RECTS(&ValidReg);
+
     dst_pitch = pExaPixmap->sys_pitch;
     src_pitch = pExaPixmap->fb_pitch;
     cpp = pPixmap->drawable.bitsPerPixel / 8;
@@ -479,6 +537,8 @@ exaAssertNotDirty (PixmapPtr pPixmap)
     }
     exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
 
+out:
+    REGION_UNINIT(pScreen, &ValidReg);
     return ret;
 }
 
@@ -533,7 +593,7 @@ exaDoMigration (ExaMigrationPtr pixmaps,
 	    {
 		for (i = 0; i < npixmaps; i++) {
 		    if (!exaPixmapIsDirty (pixmaps[i].pPix))
-			exaMoveOutPixmap (pixmaps[i].pPix);
+			exaDoMoveOutPixmap (pixmaps + i);
 		}
 		return;
 	    }
@@ -544,17 +604,17 @@ exaDoMigration (ExaMigrationPtr pixmaps,
 	 */
 	if (!can_accel) {
 	    for (i = 0; i < npixmaps; i++) {
-		exaMigrateTowardSys (pixmaps[i].pPix);
+		exaMigrateTowardSys (pixmaps + i);
 		if (!exaPixmapIsDirty (pixmaps[i].pPix))
-		    exaMoveOutPixmap (pixmaps[i].pPix);
+		    exaDoMoveOutPixmap (pixmaps + i);
 	    }
 	    return;
 	}
 
 	/* Finally, the acceleration path.  Move them all in. */
 	for (i = 0; i < npixmaps; i++) {
-	    exaMigrateTowardFb(pixmaps[i].pPix);
-	    exaMoveInPixmap(pixmaps[i].pPix);
+	    exaMigrateTowardFb(pixmaps + i);
+	    exaDoMoveInPixmap(pixmaps + i);
 	}
     } else if (pExaScr->migration == ExaMigrationGreedy) {
 	/* If we can't accelerate, either because the driver can't or because one of
@@ -570,7 +630,7 @@ exaDoMigration (ExaMigrationPtr pixmaps,
 	 */
 	if (!can_accel) {
 	    for (i = 0; i < npixmaps; i++)
-		exaMigrateTowardSys (pixmaps[i].pPix);
+		exaMigrateTowardSys (pixmaps + i);
 	    return;
 	}
 
@@ -578,14 +638,14 @@ exaDoMigration (ExaMigrationPtr pixmaps,
 	    if (exaPixmapIsOffscreen(pixmaps[i].pPix)) {
 		/* Found one in FB, so move all to FB. */
 		for (j = 0; j < npixmaps; j++)
-		    exaMigrateTowardFb(pixmaps[j].pPix);
+		    exaMigrateTowardFb(pixmaps + i);
 		return;
 	    }
 	}
 
 	/* Nobody's in FB, so move all away from FB. */
 	for (i = 0; i < npixmaps; i++)
-	    exaMigrateTowardSys(pixmaps[i].pPix);
+	    exaMigrateTowardSys(pixmaps + i);
     } else if (pExaScr->migration == ExaMigrationAlways) {
 	/* Always move the pixmaps out if we can't accelerate.  If we can
 	 * accelerate, try to move them all in.  If that fails, then move them
@@ -593,13 +653,13 @@ exaDoMigration (ExaMigrationPtr pixmaps,
 	 */
 	if (!can_accel) {
 	    for (i = 0; i < npixmaps; i++)
-		exaMoveOutPixmap(pixmaps[i].pPix);
+		exaDoMoveOutPixmap(pixmaps + i);
 	    return;
 	}
 
 	/* Now, try to move them all into FB */
 	for (i = 0; i < npixmaps; i++) {
-	    exaMoveInPixmap(pixmaps[i].pPix);
+	    exaDoMoveInPixmap(pixmaps + i);
 	}
 
 	/* If we couldn't fit everything in, abort */
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index b9e5016..491d80b 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -185,6 +185,7 @@ typedef struct _ExaMigrationRec {
     Bool as_dst;
     Bool as_src;
     PixmapPtr pPix;
+    RegionPtr pReg;
 } ExaMigrationRec, *ExaMigrationPtr;
 
 /**
@@ -338,6 +339,9 @@ void
 ExaDoPrepareAccess(DrawablePtr pDrawable, int index);
 
 void
+exaPrepareAccessReg(DrawablePtr pDrawable, int index, RegionPtr pReg);
+
+void
 exaPrepareAccess(DrawablePtr pDrawable, int index);
 
 void
diff --git a/exa/exa_render.c b/exa/exa_render.c
index 738ac15..067f88b 100644
--- a/exa/exa_render.c
+++ b/exa/exa_render.c
@@ -267,6 +267,7 @@ exaTryDriverSolidFill(PicturePtr	pSrc,
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = FALSE;
     pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
+    pixmaps[0].pReg = NULL;
     exaDoMigration(pixmaps, 1, TRUE);
 
     pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
@@ -381,13 +382,16 @@ exaTryDriverComposite(CARD8		op,
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = exaOpReadsDestination(op);
     pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
+    pixmaps[0].pReg = NULL;
     pixmaps[1].as_dst = FALSE;
     pixmaps[1].as_src = TRUE;
     pixmaps[1].pPix = exaGetDrawablePixmap (pSrc->pDrawable);
+    pixmaps[1].pReg = NULL;
     if (pMask) {
 	pixmaps[2].as_dst = FALSE;
 	pixmaps[2].as_src = TRUE;
 	pixmaps[2].pPix = exaGetDrawablePixmap (pMask->pDrawable);
+	pixmaps[2].pReg = NULL;
 	exaDoMigration(pixmaps, 3, TRUE);
     } else {
 	exaDoMigration(pixmaps, 2, TRUE);
@@ -579,12 +583,14 @@ exaComposite(CARD8	op,
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = exaOpReadsDestination(op);
     pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
+    pixmaps[0].pReg = NULL;
 
     if (pSrc->pDrawable) {
 	pSrcPixmap = exaGetDrawablePixmap (pSrc->pDrawable);
 	pixmaps[npixmaps].as_dst = FALSE;
 	pixmaps[npixmaps].as_src = TRUE;
 	pixmaps[npixmaps].pPix = pSrcPixmap;
+	pixmaps[npixmaps].pReg = NULL;
 	npixmaps++;
     }
 
@@ -592,6 +598,7 @@ exaComposite(CARD8	op,
 	pixmaps[npixmaps].as_dst = FALSE;
 	pixmaps[npixmaps].as_src = TRUE;
 	pixmaps[npixmaps].pPix = exaGetDrawablePixmap (pMask->pDrawable);
+	pixmaps[npixmaps].pReg = NULL;
 	npixmaps++;
     }
 
@@ -1159,8 +1166,9 @@ exaGlyphs (CARD8	op,
 	 * it'll stick there.
 	 */
 	pixmaps[0].as_dst = TRUE;
-	pixmaps[0].as_src = TRUE;
+	pixmaps[0].as_src = FALSE;
 	pixmaps[0].pPix = pPixmap;
+	pixmaps[0].pReg = NULL;
 	exaDoMigration (pixmaps, 1, pExaScr->info->PrepareComposite != NULL);
 
 	while (n--)
diff-tree 19ca0ab22f9bd5a29716259ac230fee62c1afc10 (from 47bb63376b4478074bbd445dfc99c35fa4506127)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Wed Aug 29 19:41:52 2007 +0200

    Add DamagePendingRegion.
    
    DamagePendingRegion returns a pointer to the region of a drawable that will
    be damaged by the current operation for damage records that chose to get damage
    reported only at the end of the operation.

diff --git a/miext/damage/damage.c b/miext/damage/damage.c
index 65314d8..472b1b8 100755
--- a/miext/damage/damage.c
+++ b/miext/damage/damage.c
@@ -1987,6 +1987,12 @@ DamageRegion (DamagePtr		    pDamage)
     return &pDamage->damage;
 }
 
+_X_EXPORT RegionPtr
+DamagePendingRegion (DamagePtr	    pDamage)
+{
+    return &pDamage->pendingDamage;
+}
+
 _X_EXPORT void
 DamageDamageRegion (DrawablePtr	pDrawable,
 		    RegionPtr	pRegion)
diff --git a/miext/damage/damage.h b/miext/damage/damage.h
index 4cfc812..102da6e 100755
--- a/miext/damage/damage.h
+++ b/miext/damage/damage.h
@@ -75,6 +75,9 @@ DamageEmpty (DamagePtr pDamage);
 RegionPtr
 DamageRegion (DamagePtr		    pDamage);
 
+RegionPtr
+DamagePendingRegion (DamagePtr	    pDamage);
+
 void
 DamageDamageRegion (DrawablePtr	    pDrawable,
 		    const RegionPtr pRegion);
diff-tree 47bb63376b4478074bbd445dfc99c35fa4506127 (from d92947c8a83d403e94aa61094f07eea10301ddb0)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Fri Aug 24 19:24:18 2007 +0200

    EXA: Track valid bits in Sys and FB separately.
    
    Also consolidate exaCopyDirtyToFb/Sys.

diff --git a/exa/exa.c b/exa/exa.c
index 514b88b..ecdb761 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -186,7 +186,8 @@ exaDestroyPixmap (PixmapPtr pPixmap)
 	    pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
 	    pPixmap->devKind = pExaPixmap->sys_pitch;
 	}
-	REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validReg);
+	REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validSys);
+	REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validFB);
     }
     return fbDestroyPixmap (pPixmap);
 }
@@ -267,7 +268,8 @@ exaCreatePixmap(ScreenPtr pScreen, int w
     DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE);
 
     /* None of the pixmap bits are valid initially */
-    REGION_NULL(pScreen, &pExaPixmap->validReg);
+    REGION_NULL(pScreen, &pExaPixmap->validSys);
+    REGION_NULL(pScreen, &pExaPixmap->validFB);
 
     return pPixmap;
 }
diff --git a/exa/exa_migration.c b/exa/exa_migration.c
index 661ff40..99058f1 100644
--- a/exa/exa_migration.c
+++ b/exa/exa_migration.c
@@ -90,7 +90,8 @@ exaPixmapIsDirty (PixmapPtr pPix)
     ExaPixmapPriv (pPix);
 
     return pExaPixmap == NULL ||
-	REGION_NOTEMPTY (pScreen, DamageRegion(pExaPixmap->pDamage));
+	REGION_NOTEMPTY (pScreen, DamageRegion(pExaPixmap->pDamage)) ||
+	!REGION_EQUAL(pScreen, &pExaPixmap->validSys, &pExaPixmap->validFB);
 }
 
 /**
@@ -113,21 +114,34 @@ exaPixmapShouldBeInFB (PixmapPtr pPix)
 
 /**
  * If the pixmap is currently dirty, this copies at least the dirty area from
- * the framebuffer  memory copy to the system memory copy.  Both areas must be
- * allocated.
+ * FB to system or vice versa.  Both areas must be allocated.
  */
-static void
-exaCopyDirtyToSys (PixmapPtr pPixmap)
+static _X_INLINE void
+exaCopyDirty(PixmapPtr pPixmap, RegionPtr pValidDst, RegionPtr pValidSrc,
+	     Bool (*transfer) (PixmapPtr pPix, int x, int y, int w, int h,
+			       char *sys, int sys_pitch), CARD8 *fallback_src,
+	     CARD8 *fallback_dst, int fallback_srcpitch, int fallback_dstpitch,
+	     int fallback_index, void (*sync) (ScreenPtr pScreen))
 {
-    ExaScreenPriv (pPixmap->drawable.pScreen);
     ExaPixmapPriv (pPixmap);
-    RegionPtr pRegion = DamageRegion (pExaPixmap->pDamage);
+    RegionPtr pDamageReg = DamageRegion (pExaPixmap->pDamage);
+    RegionRec CopyReg;
     CARD8 *save_ptr;
     int save_pitch;
-    BoxPtr pBox = REGION_RECTS(pRegion);
-    int nbox = REGION_NUM_RECTS(pRegion);
+    BoxPtr pBox;
+    int nbox;
     Bool do_sync = FALSE;
 
+    /* Damaged bits are valid in source but invalid in destination */
+    REGION_UNION(pScreen, pValidSrc, pValidSrc, pDamageReg);
+    REGION_SUBTRACT(pScreen, pValidDst, pValidDst, pDamageReg);
+
+    /* Copy bits valid in ssource but not in destination */
+    REGION_NULL(pScreen, &CopyReg);
+    REGION_SUBTRACT(pScreen, &CopyReg, pValidSrc, pValidDst);
+    pBox = REGION_RECTS(&CopyReg);
+    nbox = REGION_NUM_RECTS(&CopyReg);
+
     save_ptr = pPixmap->devPrivate.ptr;
     save_pitch = pPixmap->devKind;
     pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
@@ -142,21 +156,20 @@ exaCopyDirtyToSys (PixmapPtr pPixmap)
 	if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
 	    continue;
 
-	if (pExaScr->info->DownloadFromScreen == NULL ||
-	    !pExaScr->info->DownloadFromScreen (pPixmap,
-						pBox->x1, pBox->y1,
-						pBox->x2 - pBox->x1,
-						pBox->y2 - pBox->y1,
-						pExaPixmap->sys_ptr
-						+ pBox->y1 * pExaPixmap->sys_pitch
-						+ pBox->x1 * pPixmap->drawable.bitsPerPixel / 8,
-						pExaPixmap->sys_pitch))
+	if (!transfer || !transfer (pPixmap,
+				    pBox->x1, pBox->y1,
+				    pBox->x2 - pBox->x1,
+				    pBox->y2 - pBox->y1,
+				    pExaPixmap->sys_ptr
+				    + pBox->y1 * pExaPixmap->sys_pitch
+				    + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8,
+				    pExaPixmap->sys_pitch))
 	{
-	    ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
+	    ExaDoPrepareAccess(&pPixmap->drawable, fallback_index);
 	    exaMemcpyBox (pPixmap, pBox,
-			  pExaPixmap->fb_ptr, pExaPixmap->fb_pitch,
-			  pExaPixmap->sys_ptr, pExaPixmap->sys_pitch);
-	    exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
+			  fallback_src, fallback_srcpitch,
+			  fallback_dst, fallback_dstpitch);
+	    exaFinishAccess(&pPixmap->drawable, fallback_index);
 	}
 	else
 	    do_sync = TRUE;
@@ -164,84 +177,51 @@ exaCopyDirtyToSys (PixmapPtr pPixmap)
 	pBox++;
     }
 
-    /* Make sure the bits have actually landed, since we don't necessarily sync
-     * when accessing pixmaps in system memory.
-     */
     if (do_sync)
-	exaWaitSync (pPixmap->drawable.pScreen);
+	sync (pPixmap->drawable.pScreen);
 
     pPixmap->devPrivate.ptr = save_ptr;
     pPixmap->devKind = save_pitch;
 
-    /* The previously damaged bits are now no longer damaged but valid */
-    REGION_UNION(pPixmap->drawable.pScreen,
-		 &pExaPixmap->validReg, &pExaPixmap->validReg, pRegion);
-    DamageEmpty (pExaPixmap->pDamage);
+    /* The copied bits are now no longer damaged but valid in destination */
+    REGION_UNION(pScreen, pValidDst, pValidDst, &CopyReg);
+    REGION_SUBTRACT(pScreen, pDamageReg, pDamageReg, &CopyReg);
+
+    REGION_NULL(pScreen, &CopyReg);
 }
 
 /**
  * If the pixmap is currently dirty, this copies at least the dirty area from
- * the system memory copy to the framebuffer memory copy.  Both areas must be
+ * the framebuffer  memory copy to the system memory copy.  Both areas must be
  * allocated.
  */
 static void
-exaCopyDirtyToFb (PixmapPtr pPixmap)
+exaCopyDirtyToSys (PixmapPtr pPixmap)
 {
     ExaScreenPriv (pPixmap->drawable.pScreen);
     ExaPixmapPriv (pPixmap);
-    RegionPtr pRegion = DamageRegion (pExaPixmap->pDamage);
-    CARD8 *save_ptr;
-    int save_pitch;
-    BoxPtr pBox = REGION_RECTS(pRegion);
-    int nbox = REGION_NUM_RECTS(pRegion);
-    Bool do_sync = FALSE;
-
-    save_ptr = pPixmap->devPrivate.ptr;
-    save_pitch = pPixmap->devKind;
-    pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
-    pPixmap->devKind = pExaPixmap->fb_pitch;
-
-    while (nbox--) {
-	pBox->x1 = max(pBox->x1, 0);
-	pBox->y1 = max(pBox->y1, 0);
-	pBox->x2 = min(pBox->x2, pPixmap->drawable.width);
-	pBox->y2 = min(pBox->y2, pPixmap->drawable.height);
 
-	if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
-	    continue;
-
-	if (pExaScr->info->UploadToScreen == NULL ||
-	    !pExaScr->info->UploadToScreen (pPixmap,
-					    pBox->x1, pBox->y1,
-					    pBox->x2 - pBox->x1,
-					    pBox->y2 - pBox->y1,
-					    pExaPixmap->sys_ptr
-					    + pBox->y1 * pExaPixmap->sys_pitch
-					    + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8,
-					    pExaPixmap->sys_pitch))
-	{
-	    ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_DEST);
-	    exaMemcpyBox (pPixmap, pBox,
-			  pExaPixmap->sys_ptr, pExaPixmap->sys_pitch,
-			  pExaPixmap->fb_ptr, pExaPixmap->fb_pitch);
-	    exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_DEST);
-	}
-	else
-	    do_sync = TRUE;
-
-	pBox++;
-    }
-
-    if (do_sync)
-	exaMarkSync (pPixmap->drawable.pScreen);
+    exaCopyDirty(pPixmap, &pExaPixmap->validSys, &pExaPixmap->validFB,
+		 pExaScr->info->DownloadFromScreen, pExaPixmap->fb_ptr,
+		 pExaPixmap->sys_ptr, pExaPixmap->fb_pitch,
+		 pExaPixmap->sys_pitch, EXA_PREPARE_SRC, exaWaitSync);
+}
 
-    pPixmap->devPrivate.ptr = save_ptr;
-    pPixmap->devKind = save_pitch;
+/**
+ * If the pixmap is currently dirty, this copies at least the dirty area from
+ * the system memory copy to the framebuffer memory copy.  Both areas must be
+ * allocated.
+ */
+static void
+exaCopyDirtyToFb (PixmapPtr pPixmap)
+{
+    ExaScreenPriv (pPixmap->drawable.pScreen);
+    ExaPixmapPriv (pPixmap);
 
-    /* The previously damaged bits are now no longer damaged but valid */
-    REGION_UNION(pPixmap->drawable.pScreen,
-		 &pExaPixmap->validReg, &pExaPixmap->validReg, pRegion);
-    DamageEmpty (pExaPixmap->pDamage);
+    exaCopyDirty(pPixmap, &pExaPixmap->validFB, &pExaPixmap->validSys,
+		 pExaScr->info->UploadToScreen, pExaPixmap->sys_ptr,
+		 pExaPixmap->fb_ptr, pExaPixmap->sys_pitch,
+		 pExaPixmap->fb_pitch, EXA_PREPARE_DEST, exaMarkSync);
 }
 
 /**
@@ -254,7 +234,6 @@ exaPixmapSave (ScreenPtr pScreen, ExaOff
 {
     PixmapPtr pPixmap = area->privData;
     ExaPixmapPriv(pPixmap);
-    RegionPtr pDamageReg = DamageRegion(pExaPixmap->pDamage);
 
     DBG_MIGRATE (("Save %p (%p) (%dx%d) (%c)\n", pPixmap,
 		  (void*)(ExaGetPixmapPriv(pPixmap)->area ?
@@ -273,9 +252,9 @@ exaPixmapSave (ScreenPtr pScreen, ExaOff
     pExaPixmap->fb_ptr = NULL;
     pExaPixmap->area = NULL;
 
-    /* Mark all valid bits as damaged, so they'll get copied to FB next time */
-    REGION_UNION(pPixmap->drawable.pScreen, pDamageReg, pDamageReg,
-		 &pExaPixmap->validReg);
+    /* Mark all FB bits as invalid, so all valid system bits get copied to FB
+     * next time */
+    REGION_NULL(pPixmap->drawable.pScreen, &pExaPixmap->validFB);
 }
 
 /**
@@ -459,7 +438,8 @@ exaAssertNotDirty (PixmapPtr pPixmap)
 {
     ExaPixmapPriv (pPixmap);
     CARD8 *dst, *src;
-    RegionPtr pValidReg = &pExaPixmap->validReg;
+    RegionPtr pValidReg = exaPixmapIsOffscreen(pPixmap) ? &pExaPixmap->validFB :
+			  &pExaPixmap->validSys;
     int dst_pitch, src_pitch, cpp, y, nbox = REGION_NUM_RECTS(pValidReg);
     BoxPtr pBox = REGION_RECTS(pValidReg);
     Bool ret = TRUE;
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index 409bc4d..b9e5016 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -175,10 +175,10 @@ typedef struct {
      */
     DamagePtr	    pDamage;
     /**
-     * The valid region marks the valid bits of a drawable (at least, as it's
-     * derived from damage, which may be overreported).
+     * The valid regions mark the valid bits (at least, as they're derived from
+     * damage, which may be overreported) of a pixmap's system and FB copies.
      */
-    RegionRec	    validReg;
+    RegionRec	    validSys, validFB;
 } ExaPixmapPrivRec, *ExaPixmapPrivPtr;
  
 typedef struct _ExaMigrationRec {
diff-tree d92947c8a83d403e94aa61094f07eea10301ddb0 (from 3a4873a46093c37a707e6be0c336a57ab67115ab)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Wed Sep 5 20:10:09 2007 +0200

    EXA: Migrate out pixmap in exaPrepareAccess.
    
    Also fix exaFinishAccessGC not to use the same index for tile and stipple.

diff --git a/exa/exa.c b/exa/exa.c
index 46fb557..514b88b 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -329,14 +329,8 @@ exaGetOffscreenPixmap (DrawablePtr pDraw
 	return NULL;
 }
 
-/**
- * exaPrepareAccess() is EXA's wrapper for the driver's PrepareAccess() handler.
- *
- * It deals with waiting for synchronization with the card, determining if
- * PrepareAccess() is necessary, and working around PrepareAccess() failure.
- */
 void
-exaPrepareAccess(DrawablePtr pDrawable, int index)
+ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
 {
     ScreenPtr	    pScreen = pDrawable->pScreen;
     ExaScreenPriv  (pScreen);
@@ -368,6 +362,26 @@ exaPrepareAccess(DrawablePtr pDrawable, 
 }
 
 /**
+ * exaPrepareAccess() is EXA's wrapper for the driver's PrepareAccess() handler.
+ *
+ * It deals with waiting for synchronization with the card, determining if
+ * PrepareAccess() is necessary, and working around PrepareAccess() failure.
+ */
+void
+exaPrepareAccess(DrawablePtr pDrawable, int index)
+{
+    ExaMigrationRec pixmaps[1];
+
+    pixmaps[0].as_dst = index == EXA_PREPARE_DEST;
+    pixmaps[0].as_src = index != EXA_PREPARE_DEST;
+    pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
+
+    exaDoMigration(pixmaps, 1, FALSE);
+
+    ExaDoPrepareAccess(pDrawable, index);
+}
+
+/**
  * exaFinishAccess() is EXA's wrapper for the driver's FinishAccess() handler.
  *
  * It deals with calling the driver's FinishAccess() only if necessary.
@@ -698,7 +712,7 @@ exaDriverInit (ScreenPtr		pScreen,
     pScreen->GetImage = exaGetImage;
 
     pExaScr->SavedGetSpans = pScreen->GetSpans;
-    pScreen->GetSpans = exaGetSpans;
+    pScreen->GetSpans = ExaCheckGetSpans;
 
     pExaScr->SavedCopyWindow = pScreen->CopyWindow;
     pScreen->CopyWindow = exaCopyWindow;
diff --git a/exa/exa_accel.c b/exa/exa_accel.c
index feedd49..07ada15 100644
--- a/exa/exa_accel.c
+++ b/exa/exa_accel.c
@@ -61,7 +61,6 @@ exaFillSpans(DrawablePtr pDrawable, GCPt
 	pPixmap->drawable.width > pExaScr->info->maxX ||
 	pPixmap->drawable.height > pExaScr->info->maxY)
     {
-	exaDoMigration (pixmaps, 1, FALSE);
 	ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
 	return;
     } else {
@@ -74,7 +73,6 @@ exaFillSpans(DrawablePtr pDrawable, GCPt
 					 pGC->planemask,
 					 pGC->fgPixel))
     {
-	exaDoMigration (pixmaps, 1, FALSE);
 	ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
 	return;
     }
@@ -158,11 +156,11 @@ exaDoPutImage (DrawablePtr pDrawable, GC
 
     /* Don't bother with under 8bpp, XYPixmaps. */
     if (format != ZPixmap || bpp < 8)
-	goto migrate_and_fallback;
+	goto fallback;
 
     /* Only accelerate copies: no rop or planemask. */
     if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
-	goto migrate_and_fallback;
+	goto fallback;
 
     if (pExaScr->swappedOut)
 	goto fallback;
@@ -240,9 +238,6 @@ exaDoPutImage (DrawablePtr pDrawable, GC
 
     return TRUE;
 
-migrate_and_fallback:
-    exaDoMigration (pixmaps, 1, FALSE);
-
 fallback:
     return FALSE;
 }
@@ -468,7 +463,6 @@ exaCopyNtoN (DrawablePtr    pSrcDrawable
 	EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable,
 		      exaDrawableLocation(pSrcDrawable),
 		      exaDrawableLocation(pDstDrawable)));
-	exaDoMigration (pixmaps, 2, FALSE);
 	exaPrepareAccess (pDstDrawable, EXA_PREPARE_DEST);
 	exaPrepareAccess (pSrcDrawable, EXA_PREPARE_SRC);
 	fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC,
@@ -731,15 +725,6 @@ exaPolyFillRect(DrawablePtr pDrawable,
 					 pGC->fgPixel))
     {
 fallback:
-	if (pGC->fillStyle == FillTiled && !pGC->tileIsPixel) {
-	    pixmaps[1].as_dst = FALSE;
-	    pixmaps[1].as_src = TRUE;
-	    pixmaps[1].pPix = pGC->tile.pixmap;
-	    exaDoMigration (pixmaps, 2, FALSE);
-	} else {
-	    exaDoMigration (pixmaps, 1, FALSE);
-	}
-
 	ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect);
 	goto out;
     }
@@ -860,7 +845,6 @@ exaSolidBoxClipped (DrawablePtr	pDrawabl
     {
 	EXA_FALLBACK(("to %p (%c)\n", pDrawable,
 		      exaDrawableLocation(pDrawable)));
-	exaDoMigration (pixmaps, 1, FALSE);
 	fallback = TRUE;
 	exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
 	fg = fbReplicatePixel (fg, pDrawable->bitsPerPixel);
@@ -969,7 +953,6 @@ exaImageGlyphBlt (DrawablePtr	pDrawable,
     depthMask = FbFullMask(pDrawable->depth);
     if ((pGC->planemask & depthMask) != depthMask)
     {
-	exaDoMigration(pixmaps, 1, FALSE);
 	ExaCheckImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppciInit, pglyphBase);
 	goto damage;
     }
@@ -1004,7 +987,6 @@ exaImageGlyphBlt (DrawablePtr	pDrawable,
     }
 
     EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
-    exaDoMigration(pixmaps, 1, FALSE);
     exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
     exaPrepareAccessGC (pGC);
 
@@ -1146,7 +1128,6 @@ fallback:
 	    return FALSE;
 	EXA_FALLBACK(("to %p (%c)\n", pDrawable,
 		      exaDrawableLocation(pDrawable)));
-	exaDoMigration (pixmaps, 1, FALSE);
 	exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
 	fbFillRegionSolid (pDrawable, pRegion, 0,
 			   fbReplicatePixel (pixel, pDrawable->bitsPerPixel));
@@ -1262,7 +1243,6 @@ fallback:
     EXA_FALLBACK(("from %p to %p (%c,%c)\n", pTile, pDrawable,
 		  exaDrawableLocation(&pTile->drawable),
 		  exaDrawableLocation(pDrawable)));
-    exaDoMigration (pixmaps, 2, FALSE);
     exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
     exaPrepareAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC);
     fbFillRegionTiled (pDrawable, pRegion, pTile);
@@ -1349,7 +1329,6 @@ exaGetImage (DrawablePtr pDrawable, int 
 	     unsigned int format, unsigned long planeMask, char *d)
 {
     ExaScreenPriv (pDrawable->pScreen);
-    ExaMigrationRec pixmaps[1];
     PixmapPtr pPix;
     int xoff, yoff;
     Bool ok;
@@ -1362,13 +1341,13 @@ exaGetImage (DrawablePtr pDrawable, int 
 
     /* Only cover the ZPixmap, solid copy case. */
     if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask))
-	goto migrate_and_fallback;
+	goto fallback;
 
     /* Only try to handle the 8bpp and up cases, since we don't want to think
      * about <8bpp.
      */
     if (pDrawable->bitsPerPixel < 8)
-	goto migrate_and_fallback;
+	goto fallback;
 
     pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
     if (pPix == NULL)
@@ -1384,29 +1363,6 @@ exaGetImage (DrawablePtr pDrawable, int 
 	return;
     }
 
-migrate_and_fallback:
-    pixmaps[0].as_dst = FALSE;
-    pixmaps[0].as_src = TRUE;
-    pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
-    exaDoMigration (pixmaps, 1, FALSE);
 fallback:
     ExaCheckGetImage (pDrawable, x, y, w, h, format, planeMask, d);
 }
-
-/**
- * GetSpans isn't accelerated yet, but performs migration so that we'll
- * hopefully avoid the read-from-framebuffer cost.
- */
-void
-exaGetSpans (DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, int *pwidth,
-	     int nspans, char *pdstStart)
-{
-    ExaMigrationRec pixmaps[1];
-
-    pixmaps[0].as_dst = FALSE;
-    pixmaps[0].as_src = TRUE;
-    pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
-    exaDoMigration (pixmaps, 1, FALSE);
-
-    ExaCheckGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
-}
diff --git a/exa/exa_migration.c b/exa/exa_migration.c
index 5f07a8d..661ff40 100644
--- a/exa/exa_migration.c
+++ b/exa/exa_migration.c
@@ -152,7 +152,7 @@ exaCopyDirtyToSys (PixmapPtr pPixmap)
 						+ pBox->x1 * pPixmap->drawable.bitsPerPixel / 8,
 						pExaPixmap->sys_pitch))
 	{
-	    exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
+	    ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
 	    exaMemcpyBox (pPixmap, pBox,
 			  pExaPixmap->fb_ptr, pExaPixmap->fb_pitch,
 			  pExaPixmap->sys_ptr, pExaPixmap->sys_pitch);
@@ -220,7 +220,7 @@ exaCopyDirtyToFb (PixmapPtr pPixmap)
 					    + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8,
 					    pExaPixmap->sys_pitch))
 	{
-	    exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_DEST);
+	    ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_DEST);
 	    exaMemcpyBox (pPixmap, pBox,
 			  pExaPixmap->sys_ptr, pExaPixmap->sys_pitch,
 			  pExaPixmap->fb_ptr, pExaPixmap->fb_pitch);
@@ -471,7 +471,7 @@ exaAssertNotDirty (PixmapPtr pPixmap)
     src_pitch = pExaPixmap->fb_pitch;
     cpp = pPixmap->drawable.bitsPerPixel / 8;
 
-    exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
+    ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
     while (nbox--) {
 	    int rowbytes;
 
@@ -622,14 +622,9 @@ exaDoMigration (ExaMigrationPtr pixmaps,
 	    exaMoveInPixmap(pixmaps[i].pPix);
 	}
 
-	/* If we couldn't fit everything in, then kick back out */
+	/* If we couldn't fit everything in, abort */
 	for (i = 0; i < npixmaps; i++) {
 	    if (!exaPixmapIsOffscreen(pixmaps[i].pPix)) {
-		EXA_FALLBACK(("Pixmap %p (%dx%d) not in fb\n", pixmaps[i].pPix,
-			      pixmaps[i].pPix->drawable.width,
-			      pixmaps[i].pPix->drawable.height));
-		for (j = 0; j < npixmaps; j++)
-		    exaMoveOutPixmap(pixmaps[j].pPix);
 		return;
 	    }
 	}
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index a08acfa..409bc4d 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -298,10 +298,6 @@ void
 exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
 	     unsigned int format, unsigned long planeMask, char *d);
 
-void
-exaGetSpans (DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, int *pwidth,
-	     int nspans, char *pdstStart);
-
 extern const GCOps exaOps;
 
 #ifdef MITSHM
@@ -339,6 +335,9 @@ ExaOffscreenFini (ScreenPtr pScreen);
 
 /* exa.c */
 void
+ExaDoPrepareAccess(DrawablePtr pDrawable, int index);
+
+void
 exaPrepareAccess(DrawablePtr pDrawable, int index);
 
 void
diff --git a/exa/exa_render.c b/exa/exa_render.c
index 2dd3fc1..738ac15 100644
--- a/exa/exa_render.c
+++ b/exa/exa_render.c
@@ -738,7 +738,6 @@ fallback:
     exaPrintCompositeFallback (op, pSrc, pMask, pDst);
 #endif
 
-    exaDoMigration(pixmaps, npixmaps, FALSE);
     ExaCheckComposite (op, pSrc, pMask, pDst, xSrc, ySrc,
 		      xMask, yMask, xDst, yDst, width, height);
 
@@ -889,18 +888,13 @@ exaRasterizeTrapezoid (PicturePtr pPictu
 		       int x_off, int y_off)
 {
     DrawablePtr pDraw = pPicture->pDrawable;
-    ExaMigrationRec pixmaps[1];
+    PixmapPtr pPixmap = exaGetDrawablePixmap(pDraw);
     int xoff, yoff;
 
-    pixmaps[0].as_dst = TRUE;
-    pixmaps[0].as_src = TRUE;
-    pixmaps[0].pPix = exaGetDrawablePixmap (pDraw);
-    exaDoMigration(pixmaps, 1, FALSE);
-
     exaPrepareAccess(pDraw, EXA_PREPARE_DEST);
     fbRasterizeTrapezoid(pPicture, trap, x_off, y_off);
-    exaGetDrawableDeltas(pDraw, pixmaps[0].pPix, &xoff, &yoff);
-    exaPixmapDirty(pixmaps[0].pPix, pDraw->x + xoff, pDraw->y + yoff,
+    exaGetDrawableDeltas(pDraw, pPixmap, &xoff, &yoff);
+    exaPixmapDirty(pPixmap, pDraw->x + xoff, pDraw->y + yoff,
 		   pDraw->x + xoff + pDraw->width,
 		   pDraw->y + yoff + pDraw->height);
     exaFinishAccess(pDraw, EXA_PREPARE_DEST);
@@ -915,18 +909,13 @@ exaAddTriangles (PicturePtr pPicture, IN
 		 xTriangle *tris)
 {
     DrawablePtr pDraw = pPicture->pDrawable;
-    ExaMigrationRec pixmaps[1];
+    PixmapPtr pPixmap = exaGetDrawablePixmap(pDraw);
     int xoff, yoff;
 
-    pixmaps[0].as_dst = TRUE;
-    pixmaps[0].as_src = TRUE;
-    pixmaps[0].pPix = exaGetDrawablePixmap (pDraw);
-    exaDoMigration(pixmaps, 1, FALSE);
-
     exaPrepareAccess(pDraw, EXA_PREPARE_DEST);
     fbAddTriangles(pPicture, x_off, y_off, ntri, tris);
-    exaGetDrawableDeltas(pDraw, pixmaps[0].pPix, &xoff, &yoff);
-    exaPixmapDirty(pixmaps[0].pPix, pDraw->x + xoff, pDraw->y + yoff,
+    exaGetDrawableDeltas(pDraw, pPixmap, &xoff, &yoff);
+    exaPixmapDirty(pPixmap, pDraw->x + xoff, pDraw->y + yoff,
 		   pDraw->x + xoff + pDraw->width,
 		   pDraw->y + yoff + pDraw->height);
     exaFinishAccess(pDraw, EXA_PREPARE_DEST);
diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c
index 8db2866..8dadd06 100644
--- a/exa/exa_unaccel.c
+++ b/exa/exa_unaccel.c
@@ -41,7 +41,7 @@ void
 exaPrepareAccessGC(GCPtr pGC)
 {
     if (pGC->stipple)
-        exaPrepareAccess(&pGC->stipple->drawable, EXA_PREPARE_SRC);
+        exaPrepareAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK);
     if (pGC->fillStyle == FillTiled)
 	exaPrepareAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC);
 }
@@ -53,7 +53,7 @@ void
 exaFinishAccessGC(GCPtr pGC)
 {
     if (pGC->fillStyle == FillTiled)
-	exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC);
+	exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_MASK);
     if (pGC->stipple)
         exaFinishAccess(&pGC->stipple->drawable, EXA_PREPARE_SRC);
 }
@@ -358,7 +358,6 @@ exaGetPixmapFirstPixel (PixmapPtr pPixma
     void *fb;
     Bool need_finish = FALSE;
     BoxRec box;
-    ExaMigrationRec pixmaps[1];
     ExaPixmapPriv (pPixmap);
 
     fb = pExaPixmap->sys_ptr;
@@ -368,10 +367,6 @@ exaGetPixmapFirstPixel (PixmapPtr pPixma
         miPointInRegion(DamageRegion(pExaPixmap->pDamage), 0, 0,  &box))
     {
 	need_finish = TRUE;
-	pixmaps[0].as_dst = FALSE;
-	pixmaps[0].as_src = TRUE;
-	pixmaps[0].pPix = pPixmap;
-	exaDoMigration (pixmaps, 1, FALSE);
 	exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
 	fb = pPixmap->devPrivate.ptr;
     }
diff-tree 3a4873a46093c37a707e6be0c336a57ab67115ab (from aa7ed1f5f35cd043bc38d985500aa0a32e857e84)
Author: Dave Airlie <airlied at linux.ie>
Date:   Tue Jul 17 17:16:51 2007 +1000

    EXA: Add a couple of missing exaPrepare/FinishAccess calls.

diff --git a/exa/exa.c b/exa/exa.c
index 99707fa..46fb557 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -452,11 +452,9 @@ exaValidateGC (GCPtr pGC, unsigned long 
 	if (!pGC->tileIsPixel && FbEvenTile (pGC->tile.pixmap->drawable.width *
 					     pDrawable->bitsPerPixel))
 	{
-	    /* XXX This fixes corruption with tiled pixmaps, but may just be a
-	     * workaround for broken drivers
-	     */
-	    exaMoveOutPixmap(pGC->tile.pixmap);
+	    exaPrepareAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC);
 	    fbPadPixmap (pGC->tile.pixmap);
+	    exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC);
 	    exaPixmapDirty(pGC->tile.pixmap, 0, 0,
 			   pGC->tile.pixmap->drawable.width,
 			   pGC->tile.pixmap->drawable.height);
@@ -467,7 +465,9 @@ exaValidateGC (GCPtr pGC, unsigned long 
 	changes &= ~GCTile;
     }
 
+    exaPrepareAccessGC(pGC);
     fbValidateGC (pGC, changes, pDrawable);
+    exaFinishAccessGC(pGC);
 
     pGC->ops = (GCOps *) &exaOps;
 }
@@ -497,6 +497,47 @@ exaCreateGC (GCPtr pGC)
     return TRUE;
 }
 
+void
+exaPrepareAccessWindow(WindowPtr pWin)
+{
+    if (pWin->backgroundState == BackgroundPixmap) 
+        exaPrepareAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC);
+
+    if (pWin->borderIsPixel == FALSE)
+        exaPrepareAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_SRC);
+}
+
+void
+exaFinishAccessWindow(WindowPtr pWin)
+{
+    if (pWin->backgroundState == BackgroundPixmap) 
+        exaFinishAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC);
+
+    if (pWin->borderIsPixel == FALSE)
+        exaFinishAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_SRC);
+}
+
+static Bool
+exaChangeWindowAttributes(WindowPtr pWin, unsigned long mask)
+{
+    Bool ret;
+
+    exaPrepareAccessWindow(pWin);
+    ret = fbChangeWindowAttributes(pWin, mask);
+    exaFinishAccessWindow(pWin);
+    return ret;
+}
+
+static RegionPtr
+exaBitmapToRegion(PixmapPtr pPix)
+{
+  RegionPtr ret;
+  exaPrepareAccess(&pPix->drawable, EXA_PREPARE_SRC);
+  ret = fbPixmapToRegion(pPix);
+  exaFinishAccess(&pPix->drawable, EXA_PREPARE_SRC);
+  return ret;
+}
+
 /**
  * exaCloseScreen() unwraps its wrapped screen functions and tears down EXA's
  * screen private, before calling down to the next CloseSccreen.
@@ -518,6 +559,8 @@ exaCloseScreen(int i, ScreenPtr pScreen)
     pScreen->CreatePixmap = pExaScr->SavedCreatePixmap;
     pScreen->DestroyPixmap = pExaScr->SavedDestroyPixmap;
     pScreen->CopyWindow = pExaScr->SavedCopyWindow;
+    pScreen->ChangeWindowAttributes = pExaScr->SavedChangeWindowAttributes;
+    pScreen->BitmapToRegion = pExaScr->SavedBitmapToRegion;
 #ifdef RENDER
     if (ps) {
 	ps->Composite = pExaScr->SavedComposite;
@@ -660,6 +703,12 @@ exaDriverInit (ScreenPtr		pScreen,
     pExaScr->SavedCopyWindow = pScreen->CopyWindow;
     pScreen->CopyWindow = exaCopyWindow;
 
+    pExaScr->SavedChangeWindowAttributes = pScreen->ChangeWindowAttributes;
+    pScreen->ChangeWindowAttributes = exaChangeWindowAttributes;
+
+    pExaScr->SavedBitmapToRegion = pScreen->BitmapToRegion;
+    pScreen->BitmapToRegion = exaBitmapToRegion;
+
     pExaScr->SavedPaintWindowBackground = pScreen->PaintWindowBackground;
     pScreen->PaintWindowBackground = exaPaintWindow;
 
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index a456da0..a08acfa 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -106,6 +106,8 @@ typedef struct {
     DestroyPixmapProcPtr 	 SavedDestroyPixmap;
     PaintWindowBorderProcPtr 	 SavedPaintWindowBorder;
     CopyWindowProcPtr 		 SavedCopyWindow;
+    ChangeWindowAttributesProcPtr SavedChangeWindowAttributes;
+    BitmapToRegionProcPtr        SavedBitmapToRegion;
 #ifdef RENDER
     CompositeProcPtr             SavedComposite;
     RasterizeTrapezoidProcPtr	 SavedRasterizeTrapezoid;
@@ -113,6 +115,7 @@ typedef struct {
     GlyphsProcPtr                SavedGlyphs;
     TrapezoidsProcPtr            SavedTrapezoids;
 #endif
+  
     Bool			 swappedOut;
     enum ExaMigrationHeuristic	 migration;
     Bool			 hideOffscreenPixmapData;
@@ -190,6 +193,12 @@ typedef struct _ExaMigrationRec {
   */
 void exaDDXDriverInit (ScreenPtr pScreen);
 
+void
+exaPrepareAccessWindow(WindowPtr pWin);
+
+void
+exaFinishAccessWindow(WindowPtr pWin);
+
 /* exa_unaccel.c */
 void
 exaPrepareAccessGC(GCPtr pGC);
diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c
index d793ec2..8db2866 100644
--- a/exa/exa_unaccel.c
+++ b/exa/exa_unaccel.c
@@ -35,10 +35,13 @@
  *
  * Solid doesn't use an extra pixmap source, and Stippled/OpaqueStippled are
  * 1bpp and never in fb, so we don't worry about them.
+ * We should worry about them for completeness sake and going forward.
  */
 void
 exaPrepareAccessGC(GCPtr pGC)
 {
+    if (pGC->stipple)
+        exaPrepareAccess(&pGC->stipple->drawable, EXA_PREPARE_SRC);
     if (pGC->fillStyle == FillTiled)
 	exaPrepareAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC);
 }
@@ -51,6 +54,8 @@ exaFinishAccessGC(GCPtr pGC)
 {
     if (pGC->fillStyle == FillTiled)
 	exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC);
+    if (pGC->stipple)
+        exaFinishAccess(&pGC->stipple->drawable, EXA_PREPARE_SRC);
 }
 
 #if DEBUG_TRACE_FALL
@@ -294,7 +299,9 @@ ExaCheckPaintWindow (WindowPtr pWin, Reg
     EXA_FALLBACK(("from %p (%c)\n", pWin,
 		  exaDrawableLocation(&pWin->drawable)));
     exaPrepareAccess (&pWin->drawable, EXA_PREPARE_DEST);
+    exaPrepareAccessWindow(pWin);
     fbPaintWindow (pWin, pRegion, what);
+    exaFinishAccessWindow(pWin);
     exaFinishAccess (&pWin->drawable, EXA_PREPARE_DEST);
 }
 


More information about the xorg-commit mailing list