xserver: Branch 'server-1.2-branch' - 2 commits

Eric Anholt anholt at kemper.freedesktop.org
Tue Feb 13 23:22:26 EET 2007


 exa/exa.c                  |  141 +++++++++++++++++++++-------
 exa/exa.h                  |   12 +-
 exa/exa_accel.c            |  159 ++++++++++++++++++++++----------
 exa/exa_migration.c        |  223 +++++++++++++++++++++++++++++----------------
 exa/exa_offscreen.c        |   71 ++++++++++++--
 exa/exa_priv.h             |   31 +++---
 exa/exa_render.c           |   48 ++++++---
 exa/exa_unaccel.c          |   32 +++++-
 hw/xfree86/exa/Makefile.am |    2 
 hw/xfree86/exa/exa.man.pre |    2 
 miext/damage/damage.c      |  150 ++++++++++++++++++++++--------
 miext/damage/damage.h      |    3 
 miext/damage/damagestr.h   |    3 
 13 files changed, 624 insertions(+), 253 deletions(-)

New commits:
diff-tree ed1778cfb2135ee4d21949d8f724e24699bb5e94 (from 9fbb845e8b56847ee6ff7cbb7d941f229a39c407)
Author: Eric Anholt <eric at anholt.net>
Date:   Mon Feb 12 16:08:00 2007 -0800

    Merge EXA updates up to commit cf5b29d75dad7c74543f49f010c817623a3df747.
    
    This is EXA version 2.1, including the damagetrack work.

diff --git a/exa/exa.c b/exa/exa.c
index b490653..e9f42df 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -32,6 +32,10 @@
 #include <dix-config.h>
 #endif
 
+#ifdef MITSHM
+#include "shmint.h"
+#endif
+
 #include <stdlib.h>
 
 #include "exa_priv.h"
@@ -118,17 +122,77 @@ exaGetDrawablePixmap(DrawablePtr pDrawab
 }	
 
 /**
+ * Sets the offsets to add to coordinates to make them address the same bits in
+ * the backing drawable. These coordinates are nonzero only for redirected
+ * windows.
+ */
+static void
+exaGetDrawableDeltas (DrawablePtr pDrawable, PixmapPtr pPixmap,
+		      int *xp, int *yp)
+{
+#ifdef COMPOSITE
+    if (pDrawable->type == DRAWABLE_WINDOW) {
+	*xp = -pPixmap->screen_x;
+	*yp = -pPixmap->screen_y;
+	return;
+    }
+#endif
+
+    *xp = 0;
+    *yp = 0;
+}
+
+/**
+ * exaPixmapDirty() marks a pixmap as dirty, allowing for
+ * optimizations in pixmap migration when no changes have occurred.
+ */
+void
+exaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2)
+{
+    ExaPixmapPriv(pPix);
+    BoxRec box;
+    RegionPtr pDamageReg;
+    RegionRec region;
+
+    if (!pExaPixmap)
+	return;
+	
+    box.x1 = max(x1, 0);
+    box.y1 = max(y1, 0);
+    box.x2 = min(x2, pPix->drawable.width);
+    box.y2 = min(y2, pPix->drawable.height);
+
+    if (box.x1 >= box.x2 || box.y1 >= box.y2)
+	return;
+
+    pDamageReg = DamageRegion(pExaPixmap->pDamage);
+
+    REGION_INIT(pScreen, &region, &box, 1);
+    REGION_UNION(pScreen, pDamageReg, pDamageReg, &region);
+    REGION_UNINIT(pScreen, &region);
+}
+
+/**
  * exaDrawableDirty() marks a pixmap backing a drawable as dirty, allowing for
  * optimizations in pixmap migration when no changes have occurred.
  */
 void
-exaDrawableDirty (DrawablePtr pDrawable)
+exaDrawableDirty (DrawablePtr pDrawable, int x1, int y1, int x2, int y2)
 {
-    ExaPixmapPrivPtr pExaPixmap;
+    PixmapPtr pPix = exaGetDrawablePixmap(pDrawable);
+    int xoff, yoff;
 
-    pExaPixmap = ExaGetPixmapPriv(exaGetDrawablePixmap (pDrawable));
-    if (pExaPixmap != NULL)
-	pExaPixmap->dirty = TRUE;
+    x1 = max(x1, pDrawable->x);
+    y1 = max(y1, pDrawable->y);
+    x2 = min(x2, pDrawable->x + pDrawable->width);
+    y2 = min(y2, pDrawable->y + pDrawable->height);
+
+    if (x1 >= x2 || y1 >= y2)
+	return;
+
+    exaGetDrawableDeltas(pDrawable, pPix, &xoff, &yoff);
+
+    exaPixmapDirty(pPix, x1 + xoff, y1 + yoff, x2 + xoff, y2 + yoff);
 }
 
 static Bool
@@ -149,6 +213,7 @@ exaDestroyPixmap (PixmapPtr pPixmap)
 	    pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
 	    pPixmap->devKind = pExaPixmap->sys_pitch;
 	}
+	REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validReg);
     }
     return fbDestroyPixmap (pPixmap);
 }
@@ -216,7 +281,20 @@ exaCreatePixmap(ScreenPtr pScreen, int w
 	return NULL;
     }
 
-    pExaPixmap->dirty = FALSE;
+    /* Set up damage tracking */
+    pExaPixmap->pDamage = DamageCreate (NULL, NULL, DamageReportNone, TRUE,
+					pScreen, pPixmap);
+
+    if (pExaPixmap->pDamage == NULL) {
+	fbDestroyPixmap (pPixmap);
+	return NULL;
+    }
+
+    DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage);
+    DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE);
+
+    /* None of the pixmap bits are valid initially */
+    REGION_NULL(pScreen, &pExaPixmap->validReg);
 
     return pPixmap;
 }
@@ -261,32 +339,14 @@ exaDrawableIsOffscreen (DrawablePtr pDra
 /**
  * Returns the pixmap which backs a drawable, and the offsets to add to
  * coordinates to make them address the same bits in the backing drawable.
- * These coordinates are nonzero only for redirected windows.
  */
 PixmapPtr
 exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp)
 {
-    PixmapPtr	pPixmap;
-    int		x, y;
+    PixmapPtr	pPixmap = exaGetDrawablePixmap (pDrawable);
+
+    exaGetDrawableDeltas (pDrawable, pPixmap, xp, yp);
 
-    if (pDrawable->type == DRAWABLE_WINDOW) {
-	pPixmap = (*pDrawable->pScreen->GetWindowPixmap) ((WindowPtr) pDrawable);
-#ifdef COMPOSITE
-	x = -pPixmap->screen_x;
-	y = -pPixmap->screen_y;
-#else
-	x = 0;
-	y = 0;
-#endif
-    }
-    else
-    {
-	pPixmap = (PixmapPtr) pDrawable;
-	x = 0;
-	y = 0;
-    }
-    *xp = x;
-    *yp = y;
     if (exaPixmapIsOffscreen (pPixmap))
 	return pPixmap;
     else
@@ -334,8 +394,7 @@ exaPrepareAccess(DrawablePtr pDrawable, 
 /**
  * exaFinishAccess() is EXA's wrapper for the driver's FinishAccess() handler.
  *
- * It deals with marking drawables as dirty, and calling the driver's
- * FinishAccess() only if necessary.
+ * It deals with calling the driver's FinishAccess() only if necessary.
  */
 void
 exaFinishAccess(DrawablePtr pDrawable, int index)
@@ -345,9 +404,6 @@ exaFinishAccess(DrawablePtr pDrawable, i
     PixmapPtr	    pPixmap;
     ExaPixmapPrivPtr pExaPixmap;
 
-    if (index == EXA_PREPARE_DEST)
-	exaDrawableDirty (pDrawable);
-
     pPixmap = exaGetDrawablePixmap (pDrawable);
 
     pExaPixmap = ExaGetPixmapPriv(pPixmap);
@@ -373,7 +429,7 @@ exaFinishAccess(DrawablePtr pDrawable, i
  * accelerated or may sync the card and fall back to fb.
  */
 static void
-exaValidateGC (GCPtr pGC, Mask changes, DrawablePtr pDrawable)
+exaValidateGC (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
 {
     /* fbValidateGC will do direct access to pixmaps if the tiling has changed.
      * Preempt fbValidateGC by doing its work and masking the change out, so
@@ -404,6 +460,7 @@ exaValidateGC (GCPtr pGC, Mask changes, 
 		exaPrepareAccess(&pOldTile->drawable, EXA_PREPARE_SRC);
 		pNewTile = fb24_32ReformatTile (pOldTile,
 						pDrawable->bitsPerPixel);
+		exaPixmapDirty(pNewTile, 0, 0, pNewTile->drawable.width, pNewTile->drawable.height);
 		exaFinishAccess(&pOldTile->drawable, EXA_PREPARE_SRC);
 	    }
 	    if (pNewTile)
@@ -419,9 +476,14 @@ exaValidateGC (GCPtr pGC, Mask changes, 
 	if (!pGC->tileIsPixel && FbEvenTile (pGC->tile.pixmap->drawable.width *
 					     pDrawable->bitsPerPixel))
 	{
-	    exaPrepareAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC);
+	    /* XXX This fixes corruption with tiled pixmaps, but may just be a
+	     * workaround for broken drivers
+	     */
+	    exaMoveOutPixmap(pGC->tile.pixmap);
 	    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);
 	}
 	/* Mask out the GCTile change notification, now that we've done FB's
 	 * job for it.
@@ -560,7 +622,7 @@ exaDriverInit (ScreenPtr		pScreen,
 
     pScreen->devPrivates[exaScreenPrivateIndex].ptr = (pointer) pExaScr;
 
-    pExaScr->migration = ExaMigrationSmart;
+    pExaScr->migration = ExaMigrationAlways;
 
     exaDDXDriverInit(pScreen);
 
@@ -610,6 +672,13 @@ exaDriverInit (ScreenPtr		pScreen,
     miDisableCompositeWrapper(pScreen);
 #endif
 
+#ifdef MITSHM
+    /* Re-register with the MI funcs, which don't allow shared pixmaps.
+     * Shared pixmaps are almost always a performance loss for us, but this
+     * still allows for SHM PutImage.
+     */
+    ShmRegisterFuncs(pScreen, NULL);
+#endif
     /*
      * Hookup offscreen pixmaps
      */
diff --git a/exa/exa.h b/exa/exa.h
index 96465a7..bf723f7 100644
--- a/exa/exa.h
+++ b/exa/exa.h
@@ -39,7 +39,7 @@
 #include "fb.h"
 
 #define EXA_VERSION_MAJOR   2
-#define EXA_VERSION_MINOR   0
+#define EXA_VERSION_MINOR   1
 #define EXA_VERSION_RELEASE 0
 
 typedef struct _ExaOffscreenArea ExaOffscreenArea;
@@ -73,8 +73,8 @@ struct _ExaOffscreenArea {
 typedef struct _ExaDriver {
     /**
      * exa_major and exa_minor should be set by the driver to the version of
-     * EXA which the driver was compiled for (or configures itself at runtime to
-     * support).  This allows EXA to extend the structure for new features
+     * EXA which the driver was compiled for (or configures itself at runtime
+     * to support).  This allows EXA to extend the structure for new features
      * without breaking ABI for drivers compiled against older versions.
      */
     int exa_major, exa_minor;
@@ -716,6 +716,12 @@ exaGetPixmapSize(PixmapPtr pPix);
 void
 exaEnableDisableFBAccess (int index, Bool enable);
 
+void
+exaMoveInPixmap (PixmapPtr pPixmap);
+
+void
+exaMoveOutPixmap (PixmapPtr pPixmap);
+
 /**
  * Returns TRUE if the given planemask covers all the significant bits in the
  * pixel values for pDrawable.
diff --git a/exa/exa_accel.c b/exa/exa_accel.c
index bc77a40..6fa481a 100644
--- a/exa/exa_accel.c
+++ b/exa/exa_accel.c
@@ -20,6 +20,11 @@
  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric at anholt.net>
+ *    Michel Dänzer <michel at tungstengraphics.com>
+ *
  */
 
 #ifdef HAVE_DIX_CONFIG_H
@@ -49,12 +54,12 @@ exaFillSpans(DrawablePtr pDrawable, GCPt
 
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = FALSE;
-    pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
+    pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
 
     if (pExaScr->swappedOut ||
 	pGC->fillStyle != FillSolid ||
-	pDrawable->width > pExaScr->info->maxX ||
-	pDrawable->height > pExaScr->info->maxY)
+	pPixmap->drawable.width > pExaScr->info->maxX ||
+	pPixmap->drawable.height > pExaScr->info->maxY)
     {
 	exaDoMigration (pixmaps, 1, FALSE);
 	ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
@@ -104,6 +109,8 @@ exaFillSpans(DrawablePtr pDrawable, GCPt
 	    (*pExaScr->info->Solid) (pPixmap,
 				     fullX1 + off_x, fullY1 + off_y,
 				     fullX2 + off_x, fullY1 + 1 + off_y);
+	    exaPixmapDirty (pPixmap, fullX1 + off_x, fullY1 + off_y,
+			    fullX2 + off_x, fullY1 + 1 + off_y);
 	}
 	else
 	{
@@ -118,17 +125,19 @@ exaFillSpans(DrawablePtr pDrawable, GCPt
 		    partX2 = pbox->x2;
 		    if (partX2 > fullX2)
 			partX2 = fullX2;
-		    if (partX2 > partX1)
+		    if (partX2 > partX1) {
 			(*pExaScr->info->Solid) (pPixmap,
 						 partX1 + off_x, fullY1 + off_y,
 						 partX2 + off_x, fullY1 + 1 + off_y);
+			exaPixmapDirty (pPixmap, partX1 + off_x, fullY1 + off_y,
+					partX2 + off_x, fullY1 + 1 + off_y);
+		    }
 		}
 		pbox++;
 	    }
 	}
     }
     (*pExaScr->info->DoneSolid) (pPixmap);
-    exaDrawableDirty (pDrawable);
     exaMarkSync(pScreen);
 }
 
@@ -222,8 +231,8 @@ exaPutImage (DrawablePtr pDrawable, GCPt
 
 	    exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
 	}
+	exaPixmapDirty(pPix, x1 + xoff, y1 + yoff, x2 + xoff, y2 + yoff);
     }
-    exaDrawableDirty(pDrawable);
 
     return;
 
@@ -351,11 +360,12 @@ 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);
     exaMarkSync(pDstDrawable->pScreen);
-    exaDrawableDirty(pDstDrawable);
     return TRUE;
 }
 
@@ -380,19 +390,19 @@ exaCopyNtoN (DrawablePtr    pSrcDrawable
 
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = FALSE;
-    pixmaps[0].pPix = exaGetDrawablePixmap (pDstDrawable);
+    pixmaps[0].pPix = pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
     pixmaps[1].as_dst = FALSE;
     pixmaps[1].as_src = TRUE;
-    pixmaps[1].pPix = exaGetDrawablePixmap (pSrcDrawable);
+    pixmaps[1].pPix = pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
 
     /* 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
      * adjusted so that the drawing happened within limits.
      */
-    if (pSrcDrawable->width > pExaScr->info->maxX ||
-	pSrcDrawable->height > pExaScr->info->maxY ||
-	pDstDrawable->width > pExaScr->info->maxX ||
-	pDstDrawable->height > pExaScr->info->maxY)
+    if (pSrcPixmap->drawable.width > pExaScr->info->maxX ||
+	pSrcPixmap->drawable.height > pExaScr->info->maxY ||
+	pDstPixmap->drawable.width > pExaScr->info->maxX ||
+	pDstPixmap->drawable.height > pExaScr->info->maxY)
     {
 	exaDoMigration (pixmaps, 2, FALSE);
 	goto fallback;
@@ -401,7 +411,8 @@ exaCopyNtoN (DrawablePtr    pSrcDrawable
     }
 
     /* Mixed directions must be handled specially if the card is lame */
-    if (pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS && (dx*dy) < 0) {
+    if (pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS &&
+	reverse != upsidedown) {
 	if (!exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
 			       dx, dy))
 	    goto fallback;
@@ -411,7 +422,7 @@ exaCopyNtoN (DrawablePtr    pSrcDrawable
     if ((pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y)) &&
 	(pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y)) &&
 	(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap,
-				       dx, dy,
+				       reverse ? -1 : 1, upsidedown ? -1 : 1,
 				       pGC ? pGC->alu : GXcopy,
 				       pGC ? pGC->planemask : FB_ALLONES))
     {
@@ -423,11 +434,13 @@ exaCopyNtoN (DrawablePtr    pSrcDrawable
 				    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);
 	    pbox++;
 	}
 	(*pExaScr->info->DoneCopy) (pDstPixmap);
 	exaMarkSync(pDstDrawable->pScreen);
-	exaDrawableDirty (pDstDrawable);
 	return;
     }
 
@@ -442,6 +455,11 @@ fallback:
 		bitplane, closure);
     exaFinishAccess (pSrcDrawable, EXA_PREPARE_SRC);
     exaFinishAccess (pDstDrawable, EXA_PREPARE_DEST);
+    while (nbox--)
+    {
+	exaDrawableDirty (pDstDrawable, pbox->x1, pbox->y1, pbox->x2, pbox->y2);
+	pbox++;
+    }
 }
 
 RegionPtr
@@ -621,12 +639,12 @@ exaPolyFillRect(DrawablePtr pDrawable,
 
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = FALSE;
-    pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
+    pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
  
     if (pExaScr->swappedOut ||
 	pGC->fillStyle != FillSolid ||
-	pDrawable->width > pExaScr->info->maxX ||
-	pDrawable->height > pExaScr->info->maxY)
+	pPixmap->drawable.width > pExaScr->info->maxX ||
+	pPixmap->drawable.height > pExaScr->info->maxY)
     {
 	exaDoMigration (pixmaps, 1, FALSE);
 	ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect);
@@ -681,6 +699,8 @@ exaPolyFillRect(DrawablePtr pDrawable,
 	    (*pExaScr->info->Solid) (pPixmap,
 				     fullX1 + xoff, fullY1 + yoff,
 				     fullX2 + xoff, fullY2 + yoff);
+	    exaPixmapDirty (pPixmap, fullX1 + xoff, fullY1 + yoff,
+			    fullX2 + xoff, fullY2 + yoff);
 	}
 	else
 	{
@@ -706,15 +726,17 @@ exaPolyFillRect(DrawablePtr pDrawable,
 
 		pbox++;
 
-		if (partX1 < partX2 && partY1 < partY2)
+		if (partX1 < partX2 && partY1 < partY2) {
 		    (*pExaScr->info->Solid) (pPixmap,
 					     partX1 + xoff, partY1 + yoff,
 					     partX2 + xoff, partY2 + yoff);
+		    exaPixmapDirty (pPixmap, partX1 + xoff, partY1 + yoff,
+				    partX2 + xoff, partY2 + yoff);
+		}
 	    }
 	}
     }
     (*pExaScr->info->DoneSolid) (pPixmap);
-    exaDrawableDirty (pDrawable);
     exaMarkSync(pDrawable->pScreen);
 }
 
@@ -735,14 +757,15 @@ exaSolidBoxClipped (DrawablePtr	pDrawabl
     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 = exaGetDrawablePixmap (pDrawable);
- 
+    pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
+
     if (pExaScr->swappedOut ||
-	pDrawable->width > pExaScr->info->maxX ||
-	pDrawable->height > pExaScr->info->maxY)
+	pPixmap->drawable.width > pExaScr->info->maxX ||
+	pPixmap->drawable.height > pExaScr->info->maxY)
     {
 	exaDoMigration (pixmaps, 1, FALSE);
 	goto fallback;
@@ -750,19 +773,21 @@ exaSolidBoxClipped (DrawablePtr	pDrawabl
 	exaDoMigration (pixmaps, 1, TRUE);
     }
 
-    if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) ||
+    pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
+
+    if (!pPixmap ||
 	!(*pExaScr->info->PrepareSolid) (pPixmap, GXcopy, pm, fg))
     {
 fallback:
 	EXA_FALLBACK(("to %p (%c)\n", pDrawable,
 		      exaDrawableLocation(pDrawable)));
+	fallback = TRUE;
 	exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
 	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);
-	return;
     }
     for (nbox = REGION_NUM_RECTS(pClip), pbox = REGION_RECTS(pClip);
 	 nbox--;
@@ -790,12 +815,20 @@ fallback:
 	if (partY2 <= partY1)
 	    continue;
 
-	(*pExaScr->info->Solid) (pPixmap,
-				 partX1 + xoff, partY1 + yoff,
-				 partX2 + xoff, partY2 + yoff);
+	if (!fallback) {
+	    (*pExaScr->info->Solid) (pPixmap,
+				     partX1 + xoff, partY1 + yoff,
+				     partX2 + xoff, partY2 + yoff);
+	    exaPixmapDirty (pPixmap, partX1 + xoff, partY1 + yoff,
+			    partX2 + xoff, partY2 + yoff);
+	} else
+	    exaDrawableDirty (pDrawable, partX1, partY1, partX2, partY2);
     }
+
+    if (fallback)
+	return;
+
     (*pExaScr->info->DoneSolid) (pPixmap);
-    exaDrawableDirty (pDrawable);
     exaMarkSync(pDrawable->pScreen);
 }
 
@@ -908,12 +941,17 @@ exaImageGlyphBlt (DrawablePtr	pDrawable,
 			  pPriv->fg,
 			  gx + dstXoff,
 			  gHeight);
+		exaDrawableDirty (pDrawable, gx, gy, gx + gWidth, gy + gHeight);
 	    }
 	    else
 	    {
+		RegionPtr pClip = fbGetCompositeClip(pGC);
+		int nbox;
+		BoxPtr pbox;
+
 		gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof (FbStip);
 		fbPutXYImage (pDrawable,
-			      fbGetCompositeClip(pGC),
+			      pClip,
 			      pPriv->fg,
 			      pPriv->bg,
 			      pPriv->pm,
@@ -927,6 +965,18 @@ exaImageGlyphBlt (DrawablePtr	pDrawable,
 			      (FbStip *) pglyph,
 			      gStride,
 			      0);
+
+		for (nbox = REGION_NUM_RECTS(pClip), pbox = REGION_RECTS(pClip);
+		     nbox--; pbox++) {
+		    int x1 = max(gx, pbox->x1), x2 = min(gx + gWidth, pbox->x2);
+		    int y1 = max(gy, pbox->y1), y2 = min(gy + gHeight, pbox->y2);
+
+		    if (x1 >= x2 || y1 >= y2)
+			continue;
+
+		    exaDrawableDirty (pDrawable, gx, gy, gx + gWidth,
+				      gy + gHeight);
+		}
 	    }
 	}
 	x += pci->metrics.characterWidth;
@@ -994,13 +1044,15 @@ 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;
-    pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
+    pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
  
-    if (pDrawable->width > pExaScr->info->maxX ||
-	pDrawable->height > pExaScr->info->maxY)
+    if (pPixmap->drawable.width > pExaScr->info->maxX ||
+	pPixmap->drawable.height > pExaScr->info->maxY)
     {
 	exaDoMigration (pixmaps, 1, FALSE);
 	goto fallback;
@@ -1011,19 +1063,17 @@ exaFillRegionSolid (DrawablePtr	pDrawabl
     if ((pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) &&
 	(*pExaScr->info->PrepareSolid) (pPixmap, GXcopy, FB_ALLONES, pixel))
     {
-	int	nbox = REGION_NUM_RECTS (pRegion);
-	BoxPtr	pBox = REGION_RECTS (pRegion);
-
 	while (nbox--)
 	{
 	    (*pExaScr->info->Solid) (pPixmap,
 				     pBox->x1 + xoff, pBox->y1 + yoff,
 				     pBox->x2 + xoff, pBox->y2 + yoff);
+	    exaPixmapDirty (pPixmap, pBox->x1 + xoff, pBox->y1 + yoff,
+			    pBox->x2 + xoff, pBox->y2 + yoff);
 	    pBox++;
 	}
 	(*pExaScr->info->DoneSolid) (pPixmap);
 	exaMarkSync(pDrawable->pScreen);
-	exaDrawableDirty (pDrawable);
     }
     else
     {
@@ -1034,6 +1084,11 @@ fallback:
 	fbFillRegionSolid (pDrawable, pRegion, 0,
 			   fbReplicatePixel (pixel, pDrawable->bitsPerPixel));
 	exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
+	while (nbox--)
+	{
+	    exaDrawableDirty (pDrawable, pBox->x1, pBox->y1, pBox->x2, pBox->y2);
+	    pBox++;
+	}
     }
 }
 
@@ -1047,9 +1102,11 @@ exaFillRegionTiled (DrawablePtr	pDrawabl
 {
     ExaScreenPriv(pDrawable->pScreen);
     PixmapPtr pPixmap;
-    int xoff, yoff;
+    int xoff, yoff, tileXoff, tileYoff;
     int tileWidth, tileHeight;
     ExaMigrationRec pixmaps[2];
+    int nbox = REGION_NUM_RECTS (pRegion);
+    BoxPtr pBox = REGION_RECTS (pRegion);
 
     tileWidth = pTile->drawable.width;
     tileHeight = pTile->drawable.height;
@@ -1064,13 +1121,13 @@ exaFillRegionTiled (DrawablePtr	pDrawabl
 
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = FALSE;
-    pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
+    pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
     pixmaps[1].as_dst = FALSE;
     pixmaps[1].as_src = TRUE;
     pixmaps[1].pPix = pTile;
 
-    if (pDrawable->width > pExaScr->info->maxX ||
-	pDrawable->height > pExaScr->info->maxY ||
+    if (pPixmap->drawable.width > pExaScr->info->maxX ||
+	pPixmap->drawable.height > pExaScr->info->maxY ||
 	tileWidth > pExaScr->info->maxX ||
 	tileHeight > pExaScr->info->maxY)
     {
@@ -1081,18 +1138,16 @@ exaFillRegionTiled (DrawablePtr	pDrawabl
     }
 
     pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
+
     if (!pPixmap)
 	goto fallback;
 
     if (!exaPixmapIsOffscreen(pTile))
 	goto fallback;
 
-    if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 0, 0, GXcopy,
+    if ((*pExaScr->info->PrepareCopy) (exaGetOffscreenPixmap((DrawablePtr)pTile, &tileXoff, &tileYoff), pPixmap, 0, 0, GXcopy,
 				       FB_ALLONES))
     {
-	int nbox = REGION_NUM_RECTS (pRegion);
-	BoxPtr pBox = REGION_RECTS (pRegion);
-
 	while (nbox--)
 	{
 	    int height = pBox->y2 - pBox->y1;
@@ -1118,7 +1173,7 @@ exaFillRegionTiled (DrawablePtr	pDrawabl
 		    width -= w;
 
 		    (*pExaScr->info->Copy) (pPixmap,
-					    tileX, tileY,
+					    tileX + tileXoff, tileY + tileYoff,
 					    dstX + xoff, dstY + yoff,
 					    w, h);
 		    dstX += w;
@@ -1127,11 +1182,12 @@ exaFillRegionTiled (DrawablePtr	pDrawabl
 		dstY += h;
 		tileY = 0;
 	    }
+	    exaPixmapDirty (pPixmap, pBox->x1 + xoff, pBox->y1 + yoff,
+			    pBox->x2 + xoff, pBox->y2 + yoff);
 	    pBox++;
 	}
 	(*pExaScr->info->DoneCopy) (pPixmap);
 	exaMarkSync(pDrawable->pScreen);
-	exaDrawableDirty (pDrawable);
 	return;
     }
 
@@ -1144,6 +1200,11 @@ fallback:
     fbFillRegionTiled (pDrawable, pRegion, pTile);
     exaFinishAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC);
     exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
+    while (nbox--)
+    {
+	exaDrawableDirty (pDrawable, pBox->x1, pBox->y1, pBox->x2, pBox->y2);
+	pBox++;
+    }
 }
 
 void
diff --git a/exa/exa_migration.c b/exa/exa_migration.c
index 06a4b93..eedc5fd 100644
--- a/exa/exa_migration.c
+++ b/exa/exa_migration.c
@@ -22,6 +22,7 @@
  *
  * Authors:
  *    Eric Anholt <eric at anholt.net>
+ *    Michel Dänzer <michel at tungstengraphics.com>
  *
  */
 
@@ -58,6 +59,27 @@ exaPixmapIsPinned (PixmapPtr pPix)
 }
 
 /**
+ * The fallback path for UTS/DFS failing is to just memcpy.  exaCopyDirtyToSys
+ * and exaCopyDirtyToFb both needed to do this loop.
+ */
+static void
+exaMemcpyBox (PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int src_pitch,
+	      CARD8 *dst, int dst_pitch)
+ {
+    int i, cpp = pPixmap->drawable.bitsPerPixel / 8;
+    int bytes = (pbox->x2 - pbox->x1) * cpp;
+
+    src += pbox->y1 * src_pitch + pbox->x1 * cpp;
+    dst += pbox->y1 * dst_pitch + pbox->x1 * cpp;
+
+    for (i = pbox->y2 - pbox->y1; i; i--) {
+	memcpy (dst, src, bytes);
+	src += src_pitch;
+	dst += dst_pitch;
+    }
+}
+ 
+/**
  * Returns TRUE if the pixmap is dirty (has been modified in its current
  * location compared to the other), or lacks a private for tracking
  * dirtiness.
@@ -67,7 +89,8 @@ exaPixmapIsDirty (PixmapPtr pPix)
 {
     ExaPixmapPriv (pPix);
 
-    return pExaPixmap == NULL || pExaPixmap->dirty == TRUE;
+    return pExaPixmap == NULL ||
+	REGION_NOTEMPTY (pScreen, DamageRegion(pExaPixmap->pDamage));
 }
 
 /**
@@ -98,54 +121,62 @@ exaCopyDirtyToSys (PixmapPtr pPixmap)
 {
     ExaScreenPriv (pPixmap->drawable.pScreen);
     ExaPixmapPriv (pPixmap);
+    RegionPtr pRegion = DamageRegion (pExaPixmap->pDamage);
     CARD8 *save_ptr;
     int save_pitch;
-
-    if (!pExaPixmap->dirty)
-	return;
+    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;
 
-    if (pExaScr->info->DownloadFromScreen == NULL ||
-	!pExaScr->info->DownloadFromScreen (pPixmap,
-					    0,
-					    0,
-					    pPixmap->drawable.width,
-					    pPixmap->drawable.height,
-					    pExaPixmap->sys_ptr,
-					    pExaPixmap->sys_pitch))
-    {
-	char *src, *dst;
-	int src_pitch, dst_pitch, i, bytes;
-
-	exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
-
-	dst = pExaPixmap->sys_ptr;
-	dst_pitch = pExaPixmap->sys_pitch;
-	src = pExaPixmap->fb_ptr;
-	src_pitch = pExaPixmap->fb_pitch;
-	bytes = src_pitch < dst_pitch ? src_pitch : dst_pitch;
-
-	for (i = 0; i < pPixmap->drawable.height; i++) {
-	    memcpy (dst, src, bytes);
-	    dst += dst_pitch;
-	    src += src_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->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))
+	{
+	    exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
+	    exaMemcpyBox (pPixmap, pBox,
+			  pExaPixmap->fb_ptr, pExaPixmap->fb_pitch,
+			  pExaPixmap->sys_ptr, pExaPixmap->sys_pitch);
+	    exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
 	}
-	exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
+	else
+	    do_sync = TRUE;
+
+	pBox++;
     }
 
     /* Make sure the bits have actually landed, since we don't necessarily sync
      * when accessing pixmaps in system memory.
      */
-    exaWaitSync (pPixmap->drawable.pScreen);
+    if (do_sync)
+	exaWaitSync (pPixmap->drawable.pScreen);
 
     pPixmap->devPrivate.ptr = save_ptr;
     pPixmap->devKind = save_pitch;
 
-    pExaPixmap->dirty = FALSE;
+    /* The previously damaged bits are now no longer damaged but valid */
+    REGION_UNION(pPixmap->drawable.pScreen,
+		 &pExaPixmap->validReg, &pExaPixmap->validReg, pRegion);
+    DamageEmpty (pExaPixmap->pDamage);
 }
 
 /**
@@ -158,49 +189,59 @@ exaCopyDirtyToFb (PixmapPtr pPixmap)
 {
     ExaScreenPriv (pPixmap->drawable.pScreen);
     ExaPixmapPriv (pPixmap);
+    RegionPtr pRegion = DamageRegion (pExaPixmap->pDamage);
     CARD8 *save_ptr;
     int save_pitch;
-
-    if (!pExaPixmap->dirty)
-	return;
+    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;
 
-    if (pExaScr->info->UploadToScreen == NULL ||
-	!pExaScr->info->UploadToScreen (pPixmap,
-					0,
-					0,
-					pPixmap->drawable.width,
-					pPixmap->drawable.height,
-					pExaPixmap->sys_ptr,
-					pExaPixmap->sys_pitch))
-    {
-	char *src, *dst;
-	int src_pitch, dst_pitch, i, bytes;
-
-	exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_DEST);
-
-	dst = pExaPixmap->fb_ptr;
-	dst_pitch = pExaPixmap->fb_pitch;
-	src = pExaPixmap->sys_ptr;
-	src_pitch = pExaPixmap->sys_pitch;
-	bytes = src_pitch < dst_pitch ? src_pitch : dst_pitch;
-
-	for (i = 0; i < pPixmap->drawable.height; i++) {
-	    memcpy (dst, src, bytes);
-	    dst += dst_pitch;
-	    src += src_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))
+	{
+	    exaPrepareAccess(&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);
 	}
-	exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_DEST);
+	else
+	    do_sync = TRUE;
+
+	pBox++;
     }
 
+    if (do_sync)
+	exaMarkSync (pPixmap->drawable.pScreen);
+
     pPixmap->devPrivate.ptr = save_ptr;
     pPixmap->devKind = save_pitch;
 
-    pExaPixmap->dirty = FALSE;
+    /* The previously damaged bits are now no longer damaged but valid */
+    REGION_UNION(pPixmap->drawable.pScreen,
+		 &pExaPixmap->validReg, &pExaPixmap->validReg, pRegion);
+    DamageEmpty (pExaPixmap->pDamage);
 }
 
 /**
@@ -208,11 +249,12 @@ exaCopyDirtyToFb (PixmapPtr pPixmap)
  * Called when the memory manager decides it's time to kick the pixmap out of
  * framebuffer entirely.
  */
-static void
+void
 exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area)
 {
     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 ?
@@ -231,10 +273,9 @@ exaPixmapSave (ScreenPtr pScreen, ExaOff
     pExaPixmap->fb_ptr = NULL;
     pExaPixmap->area = NULL;
 
-    /* Mark it dirty now, to say that there is important data in the
-     * system-memory copy.
-     */
-    pExaPixmap->dirty = TRUE;
+    /* Mark all valid bits as damaged, so they'll get copied to FB next time */
+    REGION_UNION(pPixmap->drawable.pScreen, pDamageReg, pDamageReg,
+		 &pExaPixmap->validReg);
 }
 
 /**
@@ -413,32 +454,57 @@ exaMigrateTowardSys (PixmapPtr pPixmap)
  * If the pixmap has both a framebuffer and system memory copy, this function
  * asserts that both of them are the same.
  */
-static void
+static Bool
 exaAssertNotDirty (PixmapPtr pPixmap)
 {
     ExaPixmapPriv (pPixmap);
     CARD8 *dst, *src;
-    int dst_pitch, src_pitch, data_row_bytes, y;
+    RegionPtr pValidReg = &pExaPixmap->validReg;
+    int dst_pitch, src_pitch, cpp, y, nbox = REGION_NUM_RECTS(pValidReg);
+    BoxPtr pBox = REGION_RECTS(pValidReg);
+    Bool ret = TRUE;
 
     if (pExaPixmap == NULL || pExaPixmap->fb_ptr == NULL)
-	return;
+	return ret;
 
     dst = pExaPixmap->sys_ptr;
     dst_pitch = pExaPixmap->sys_pitch;
     src = pExaPixmap->fb_ptr;
     src_pitch = pExaPixmap->fb_pitch;
-    data_row_bytes = pPixmap->drawable.width *
-		     pPixmap->drawable.bitsPerPixel / 8;
+    cpp = pPixmap->drawable.bitsPerPixel / 8;
 
     exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
-    for (y = 0; y < pPixmap->drawable.height; y++) {
-	if (memcmp(dst, src, data_row_bytes) != 0) {
-	     abort();
-	}
-	dst += dst_pitch;
-	src += src_pitch;
+    while (nbox--) {
+	    int rowbytes;
+
+	    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;
+
+	    rowbytes = (pBox->x2 - pBox->x1) * cpp;
+	    src += pBox->y1 * src_pitch + pBox->x1 * cpp;
+	    dst += pBox->y1 * dst_pitch + pBox->x1 * cpp;
+
+	    for (y = pBox->y2 - pBox->y1; y; y--) {
+		if (memcmp(dst + pBox->y1 * dst_pitch + pBox->x1 * cpp,
+			   src + pBox->y1 * src_pitch + pBox->x1 * cpp,
+			   (pBox->x2 - pBox->x1) * cpp) != 0) {
+		    ret = FALSE;
+		    break;
+		}
+		src += src_pitch;
+		dst += dst_pitch;
+	    }
+	    src -= pBox->y1 * src_pitch + pBox->x1 * cpp;
+	    dst -= pBox->y1 * dst_pitch + pBox->x1 * cpp;
     }
     exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
+
+    return ret;
 }
 
 /**
@@ -462,8 +528,9 @@ exaDoMigration (ExaMigrationPtr pixmaps,
      */
     if (pExaScr->checkDirtyCorrectness) {
 	for (i = 0; i < npixmaps; i++) {
-	    if (!exaPixmapIsDirty (pixmaps[i].pPix))
-		exaAssertNotDirty (pixmaps[i].pPix);
+	    if (!exaPixmapIsDirty (pixmaps[i].pPix) &&
+		!exaAssertNotDirty (pixmaps[i].pPix))
+		ErrorF("%s: Pixmap %d dirty but not marked as such!\n", __func__, i);
 	}
     }
     /* If anything is pinned in system memory, we won't be able to
diff --git a/exa/exa_offscreen.c b/exa/exa_offscreen.c
index 9e0aa5d..7708dd7 100644
--- a/exa/exa_offscreen.c
+++ b/exa/exa_offscreen.c
@@ -81,15 +81,14 @@ ExaOffscreenKickOut (ScreenPtr pScreen, 
  * @param save callback for when the area is evicted from memory
  * @param privdata private data for the save callback.
  *
- * Allocates offscreen memory from the device associated with pScreen.  size and
- * align deteremine where and how large the allocated area is, and locked will
- * mark whether it should be held in card memory.  privdata may be any pointer
- * for the save callback when the area is removed.
+ * Allocates offscreen memory from the device associated with pScreen.  size
+ * and align deteremine where and how large the allocated area is, and locked
+ * will mark whether it should be held in card memory.  privdata may be any
+ * pointer for the save callback when the area is removed.
  *
- * Note that locked areas do get evicted on VT switch, because during that time
- * all offscreen memory becomes inaccessible.  This may change in the future,
- * but drivers should be aware of this and provide a callback to mark that their
- * locked allocation was evicted, and then restore it if necessary on EnterVT.
+ * Note that locked areas do get evicted on VT switch unless the driver
+ * requested version 2.1 or newer behavior.  In that case, the save callback is
+ * still called.
  */
 ExaOffscreenArea *
 exaOffscreenAlloc (ScreenPtr pScreen, int size, int align,
@@ -256,6 +255,9 @@ exaOffscreenAlloc (ScreenPtr pScreen, in
     return area;
 }
 
+/**
+ * Ejects all offscreen areas, and uninitializes the offscreen memory manager.
+ */
 void
 ExaOffscreenSwapOut (ScreenPtr pScreen)
 {
@@ -283,12 +285,56 @@ ExaOffscreenSwapOut (ScreenPtr pScreen)
     ExaOffscreenFini (pScreen);
 }
 
+/** Ejects all pixmaps managed by EXA. */
+static void
+ExaOffscreenEjectPixmaps (ScreenPtr pScreen)
+{
+    ExaScreenPriv (pScreen);
+
+    ExaOffscreenValidate (pScreen);
+    /* loop until a single free area spans the space */
+    for (;;)
+    {
+	ExaOffscreenArea *area;
+
+	for (area = pExaScr->info->offScreenAreas; area != NULL;
+	     area = area->next)
+	{
+	    if (area->state == ExaOffscreenRemovable &&
+		area->save == exaPixmapSave)
+	    {
+		(void) ExaOffscreenKickOut (pScreen, area);
+		ExaOffscreenValidate (pScreen);
+		break;
+	    }
+	}
+	if (area == NULL)
+	    break;
+    }
+    ExaOffscreenValidate (pScreen);
+}
+
 void
 ExaOffscreenSwapIn (ScreenPtr pScreen)
 {
     exaOffscreenInit (pScreen);
 }
 
+/**
+ * Prepares EXA for disabling of FB access, or restoring it.
+ *
+ * In version 2.1, the disabling results in pixmaps being ejected, while other
+ * allocations remain.  With this plus the prevention of migration while
+ * swappedOut is set, EXA by itself should not cause any access of the
+ * framebuffer to occur while swapped out.  Any remaining issues are the
+ * responsibility of the driver.
+ *
+ * Prior to version 2.1, all allocations, including locked ones, are ejected
+ * when access is disabled, and the allocator is torn down while swappedOut
+ * is set.  This is more drastic, and caused implementation difficulties for
+ * many drivers that could otherwise handle the lack of FB access while
+ * swapped out.
+ */
 void
 exaEnableDisableFBAccess (int index, Bool enable)
 {
@@ -296,10 +342,14 @@ exaEnableDisableFBAccess (int index, Boo
     ExaScreenPriv (pScreen);
 
     if (!enable) {
-	ExaOffscreenSwapOut (pScreen);
+	if (pExaScr->info->exa_minor < 1)
+	    ExaOffscreenSwapOut (pScreen);
+	else
+	    ExaOffscreenEjectPixmaps (pScreen);
 	pExaScr->swappedOut = TRUE;
     } else {
-	ExaOffscreenSwapIn (pScreen);
+	if (pExaScr->info->exa_minor < 1)
+	    ExaOffscreenSwapIn (pScreen);
 	pExaScr->swappedOut = FALSE;
     }
 }
@@ -390,6 +440,7 @@ ExaOffscreenMarkUsed (PixmapPtr pPixmap)
 	    if (area->state == ExaOffscreenRemovable)
 		area->score = (area->score * 7) / 8;
 	}
+	iter = 0;
     }
 }
 
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index 03ee0ed..984cb66 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -51,6 +51,7 @@
 #ifdef RENDER
 #include "fbpict.h"
 #endif
+#include "damage.h"
 
 #define DEBUG_TRACE_FALL	0
 #define DEBUG_MIGRATE		0
@@ -160,16 +161,16 @@ typedef struct {
     unsigned int    fb_size;	/**< size of pixmap in framebuffer memory */
 
     /**
-     * If area is NULL, then dirty == TRUE means that the pixmap has been
-     * modified, so the contents are defined.  Used to avoid uploads of
-     * undefined data.
-     *
-     * If area is non-NULL, then dirty == TRUE means that the pixmap data at
-     * pPixmap->devPrivate.ptr (either fb_ptr or sys_ptr) has been changed
-     * compared to the copy in the other location.  This is used to avoid
-     * uploads/downloads of unmodified data.
+     * The damage record contains the areas of the pixmap's current location
+     * (framebuffer or system) that have been damaged compared to the other
+     * location.
      */
-    Bool	    dirty;
+    DamagePtr	    pDamage;
+    /**
+     * The valid region marks the valid bits of a drawable (at least, as it's
+     * derived from damage, which may be overreported).
+     */
+    RegionRec	    validReg;
 } ExaPixmapPrivRec, *ExaPixmapPrivPtr;
  
 typedef struct _ExaMigrationRec {
@@ -315,7 +316,7 @@ ExaCheckComposite (CARD8      op,
 		  CARD16     height);
 #endif
 
-/* exaoffscreen.c */
+/* exa_offscreen.c */
 void
 ExaOffscreenMarkUsed (PixmapPtr pPixmap);
 
@@ -339,7 +340,10 @@ void
 exaFinishAccess(DrawablePtr pDrawable, int index);
 
 void
-exaDrawableDirty(DrawablePtr pDrawable);
+exaPixmapDirty(PixmapPtr pPix, int x1, int y1, int x2, int y2);
+
+void
+exaDrawableDirty(DrawablePtr pDrawable, int x1, int y1, int x2, int y2);
 
 Bool
 exaDrawableIsOffscreen (DrawablePtr pDrawable);
@@ -409,9 +413,6 @@ void
 exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
 
 void
-exaMoveInPixmap (PixmapPtr pPixmap);
-
-void
-exaMoveOutPixmap (PixmapPtr pPixmap);
+exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area);
 
 #endif /* EXAPRIV_H */
diff --git a/exa/exa_render.c b/exa/exa_render.c
index 9affb9f..75108a7 100644
--- a/exa/exa_render.c
+++ b/exa/exa_render.c
@@ -302,12 +302,12 @@ exaTryDriverSolidFill(PicturePtr	pSrc,
 	(*pExaScr->info->Solid) (pDstPix,
 				 pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
 				 pbox->x2 + dst_off_x, pbox->y2 + dst_off_y);
+	exaPixmapDirty (pDstPix, pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
+			pbox->x2 + dst_off_x, pbox->y2 + dst_off_y);
 	pbox++;
     }
-
     (*pExaScr->info->DoneSolid) (pDstPix);
     exaMarkSync(pDst->pDrawable->pScreen);
-    exaDrawableDirty (pDst->pDrawable);
 
     REGION_UNINIT(pDst->pDrawable->pScreen, &region);
     return 1;
@@ -336,16 +336,21 @@ exaTryDriverComposite(CARD8		op,
     struct _Pixmap scratch;
     ExaMigrationRec pixmaps[3];
 
+    pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
+    pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
+    if (pMask)
+	pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
+
     /* Bail if we might exceed coord limits by rendering from/to these.  We
      * should really be making some scratch pixmaps with offsets and coords
      * adjusted to deal with this, but it hasn't been done yet.
      */
-    if (pSrc->pDrawable->width > pExaScr->info->maxX ||
-	pSrc->pDrawable->height > pExaScr->info->maxY ||
-	pDst->pDrawable->width > pExaScr->info->maxX ||
-	pDst->pDrawable->height > pExaScr->info->maxY || 
-	(pMask && (pMask->pDrawable->width > pExaScr->info->maxX ||
-		   pMask->pDrawable->height > pExaScr->info->maxY)))
+    if (pSrcPix->drawable.width > pExaScr->info->maxX ||
+	pSrcPix->drawable.height > pExaScr->info->maxY ||
+	pDstPix->drawable.width > pExaScr->info->maxX ||
+	pDstPix->drawable.height > pExaScr->info->maxY || 
+	(pMask && (pMaskPix->drawable.width > pExaScr->info->maxX ||
+		   pMaskPix->drawable.height > pExaScr->info->maxY)))
     {
 	return -1;
     }
@@ -441,12 +446,12 @@ exaTryDriverComposite(CARD8		op,
 				     pbox->y1 + dst_off_y,
 				     pbox->x2 - pbox->x1,
 				     pbox->y2 - pbox->y1);
+	exaPixmapDirty (pDstPix, pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
+			pbox->x2 + dst_off_x, pbox->y2 + dst_off_y);
 	pbox++;
     }
-
     (*pExaScr->info->DoneComposite) (pDstPix);
     exaMarkSync(pDst->pDrawable->pScreen);
-    exaDrawableDirty (pDst->pDrawable);
 
     REGION_UNINIT(pDst->pDrawable->pScreen, &region);
     return 1;
@@ -705,16 +710,19 @@ void
 exaRasterizeTrapezoid (PicturePtr pPicture, xTrapezoid  *trap,
 		       int x_off, int y_off)
 {
+    DrawablePtr pDraw = pPicture->pDrawable;
     ExaMigrationRec pixmaps[1];
 
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = TRUE;
-    pixmaps[0].pPix = exaGetDrawablePixmap (pPicture->pDrawable);
+    pixmaps[0].pPix = exaGetDrawablePixmap (pDraw);
     exaDoMigration(pixmaps, 1, FALSE);
 
-    exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
+    exaPrepareAccess(pDraw, EXA_PREPARE_DEST);
     fbRasterizeTrapezoid(pPicture, trap, x_off, y_off);
-    exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
+    exaDrawableDirty(pDraw, pDraw->x, pDraw->y,
+		     pDraw->x + pDraw->width, pDraw->y + pDraw->height);
+    exaFinishAccess(pDraw, EXA_PREPARE_DEST);
 }
 
 /**
@@ -725,16 +733,19 @@ void
 exaAddTriangles (PicturePtr pPicture, INT16 x_off, INT16 y_off, int ntri,
 		 xTriangle *tris)
 {
+    DrawablePtr pDraw = pPicture->pDrawable;
     ExaMigrationRec pixmaps[1];
 
     pixmaps[0].as_dst = TRUE;
     pixmaps[0].as_src = TRUE;
-    pixmaps[0].pPix = exaGetDrawablePixmap (pPicture->pDrawable);
+    pixmaps[0].pPix = exaGetDrawablePixmap (pDraw);
     exaDoMigration(pixmaps, 1, FALSE);
 
-    exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
+    exaPrepareAccess(pDraw, EXA_PREPARE_DEST);
     fbAddTriangles(pPicture, x_off, y_off, ntri, tris);
-    exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
+    exaDrawableDirty(pDraw, pDraw->x, pDraw->y,
+		     pDraw->x + pDraw->width, pDraw->y + pDraw->height);
+    exaFinishAccess(pDraw, EXA_PREPARE_DEST);
 }
 
 /**
@@ -1023,10 +1034,11 @@ exaGlyphs (CARD8	op,
 
 		exaCopyArea (&pScratchPixmap->drawable, &pPixmap->drawable, pGC,
 			     0, 0, glyph->info.width, glyph->info.height, 0, 0);
-	    } else {
-		exaDrawableDirty (&pPixmap->drawable);
 	    }
 
+	    exaPixmapDirty (pPixmap, 0, 0,
+			    glyph->info.width, glyph->info.height);
+
 	    if (maskFormat)
 	    {
 		exaComposite (PictOpAdd, pPicture, NULL, pMask, 0, 0, 0, 0,
diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c
index f9df6ad..7713a08 100644
--- a/exa/exa_unaccel.c
+++ b/exa/exa_unaccel.c
@@ -200,11 +200,33 @@ ExaCheckPolyFillRect (DrawablePtr pDrawa
 		     int nrect, xRectangle *prect)
 {
     EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
-    exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
-    exaPrepareAccessGC (pGC);
-    fbPolyFillRect (pDrawable, pGC, nrect, prect);
-    exaFinishAccessGC (pGC);
-    exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
+
+    if (nrect) {
+	int x1 = max(prect->x, 0), y1 = max(prect->y, 0);
+	int x2 = min(prect->x + prect->width, pDrawable->width);
+	int y2 = min(prect->y + prect->height, pDrawable->height);
+
+	exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
+	exaPrepareAccessGC (pGC);
+	fbPolyFillRect (pDrawable, pGC, nrect, prect);
+	exaFinishAccessGC (pGC);
+	exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
+
+	/* Only track bounding box of damage, as this path can degenerate to
+	 * zillions of damage boxes
+	 */
+	while (--nrect)
+	{
+	    prect++;
+	    x1 = min(x1, prect->x);
+	    x2 = max(x2, prect->x + prect->width);
+	    y1 = min(y1, prect->y);
+	    y2 = max(y2, prect->y + prect->height);
+	}
+
+	exaDrawableDirty (pDrawable, pDrawable->x + x1, pDrawable->y + y1,
+			  pDrawable->x + x2, pDrawable->y + y2);
+    }
 }
 
 void
diff --git a/hw/xfree86/exa/Makefile.am b/hw/xfree86/exa/Makefile.am
index 31682c4..9eb2e17 100644
--- a/hw/xfree86/exa/Makefile.am
+++ b/hw/xfree86/exa/Makefile.am
@@ -7,7 +7,7 @@ INCLUDES = \
 	-I$(srcdir)/../../../exa \
 	-I$(srcdir)/../../../miext/cw
 
-AM_CFLAGS = $(XORG_CFLAGS)
+AM_CFLAGS = $(DIX_CFLAGS) $(XORG_CFLAGS)
 
 libexa_la_SOURCES = \
 	examodule.c
diff --git a/hw/xfree86/exa/exa.man.pre b/hw/xfree86/exa/exa.man.pre
index ea41b90..b0eecd5 100644
--- a/hw/xfree86/exa/exa.man.pre
+++ b/hw/xfree86/exa/exa.man.pre
@@ -35,6 +35,6 @@ Default: No.
 Chooses an alternate pixmap migration heuristic, for debugging purposes.  The
 default is intended to be the best performing one for general use, though others
 may help with specific use cases.  Available options include \*qalways\*q,
-\*qgreedy\*q, and \*qsmart\*q.  Default: smart.
+\*qgreedy\*q, and \*qsmart\*q.  Default: always.
 .SH AUTHORS
 Authors include: Keith Packard, Eric Anholt, Zack Rusin, and Michel Dänzer
diff-tree 9fbb845e8b56847ee6ff7cbb7d941f229a39c407 (from fe13ebbe6960b5a23ed0dc0dd991fd5177dee483)
Author: Eric Anholt <eric at anholt.net>
Date:   Mon Jun 12 20:12:31 2006 +0200

    Provide option to report damage after operation is complete.
    (cherry picked from commit 6060b612de6b41f872d034c6130770c1d189d0a3)

diff --git a/miext/damage/damage.c b/miext/damage/damage.c
index 2e80011..cd66b54 100755
--- a/miext/damage/damage.c
+++ b/miext/damage/damage.c
@@ -113,6 +113,52 @@ getDrawableDamageRef (DrawablePtr pDrawa
     DamagePtr	*pPrev = (DamagePtr *) \
 	    &(pWindow->devPrivates[damageWinPrivateIndex].ptr)
 
+static void
+DamageReportDamage (DamagePtr pDamage, RegionPtr pDamageRegion)
+{
+    BoxRec tmpBox;
+    RegionRec tmpRegion;
+    Bool was_empty;
+
+    switch (pDamage->damageLevel) {
+    case DamageReportRawRegion:
+	(*pDamage->damageReport) (pDamage, pDamageRegion, pDamage->closure);
+	break;
+    case DamageReportDeltaRegion:
+	REGION_NULL (pScreen, &tmpRegion);
+	REGION_SUBTRACT (pScreen, &tmpRegion, pDamageRegion, &pDamage->damage);
+	if (REGION_NOTEMPTY (pScreen, &tmpRegion)) {
+	    REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage,
+			 pDamageRegion);
+	    (*pDamage->damageReport) (pDamage, &tmpRegion, pDamage->closure);
+	}
+	REGION_UNINIT(pScreen, &tmpRegion);
+	break;
+    case DamageReportBoundingBox:
+	tmpBox = *REGION_EXTENTS (pScreen, &pDamage->damage);
+	REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage,
+		     pDamageRegion);
+	if (!BOX_SAME (&tmpBox, REGION_EXTENTS (pScreen, &pDamage->damage))) {
+	    (*pDamage->damageReport) (pDamage, &pDamage->damage,
+				      pDamage->closure);
+	}
+	break;
+    case DamageReportNonEmpty:
+	was_empty = !REGION_NOTEMPTY(pScreen, &pDamage->damage);
+	REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage,
+		     pDamageRegion);
+	if (was_empty && REGION_NOTEMPTY(pScreen, &pDamage->damage)) {
+	    (*pDamage->damageReport) (pDamage, &pDamage->damage,
+				      pDamage->closure);
+	}
+	break;
+    case DamageReportNone:
+	REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage,
+		     pDamageRegion);
+	break;
+    }
+}
+
 #if DAMAGE_DEBUG_ENABLE
 static void
 _damageDamageRegion (DrawablePtr pDrawable, RegionPtr pRegion, Bool clip, int subWindowMode, const char *where)
@@ -130,9 +176,6 @@ damageDamageRegion (DrawablePtr pDrawabl
     RegionRec	    clippedRec;
     RegionPtr	    pDamageRegion;
     RegionRec	    pixClip;
-    Bool	    was_empty;
-    RegionRec	    tmpRegion;
-    BoxRec	    tmpBox;
     int		    draw_x, draw_y;
 #ifdef COMPOSITE
     int		    screen_x = 0, screen_y = 0;
@@ -256,41 +299,18 @@ damageDamageRegion (DrawablePtr pDrawabl
 	 */
 	if (draw_x || draw_y)
 	    REGION_TRANSLATE (pScreen, pDamageRegion, -draw_x, -draw_y);
-	
-	switch (pDamage->damageLevel) {
-	case DamageReportRawRegion:
-	    (*pDamage->damageReport) (pDamage, pDamageRegion, pDamage->closure);
-	    break;
-	case DamageReportDeltaRegion:
-	    REGION_NULL (pScreen, &tmpRegion);
-	    REGION_SUBTRACT (pScreen, &tmpRegion, pDamageRegion, &pDamage->damage);
-	    if (REGION_NOTEMPTY (pScreen, &tmpRegion))
-	    {
-		REGION_UNION(pScreen, &pDamage->damage,
-			     &pDamage->damage, pDamageRegion);
-		(*pDamage->damageReport) (pDamage, &tmpRegion, pDamage->closure);
-	    }
-	    REGION_UNINIT(pScreen, &tmpRegion);
-	    break;
-	case DamageReportBoundingBox:
-	    tmpBox = *REGION_EXTENTS (pScreen, &pDamage->damage);
-	    REGION_UNION(pScreen, &pDamage->damage,
-			 &pDamage->damage, pDamageRegion);
-	    if (!BOX_SAME (&tmpBox, REGION_EXTENTS (pScreen, &pDamage->damage)))
-		(*pDamage->damageReport) (pDamage, &pDamage->damage, pDamage->closure);
-	    break;
-	case DamageReportNonEmpty:
-	    was_empty = !REGION_NOTEMPTY(pScreen, &pDamage->damage);
-	    REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage,
-			 pDamageRegion);
-	    if (was_empty && REGION_NOTEMPTY(pScreen, &pDamage->damage))
-		(*pDamage->damageReport) (pDamage, &pDamage->damage, pDamage->closure);
-	    break;
-	case DamageReportNone:
-	    REGION_UNION(pScreen, &pDamage->damage, &pDamage->damage,
-			 pDamageRegion);
-	    break;
+
+	/* If the damage rec has been flagged to report damage after the op has
+	 * completed, then union it into the delayed damage region, which will
+	 * be used for reporting after calling down, and skip the reporting 
+	 */
+	if (!pDamage->reportAfter) {
+	    DamageReportDamage (pDamage, pDamageRegion);
+	} else {
+	    REGION_UNION(pScreen, &pDamage->pendingDamage,
+			 &pDamage->pendingDamage, pDamageRegion);
 	}
+
 	/*
 	 * translate original region back
 	 */
@@ -305,6 +325,21 @@ damageDamageRegion (DrawablePtr pDrawabl
     REGION_UNINIT (pScreen, &clippedRec);
 }
 
+static void
+damageReportPostOp (DrawablePtr pDrawable)
+{
+    drawableDamage(pDrawable);
+
+    for (; pDamage != NULL; pDamage = pDamage->pNext)
+    {
+	if (pDamage->reportAfter) {
+	    DamageReportDamage (pDamage, &pDamage->pendingDamage);
+	    REGION_EMPTY (pScreen, &pDamage->pendingDamage);
+	}
+    }
+    
+}
+
 #if DAMAGE_DEBUG_ENABLE
 #define damageDamageBox(d,b,m) _damageDamageBox(d,b,m,__FUNCTION__)
 static void
@@ -550,6 +585,7 @@ damageComposite (CARD8      op,
 		       yDst,
 		       width,
 		       height);
+    damageReportPostOp (pDst->pDrawable);
     wrap (pScrPriv, ps, Composite, damageComposite);
 }
 
@@ -616,6 +652,7 @@ damageGlyphs (CARD8		op,
     }
     unwrap (pScrPriv, ps, Glyphs);
     (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
+    damageReportPostOp (pDst->pDrawable);
     wrap (pScrPriv, ps, Glyphs, damageGlyphs);
 }
 #endif
@@ -668,6 +705,7 @@ damageFillSpans(DrawablePtr pDrawable,
     
     (*pGC->ops->FillSpans)(pDrawable, pGC, npt, ppt, pwidth, fSorted);
 
+    damageReportPostOp (pDrawable);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
 }
 
@@ -715,6 +753,7 @@ damageSetSpans(DrawablePtr  pDrawable,
 	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
     }
     (*pGC->ops->SetSpans)(pDrawable, pGC, pcharsrc, ppt, pwidth, npt, fSorted);
+    damageReportPostOp (pDrawable);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
 }
 
@@ -746,6 +785,7 @@ damagePutImage(DrawablePtr  pDrawable,
     }
     (*pGC->ops->PutImage)(pDrawable, pGC, depth, x, y, w, h,
 		leftPad, format, pImage);
+    damageReportPostOp (pDrawable);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
 }
 
@@ -789,6 +829,7 @@ damageCopyArea(DrawablePtr   pSrc,
 
     ret = (*pGC->ops->CopyArea)(pSrc, pDst,
             pGC, srcx, srcy, width, height, dstx, dsty);
+    damageReportPostOp (pDst);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDst);
     return ret;
 }
@@ -834,6 +875,7 @@ damageCopyPlane(DrawablePtr	pSrc,
 
     ret = (*pGC->ops->CopyPlane)(pSrc, pDst,
 	       pGC, srcx, srcy, width, height, dstx, dsty, bitPlane);
+    damageReportPostOp (pDst);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDst);
     return ret;
 }
@@ -875,6 +917,7 @@ damagePolyPoint(DrawablePtr pDrawable,
 	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
     }
     (*pGC->ops->PolyPoint)(pDrawable, pGC, mode, npt, ppt);
+    damageReportPostOp (pDrawable);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
 }
 
@@ -948,6 +991,7 @@ damagePolylines(DrawablePtr pDrawable,
 	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
     }
     (*pGC->ops->Polylines)(pDrawable, pGC, mode, npt, ppt);
+    damageReportPostOp (pDrawable);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
 }
 
@@ -1026,6 +1070,7 @@ damagePolySegment(DrawablePtr	pDrawable,
 	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
     }
     (*pGC->ops->PolySegment)(pDrawable, pGC, nSeg, pSeg);
+    damageReportPostOp (pDrawable);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
 }
 
@@ -1087,6 +1132,7 @@ damagePolyRectangle(DrawablePtr  pDrawab
 	}
     }
     (*pGC->ops->PolyRectangle)(pDrawable, pGC, nRects, pRects);
+    damageReportPostOp (pDrawable);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
 }
 
@@ -1139,6 +1185,7 @@ damagePolyArc(DrawablePtr   pDrawable,
 	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
     }
     (*pGC->ops->PolyArc)(pDrawable, pGC, nArcs, pArcs);
+    damageReportPostOp (pDrawable);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
 }
 
@@ -1197,6 +1244,7 @@ damageFillPolygon(DrawablePtr	pDrawable,
     }
     
     (*pGC->ops->FillPolygon)(pDrawable, pGC, shape, mode, npt, ppt);
+    damageReportPostOp (pDrawable);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
 }
 
@@ -1235,6 +1283,7 @@ damagePolyFillRect(DrawablePtr	pDrawable
 	    damageDamageBox (pDrawable, &box, pGC->subWindowMode);
     }
     (*pGC->ops->PolyFillRect)(pDrawable, pGC, nRects, pRects);
+    damageReportPostOp (pDrawable);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
 }
 
@@ -1276,6 +1325,7 @@ damagePolyFillArc(DrawablePtr	pDrawable,
 	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
     }
     (*pGC->ops->PolyFillArc)(pDrawable, pGC, nArcs, pArcs);
+    damageReportPostOp (pDrawable);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
 }
 
@@ -1386,6 +1436,7 @@ damagePolyText8(DrawablePtr pDrawable,
 		    Linear8Bit, TT_POLY8);
     else
 	x = (*pGC->ops->PolyText8)(pDrawable, pGC, x, y, count, chars);
+    damageReportPostOp (pDrawable);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
     return x;
 }
@@ -1406,6 +1457,7 @@ damagePolyText16(DrawablePtr	pDrawable,
 		    TT_POLY16);
     else
 	x = (*pGC->ops->PolyText16)(pDrawable, pGC, x, y, count, chars);
+    damageReportPostOp (pDrawable);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
     return x;
 }
@@ -1425,6 +1477,7 @@ damageImageText8(DrawablePtr	pDrawable,
 		    Linear8Bit, TT_IMAGE8);
     else
 	(*pGC->ops->ImageText8)(pDrawable, pGC, x, y, count, chars);
+    damageReportPostOp (pDrawable);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
 }
 
@@ -1444,6 +1497,7 @@ damageImageText16(DrawablePtr	pDrawable,
 		    TT_IMAGE16);
     else
 	(*pGC->ops->ImageText16)(pDrawable, pGC, x, y, count, chars);
+    damageReportPostOp (pDrawable);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
 }
 
@@ -1462,6 +1516,7 @@ damageImageGlyphBlt(DrawablePtr	    pDra
 		       nglyph, ppci, TRUE, pGC->subWindowMode);
     (*pGC->ops->ImageGlyphBlt)(pDrawable, pGC, x, y, nglyph,
 					ppci, pglyphBase);
+    damageReportPostOp (pDrawable);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
 }
 
@@ -1479,6 +1534,7 @@ damagePolyGlyphBlt(DrawablePtr	pDrawable
 		       nglyph, ppci, FALSE, pGC->subWindowMode);
     (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, nglyph,
 				ppci, pglyphBase);
+    damageReportPostOp (pDrawable);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
 }
 
@@ -1512,6 +1568,7 @@ damagePushPixels(GCPtr		pGC,
 	   damageDamageBox (pDrawable, &box, pGC->subWindowMode);
     }
     (*pGC->ops->PushPixels)(pGC, pBitMap, pDrawable, dx, dy, xOrg, yOrg);
+    damageReportPostOp (pDrawable);
     DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
 }
 
@@ -1591,10 +1648,12 @@ damagePaintWindow(WindowPtr pWindow,
     if(what == PW_BACKGROUND) {
 	unwrap (pScrPriv, pScreen, PaintWindowBackground);
 	(*pScreen->PaintWindowBackground) (pWindow, prgn, what);
+	damageReportPostOp (&pWindow->drawable);
 	wrap (pScrPriv, pScreen, PaintWindowBackground, damagePaintWindow);
     } else {
 	unwrap (pScrPriv, pScreen, PaintWindowBorder);
 	(*pScreen->PaintWindowBorder) (pWindow, prgn, what);
+	damageReportPostOp (&pWindow->drawable);
 	wrap (pScrPriv, pScreen, PaintWindowBorder, damagePaintWindow);
     }
 }
@@ -1623,6 +1682,7 @@ damageCopyWindow(WindowPtr	pWindow,
     }
     unwrap (pScrPriv, pScreen, CopyWindow);
     (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc);
+    damageReportPostOp (&pWindow->drawable);
     wrap (pScrPriv, pScreen, CopyWindow, damageCopyWindow);
 }
 
@@ -1654,6 +1714,7 @@ damageRestoreAreas (PixmapPtr	pPixmap,
     unwrap (pScrPriv, pScreen, BackingStoreFuncs.RestoreAreas);
     (*pScreen->BackingStoreFuncs.RestoreAreas) (pPixmap, prgn,
 						xorg, yorg, pWindow);
+    damageReportPostOp (&pWindow->drawable);
     wrap (pScrPriv, pScreen, BackingStoreFuncs.RestoreAreas,
 			     damageRestoreAreas);
 }
@@ -1820,12 +1881,14 @@ DamageCreate (DamageReportFunc  damageRe
     pDamage->pNext = 0;
     pDamage->pNextWin = 0;
     REGION_NULL(pScreen, &pDamage->damage);
+    REGION_NULL(pScreen, &pDamage->pendingDamage);
     
     pDamage->damageLevel = damageLevel;
     pDamage->isInternal = isInternal;
     pDamage->closure = closure;
     pDamage->isWindow = FALSE;
     pDamage->pDrawable = 0;
+    pDamage->reportAfter = FALSE;
 
     pDamage->damageReport = damageReport;
     pDamage->damageDestroy = damageDestroy;
@@ -1909,6 +1972,7 @@ DamageDestroy (DamagePtr    pDamage)
     if (pDamage->damageDestroy)
 	(*pDamage->damageDestroy) (pDamage, pDamage->closure);
     REGION_UNINIT (pDamage->pDrawable->pScreen, &pDamage->damage);
+    REGION_UNINIT (pDamage->pDrawable->pScreen, &pDamage->pendingDamage);
     xfree (pDamage);
 }
 
@@ -1962,4 +2026,16 @@ DamageDamageRegion (DrawablePtr	pDrawabl
 		    RegionPtr	pRegion)
 {
     damageDamageRegion (pDrawable, pRegion, FALSE, -1);
+
+    /* Go back and report this damage for DamagePtrs with reportAfter set, since
+     * this call isn't part of an in-progress drawing op in the call chain and
+     * the DDX probably just wants to know about it right away.
+     */
+    damageReportPostOp (pDrawable);
+}
+
+void
+DamageSetReportAfterOp (DamagePtr pDamage, Bool reportAfter)
+{
+    pDamage->reportAfter = reportAfter;
 }
diff --git a/miext/damage/damage.h b/miext/damage/damage.h
index c760f6b..36a0654 100755
--- a/miext/damage/damage.h
+++ b/miext/damage/damage.h
@@ -81,4 +81,7 @@ void
 DamageDamageRegion (DrawablePtr	    pDrawable,
 		    const RegionPtr pRegion);
 
+void
+DamageSetReportAfterOp (DamagePtr pDamage, Bool reportAfter);
+
 #endif /* _DAMAGE_H_ */
diff --git a/miext/damage/damagestr.h b/miext/damage/damagestr.h
index 0fe9e0a..93e213f 100755
--- a/miext/damage/damagestr.h
+++ b/miext/damage/damagestr.h
@@ -48,6 +48,9 @@ typedef struct _damage {
     
     DamageReportFunc	damageReport;
     DamageDestroyFunc	damageDestroy;
+
+    Bool		reportAfter;
+    RegionRec		pendingDamage;
 } DamageRec;
 
 typedef struct _damageScrPriv {



More information about the xorg-commit mailing list