xserver: Branch 'master' - 16 commits

Michel Daenzer daenzer at kemper.freedesktop.org
Fri Sep 7 15:20:36 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 e8093e15c7df7a3d5a9717bc9d7d7517b0743f29 (from e81af8ba643df3be53b0a46d9d4a0eaf21557c9e)
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 e81af8ba643df3be53b0a46d9d4a0eaf21557c9e (from 5f7da4da8de7449e1c2a4c679632a0b2a5858b7e)
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 5f7da4da8de7449e1c2a4c679632a0b2a5858b7e (from be922b30486abce3a8c13996d579b211a7b56f0e)
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 be922b30486abce3a8c13996d579b211a7b56f0e (from ea92ea415665e294a1ba233e9a1d39b6daa0cee1)
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 ea92ea415665e294a1ba233e9a1d39b6daa0cee1 (from aa2ed73e0ec881947c969b67269e3206da4de359)
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 aa2ed73e0ec881947c969b67269e3206da4de359 (from a634c9b03494ba80aeec28be19662ac96657cc23)
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 a634c9b03494ba80aeec28be19662ac96657cc23 (from 1f457ff3db24178eefecfbbf177aaf6554adb204)
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 1f457ff3db24178eefecfbbf177aaf6554adb204 (from 489bc7551ffc7360ba9648ca5c98b59c7e7a1fd1)
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 489bc7551ffc7360ba9648ca5c98b59c7e7a1fd1 (from 2e0895a4ba27c1308713022820444c8f57f7a69f)
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 2e0895a4ba27c1308713022820444c8f57f7a69f (from 6c9d7ed61bc4a19d21c53717b8af3d90b5d82ca9)
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 6c9d7ed61bc4a19d21c53717b8af3d90b5d82ca9 (from 962eddd7a2863a8475f5fd8107d3112df08d1172)
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 962eddd7a2863a8475f5fd8107d3112df08d1172 (from f27931bdd26fc9a1e6bb5173b5537e32c51a98b3)
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 f27931bdd26fc9a1e6bb5173b5537e32c51a98b3 (from 5c7ee3f47fa0c067102a17dee3f75a51cc0bdb3a)
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 5c7ee3f47fa0c067102a17dee3f75a51cc0bdb3a (from 8cfcf9973c765f11d1b45b95b8091ef7e01d7f01)
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 8cfcf9973c765f11d1b45b95b8091ef7e01d7f01 (from e510a77ba4d65d5d6ead514cd698f1b1e3f8a2b6)
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 e510a77ba4d65d5d6ead514cd698f1b1e3f8a2b6 (from 84eb7e62248ddc2761af8cefe33d1b7147477528)
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