xserver: Branch 'master' - 7 commits

Eric Anholt anholt at kemper.freedesktop.org
Thu Dec 28 23:02:05 EET 2006


 exa/exa.c                |  128 +++++++++++++++++++--------
 exa/exa_accel.c          |  112 ++++++++++++++++++-----
 exa/exa_migration.c      |  221 ++++++++++++++++++++++++++++++-----------------
 exa/exa_offscreen.c      |    1 
 exa/exa_priv.h           |   26 +++--
 exa/exa_render.c         |   31 ++++--
 exa/exa_unaccel.c        |   32 +++++-
 miext/damage/damage.c    |  150 ++++++++++++++++++++++++-------
 miext/damage/damage.h    |    3 
 miext/damage/damagestr.h |    3 
 10 files changed, 504 insertions(+), 203 deletions(-)

New commits:
diff-tree 683ca3f7afaf15fd3ca7918f6175b5a9e4a6f05b (from parents)
Merge: 05f915050cad72d4fb39cbb886be57beeac18749 9563b2eea2f61246b6a9e14e00c701f693efa4e1
Author: Eric Anholt <eric at anholt.net>
Date:   Wed Dec 27 16:11:31 2006 -0800

    Merge branch 'exa-damagetrack'

diff-tree 9563b2eea2f61246b6a9e14e00c701f693efa4e1 (from 467c00cf450826e0bf06fe94470ec193af625d68)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Tue Dec 19 18:57:22 2006 +0100

    EXA: Lots of damage tracking fixes.
    
    Mostly due to exaDrawableDirty() now calculating the backing pixmap coordinates
    internally, for cases where they aren't trivially known. There's a new
    exaPixmapDirty() function for the other cases.

diff --git a/exa/exa.c b/exa/exa.c
index 195457c..e61bc69 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -122,22 +122,49 @@ exaGetDrawablePixmap(DrawablePtr pDrawab
 }	
 
 /**
- * exaDrawableDirty() marks a pixmap backing a drawable as dirty, allowing for
+ * 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
-exaDrawableDirty (DrawablePtr pDrawable, int x1, int y1, int x2, int y2)
+exaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2)
 {
-    ExaPixmapPrivPtr pExaPixmap;
+    ExaPixmapPriv(pPix);
+    BoxRec box;
     RegionPtr pDamageReg;
-    BoxRec box = { .x1 = max(x1,0), .x2 = min(x2,pDrawable->width),
-		   .y1 = max(y1,0), .y2 = min(y2,pDrawable->height) };
     RegionRec region;
 
-    pExaPixmap = ExaGetPixmapPriv(exaGetDrawablePixmap (pDrawable));
-    if (!pExaPixmap || box.x1 >= box.x2 || box.y1 >= box.y2)
+    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);
@@ -145,6 +172,29 @@ exaDrawableDirty (DrawablePtr pDrawable,
     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, int x1, int y1, int x2, int y2)
+{
+    PixmapPtr pPix = exaGetDrawablePixmap(pDrawable);
+    int xoff, yoff;
+
+    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
 exaDestroyPixmap (PixmapPtr pPixmap)
 {
@@ -289,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
@@ -428,7 +460,7 @@ exaValidateGC (GCPtr pGC, unsigned long 
 		exaPrepareAccess(&pOldTile->drawable, EXA_PREPARE_SRC);
 		pNewTile = fb24_32ReformatTile (pOldTile,
 						pDrawable->bitsPerPixel);
-		exaDrawableDirty(&pNewTile->drawable, 0, 0, pNewTile->drawable.width, pNewTile->drawable.height);
+		exaPixmapDirty(pNewTile, 0, 0, pNewTile->drawable.width, pNewTile->drawable.height);
 		exaFinishAccess(&pOldTile->drawable, EXA_PREPARE_SRC);
 	    }
 	    if (pNewTile)
@@ -449,9 +481,9 @@ exaValidateGC (GCPtr pGC, unsigned long 
 	     */
 	    exaMoveOutPixmap(pGC->tile.pixmap);
 	    fbPadPixmap (pGC->tile.pixmap);
-	    exaDrawableDirty(&pGC->tile.pixmap->drawable, 0, 0,
-			     pGC->tile.pixmap->drawable.width,
-			     pGC->tile.pixmap->drawable.height);
+	    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.
diff --git a/exa/exa_accel.c b/exa/exa_accel.c
index d2fe2e0..6fa481a 100644
--- a/exa/exa_accel.c
+++ b/exa/exa_accel.c
@@ -109,9 +109,8 @@ exaFillSpans(DrawablePtr pDrawable, GCPt
 	    (*pExaScr->info->Solid) (pPixmap,
 				     fullX1 + off_x, fullY1 + off_y,
 				     fullX2 + off_x, fullY1 + 1 + off_y);
-	    exaDrawableDirty (pDrawable,
-			      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
 	{
@@ -130,9 +129,8 @@ exaFillSpans(DrawablePtr pDrawable, GCPt
 			(*pExaScr->info->Solid) (pPixmap,
 						 partX1 + off_x, fullY1 + off_y,
 						 partX2 + off_x, fullY1 + 1 + off_y);
-			exaDrawableDirty (pDrawable,
-					  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++;
@@ -233,7 +231,7 @@ exaPutImage (DrawablePtr pDrawable, GCPt
 
 	    exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
 	}
-	exaDrawableDirty(pDrawable, x1 + xoff, y1 + yoff, x2 + xoff, y2 + yoff);
+	exaPixmapDirty(pPix, x1 + xoff, y1 + yoff, x2 + xoff, y2 + yoff);
     }
 
     return;
@@ -362,9 +360,8 @@ exaCopyNtoNTwoDir (DrawablePtr pSrcDrawa
 				       dst_off_y + pbox->y1 + i,
 				       pbox->x2 - pbox->x1, 1);
 	}
-	exaDrawableDirty(pDstDrawable,
-			 dst_off_x + pbox->x1, dst_off_y + pbox->y1,
-			 dst_off_x + pbox->x2, dst_off_y + pbox->y2);
+	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);
@@ -437,9 +434,9 @@ exaCopyNtoN (DrawablePtr    pSrcDrawable
 				    pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
 				    pbox->x2 - pbox->x1,
 				    pbox->y2 - pbox->y1);
-	    exaDrawableDirty (pDstDrawable,
-			      pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
-			      pbox->x2 + dst_off_x, pbox->y2 + dst_off_y);
+	    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);
@@ -460,9 +457,7 @@ fallback:
     exaFinishAccess (pDstDrawable, EXA_PREPARE_DEST);
     while (nbox--)
     {
-	exaDrawableDirty (pDstDrawable,
-			  pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
-			  pbox->x2 + dst_off_x, pbox->y2 + dst_off_y);
+	exaDrawableDirty (pDstDrawable, pbox->x1, pbox->y1, pbox->x2, pbox->y2);
 	pbox++;
     }
 }
@@ -704,9 +699,8 @@ exaPolyFillRect(DrawablePtr pDrawable,
 	    (*pExaScr->info->Solid) (pPixmap,
 				     fullX1 + xoff, fullY1 + yoff,
 				     fullX2 + xoff, fullY2 + yoff);
-	    exaDrawableDirty (pDrawable,
-			      fullX1 + xoff, fullY1 + yoff,
-			      fullX2 + xoff, fullY2 + yoff);
+	    exaPixmapDirty (pPixmap, fullX1 + xoff, fullY1 + yoff,
+			    fullX2 + xoff, fullY2 + yoff);
 	}
 	else
 	{
@@ -736,9 +730,8 @@ exaPolyFillRect(DrawablePtr pDrawable,
 		    (*pExaScr->info->Solid) (pPixmap,
 					     partX1 + xoff, partY1 + yoff,
 					     partX2 + xoff, partY2 + yoff);
-		    exaDrawableDirty (pDrawable,
-				      partX1 + xoff, partY1 + yoff,
-				      partX2 + xoff, partY2 + yoff);
+		    exaPixmapDirty (pPixmap, partX1 + xoff, partY1 + yoff,
+				    partX2 + xoff, partY2 + yoff);
 		}
 	    }
 	}
@@ -770,9 +763,6 @@ exaSolidBoxClipped (DrawablePtr	pDrawabl
     pixmaps[0].as_src = FALSE;
     pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
 
-    /* We need to initialize x/yoff for tracking damage in the fallback case */
-    pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
-
     if (pExaScr->swappedOut ||
 	pPixmap->drawable.width > pExaScr->info->maxX ||
 	pPixmap->drawable.height > pExaScr->info->maxY)
@@ -825,13 +815,14 @@ fallback:
 	if (partY2 <= partY1)
 	    continue;
 
-	if (!fallback)
+	if (!fallback) {
 	    (*pExaScr->info->Solid) (pPixmap,
 				     partX1 + xoff, partY1 + yoff,
 				     partX2 + xoff, partY2 + yoff);
-	exaDrawableDirty (pDrawable,
-			  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)
@@ -950,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,
@@ -969,9 +965,19 @@ 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);
+		}
 	    }
-	    exaDrawableDirty(pDrawable, gx + dstXoff, gy + dstYoff,
-			     gx + dstXoff + gWidth, gy + dstYoff + gHeight);
 	}
 	x += pci->metrics.characterWidth;
     }
@@ -1062,9 +1068,8 @@ exaFillRegionSolid (DrawablePtr	pDrawabl
 	    (*pExaScr->info->Solid) (pPixmap,
 				     pBox->x1 + xoff, pBox->y1 + yoff,
 				     pBox->x2 + xoff, pBox->y2 + yoff);
-	    exaDrawableDirty (pDrawable,
-			      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);
@@ -1081,9 +1086,7 @@ fallback:
 	exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
 	while (nbox--)
 	{
-	    exaDrawableDirty (pDrawable,
-			      pBox->x1 + xoff, pBox->y1 + yoff,
-			      pBox->x2 + xoff, pBox->y2 + yoff);
+	    exaDrawableDirty (pDrawable, pBox->x1, pBox->y1, pBox->x2, pBox->y2);
 	    pBox++;
 	}
     }
@@ -1123,9 +1126,6 @@ exaFillRegionTiled (DrawablePtr	pDrawabl
     pixmaps[1].as_src = TRUE;
     pixmaps[1].pPix = pTile;
 
-    /* We need to initialize x/yoff for tracking damage in the fallback case */
-    pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
-
     if (pPixmap->drawable.width > pExaScr->info->maxX ||
 	pPixmap->drawable.height > pExaScr->info->maxY ||
 	tileWidth > pExaScr->info->maxX ||
@@ -1182,8 +1182,8 @@ exaFillRegionTiled (DrawablePtr	pDrawabl
 		dstY += h;
 		tileY = 0;
 	    }
-	    exaDrawableDirty (pDrawable, 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->DoneCopy) (pPixmap);
@@ -1202,8 +1202,7 @@ fallback:
     exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
     while (nbox--)
     {
-	exaDrawableDirty (pDrawable, pBox->x1 + xoff, pBox->y1 + yoff,
-			  pBox->x2 + xoff, pBox->y2 + yoff);
+	exaDrawableDirty (pDrawable, pBox->x1, pBox->y1, pBox->x2, pBox->y2);
 	pBox++;
     }
 }
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index 80cf609..926e02a 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -340,6 +340,9 @@ void
 exaFinishAccess(DrawablePtr pDrawable, int index);
 
 void
+exaPixmapDirty(PixmapPtr pPix, int x1, int y1, int x2, int y2);
+
+void
 exaDrawableDirty(DrawablePtr pDrawable, int x1, int y1, int x2, int y2);
 
 Bool
diff --git a/exa/exa_render.c b/exa/exa_render.c
index be7c240..75108a7 100644
--- a/exa/exa_render.c
+++ b/exa/exa_render.c
@@ -302,9 +302,8 @@ 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);
-	exaDrawableDirty (pDst->pDrawable,
-			  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);
@@ -447,9 +446,8 @@ exaTryDriverComposite(CARD8		op,
 				     pbox->y1 + dst_off_y,
 				     pbox->x2 - pbox->x1,
 				     pbox->y2 - pbox->y1);
-	exaDrawableDirty (pDst->pDrawable,
-			  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->DoneComposite) (pDstPix);
@@ -712,18 +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);
-    exaDrawableDirty(pPicture->pDrawable, 0, 0,
-		     pPicture->pDrawable->width, pPicture->pDrawable->height);
-    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);
 }
 
 /**
@@ -734,18 +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(pPicture->pDrawable, 0, 0,
-		     pPicture->pDrawable->width, pPicture->pDrawable->height);
+    exaDrawableDirty(pDraw, pDraw->x, pDraw->y,
+		     pDraw->x + pDraw->width, pDraw->y + pDraw->height);
+    exaFinishAccess(pDraw, EXA_PREPARE_DEST);
 }
 
 /**
@@ -1036,8 +1036,8 @@ exaGlyphs (CARD8	op,
 			     0, 0, glyph->info.width, glyph->info.height, 0, 0);
 	    }
 
-	    exaDrawableDirty (&pPixmap->drawable, 0, 0,
-			      glyph->info.width, glyph->info.height);
+	    exaPixmapDirty (pPixmap, 0, 0,
+			    glyph->info.width, glyph->info.height);
 
 	    if (maskFormat)
 	    {
diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c
index a309115..7713a08 100644
--- a/exa/exa_unaccel.c
+++ b/exa/exa_unaccel.c
@@ -23,26 +23,6 @@
 
 #include "exa_priv.h"
 
-#define TRIM_BOX(box, pGC) if (pGC->pCompositeClip) { \
-	    BoxPtr extents = &pGC->pCompositeClip->extents;\
-	    if(box.x1 < extents->x1) box.x1 = extents->x1; \
-	    if(box.x2 > extents->x2) box.x2 = extents->x2; \
-	    if(box.y1 < extents->y1) box.y1 = extents->y1; \
-	    if(box.y2 > extents->y2) box.y2 = extents->y2; \
-	    }
-
-#define TRANSLATE_BOX(box, pDrawable) { \
-	    box.x1 += pDrawable->x; \
-	    box.x2 += pDrawable->x; \
-	    box.y1 += pDrawable->y; \
-	    box.y2 += pDrawable->y; \
-	    }
-
-#define TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC) { \
-	    TRANSLATE_BOX(box, pDrawable); \
-	    TRIM_BOX(box, pGC); \
-	    }
-
 /*
  * These functions wrap the low-level fb rendering functions and
  * synchronize framebuffer/accelerated drawing by stalling until
@@ -222,10 +202,9 @@ ExaCheckPolyFillRect (DrawablePtr pDrawa
     EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
 
     if (nrect) {
-	BoxRec box = { .x1 = max(prect->x,0),
-		       .x2 = min(prect->x + prect->width,pDrawable->width),
-		       .y1 = max(prect->y,0),
-		       .y2 = min(prect->y + prect->height,pDrawable->height) };
+	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);
@@ -239,15 +218,14 @@ ExaCheckPolyFillRect (DrawablePtr pDrawa
 	while (--nrect)
 	{
 	    prect++;
-	    box.x1 = min(box.x1, prect->x);
-	    box.x2 = max(box.x2, prect->x + prect->width);
-	    box.y1 = min(box.y1, prect->y);
-	    box.y2 = max(box.y2, prect->y + prect->height);
+	    x1 = min(x1, prect->x);
+	    x2 = max(x2, prect->x + prect->width);
+	    y1 = min(y1, prect->y);
+	    y2 = max(y2, prect->y + prect->height);
 	}
 
-	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
-
-	exaDrawableDirty (pDrawable, box.x1, box.x2, box.y1, box.y2);
+	exaDrawableDirty (pDrawable, pDrawable->x + x1, pDrawable->y + y1,
+			  pDrawable->x + x2, pDrawable->y + y2);
     }
 }
 
diff-tree 467c00cf450826e0bf06fe94470ec193af625d68 (from 4334860e69e7d5b156082bd05c7a86708e5bad4c)
Author: George Sapountzis <gsap7 at yahoo.gr>
Date:   Tue Dec 19 18:45:25 2006 +0100

    exaGlyphs: mark dirty for software path also.
    
    This affects drivers with no UploadToScreen or UploadToScreen failures.

diff --git a/exa/exa_render.c b/exa/exa_render.c
index a735820..be7c240 100644
--- a/exa/exa_render.c
+++ b/exa/exa_render.c
@@ -1034,11 +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, 0, 0,
-				  glyph->info.width, glyph->info.height);
 	    }
 
+	    exaDrawableDirty (&pPixmap->drawable, 0, 0,
+			      glyph->info.width, glyph->info.height);
+
 	    if (maskFormat)
 	    {
 		exaComposite (PictOpAdd, pPicture, NULL, pMask, 0, 0, 0, 0,
diff-tree 4334860e69e7d5b156082bd05c7a86708e5bad4c (from parents)
Merge: 7e4717683d6c08d1e490a60b7493a94bbc57bf8d fdcc22ca1704d3519156c66804528c21b04fea65
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Tue Dec 19 16:29:26 2006 +0100

    Merge branch 'master' into exa-damagetrack
    
    Conflicts:
    
    	exa/exa_accel.c
    	exa/exa_migration.c

diff --cc exa/exa_accel.c
index 102973a,098b27c..d2fe2e0
@@@ -767,14 -739,11 +768,14 @@@
  
      pixmaps[0].as_dst = TRUE;
      pixmaps[0].as_src = FALSE;
-     pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
+     pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
 - 
 +
 +    /* We need to initialize x/yoff for tracking damage in the fallback case */
 +    pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
 +
      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;
@@@ -1122,11 -1070,8 +1123,11 @@@
      pixmaps[1].as_src = TRUE;
      pixmaps[1].pPix = pTile;
  
 +    /* We need to initialize x/yoff for tracking damage in the fallback case */
 +    pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
 +
-     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)
      {
diff-tree 7e4717683d6c08d1e490a60b7493a94bbc57bf8d (from f9f33b72e34eaeccea2a20f4a3dd68c2dbefc90e)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Sun Oct 15 18:12:28 2006 +0200

    exaDrawableDirty: Fix initialization of BoxRec.
    
    This will hopefully fix the partial window corruption experienced by some
    people.

diff --git a/exa/exa.c b/exa/exa.c
index b0c4d31..3e6ac76 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -126,7 +126,8 @@ exaDrawableDirty (DrawablePtr pDrawable,
 {
     ExaPixmapPrivPtr pExaPixmap;
     RegionPtr pDamageReg;
-    BoxRec box = { max(x1,0), max(y1,0), min(x2,pDrawable->width), min(y2,pDrawable->height) };
+    BoxRec box = { .x1 = max(x1,0), .x2 = min(x2,pDrawable->width),
+		   .y1 = max(y1,0), .y2 = min(y2,pDrawable->height) };
     RegionRec region;
 
     pExaPixmap = ExaGetPixmapPriv(exaGetDrawablePixmap (pDrawable));
diff-tree f9f33b72e34eaeccea2a20f4a3dd68c2dbefc90e (from 6060b612de6b41f872d034c6130770c1d189d0a3)
Author: Michel Dänzer <michel at tungstengraphics.com>
Date:   Mon Jun 12 20:19:11 2006 +0200

    Track per-drawable damage to minimize UTS and DFS transfers.
    
    Based on work by Eric Anholt.

diff --git a/exa/exa.c b/exa/exa.c
index 75d5c0d..b0c4d31 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -122,13 +122,22 @@ exaGetDrawablePixmap(DrawablePtr pDrawab
  * 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;
+    RegionPtr pDamageReg;
+    BoxRec box = { max(x1,0), max(y1,0), min(x2,pDrawable->width), min(y2,pDrawable->height) };
+    RegionRec region;
 
     pExaPixmap = ExaGetPixmapPriv(exaGetDrawablePixmap (pDrawable));
-    if (pExaPixmap != NULL)
-	pExaPixmap->dirty = TRUE;
+    if (!pExaPixmap || 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);
 }
 
 static Bool
@@ -149,6 +158,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 +226,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;
 }
@@ -334,8 +357,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 +367,6 @@ exaFinishAccess(DrawablePtr pDrawable, i
     PixmapPtr	    pPixmap;
     ExaPixmapPrivPtr pExaPixmap;
 
-    if (index == EXA_PREPARE_DEST)
-	exaDrawableDirty (pDrawable);
-
     pPixmap = exaGetDrawablePixmap (pDrawable);
 
     pExaPixmap = ExaGetPixmapPriv(pPixmap);
@@ -373,7 +392,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 +423,7 @@ exaValidateGC (GCPtr pGC, Mask changes, 
 		exaPrepareAccess(&pOldTile->drawable, EXA_PREPARE_SRC);
 		pNewTile = fb24_32ReformatTile (pOldTile,
 						pDrawable->bitsPerPixel);
+		exaDrawableDirty(&pNewTile->drawable, 0, 0, pNewTile->drawable.width, pNewTile->drawable.height);
 		exaFinishAccess(&pOldTile->drawable, EXA_PREPARE_SRC);
 	    }
 	    if (pNewTile)
@@ -419,9 +439,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);
+	    exaDrawableDirty(&pGC->tile.pixmap->drawable, 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.
diff --git a/exa/exa_accel.c b/exa/exa_accel.c
index bc77a40..102973a 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
@@ -104,6 +109,9 @@ exaFillSpans(DrawablePtr pDrawable, GCPt
 	    (*pExaScr->info->Solid) (pPixmap,
 				     fullX1 + off_x, fullY1 + off_y,
 				     fullX2 + off_x, fullY1 + 1 + off_y);
+	    exaDrawableDirty (pDrawable,
+			      fullX1 + off_x, fullY1 + off_y,
+			      fullX2 + off_x, fullY1 + 1 + off_y);
 	}
 	else
 	{
@@ -118,17 +126,20 @@ 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);
+			exaDrawableDirty (pDrawable,
+					  partX1 + off_x, fullY1 + off_y,
+					  partX2 + off_x, fullY1 + 1 + off_y);
+		    }
 		}
 		pbox++;
 	    }
 	}
     }
     (*pExaScr->info->DoneSolid) (pPixmap);
-    exaDrawableDirty (pDrawable);
     exaMarkSync(pScreen);
 }
 
@@ -222,8 +233,8 @@ exaPutImage (DrawablePtr pDrawable, GCPt
 
 	    exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
 	}
+	exaDrawableDirty(pDrawable, x1 + xoff, y1 + yoff, x2 + xoff, y2 + yoff);
     }
-    exaDrawableDirty(pDrawable);
 
     return;
 
@@ -351,11 +362,13 @@ exaCopyNtoNTwoDir (DrawablePtr pSrcDrawa
 				       dst_off_y + pbox->y1 + i,
 				       pbox->x2 - pbox->x1, 1);
 	}
+	exaDrawableDirty(pDstDrawable,
+			 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;
 }
 
@@ -423,11 +436,13 @@ exaCopyNtoN (DrawablePtr    pSrcDrawable
 				    pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
 				    pbox->x2 - pbox->x1,
 				    pbox->y2 - pbox->y1);
+	    exaDrawableDirty (pDstDrawable,
+			      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 +457,13 @@ fallback:
 		bitplane, closure);
     exaFinishAccess (pSrcDrawable, EXA_PREPARE_SRC);
     exaFinishAccess (pDstDrawable, EXA_PREPARE_DEST);
+    while (nbox--)
+    {
+	exaDrawableDirty (pDstDrawable,
+			  pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
+			  pbox->x2 + dst_off_x, pbox->y2 + dst_off_y);
+	pbox++;
+    }
 }
 
 RegionPtr
@@ -681,6 +703,9 @@ exaPolyFillRect(DrawablePtr pDrawable,
 	    (*pExaScr->info->Solid) (pPixmap,
 				     fullX1 + xoff, fullY1 + yoff,
 				     fullX2 + xoff, fullY2 + yoff);
+	    exaDrawableDirty (pDrawable,
+			      fullX1 + xoff, fullY1 + yoff,
+			      fullX2 + xoff, fullY2 + yoff);
 	}
 	else
 	{
@@ -706,15 +731,18 @@ 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);
+		    exaDrawableDirty (pDrawable,
+				      partX1 + xoff, partY1 + yoff,
+				      partX2 + xoff, partY2 + yoff);
+		}
 	    }
 	}
     }
     (*pExaScr->info->DoneSolid) (pPixmap);
-    exaDrawableDirty (pDrawable);
     exaMarkSync(pDrawable->pScreen);
 }
 
@@ -735,11 +763,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);
- 
+
+    /* We need to initialize x/yoff for tracking damage in the fallback case */
+    pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
+
     if (pExaScr->swappedOut ||
 	pDrawable->width > pExaScr->info->maxX ||
 	pDrawable->height > pExaScr->info->maxY)
@@ -750,19 +782,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 +824,19 @@ 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);
+	exaDrawableDirty (pDrawable,
+			  partX1 + xoff, partY1 + yoff,
+			  partX2 + xoff, partY2 + yoff);
     }
+
+    if (fallback)
+	return;
+
     (*pExaScr->info->DoneSolid) (pPixmap);
-    exaDrawableDirty (pDrawable);
     exaMarkSync(pDrawable->pScreen);
 }
 
@@ -928,6 +969,8 @@ exaImageGlyphBlt (DrawablePtr	pDrawable,
 			      gStride,
 			      0);
 	    }
+	    exaDrawableDirty(pDrawable, gx + dstXoff, gy + dstYoff,
+			     gx + dstXoff + gWidth, gy + dstYoff + gHeight);
 	}
 	x += pci->metrics.characterWidth;
     }
@@ -994,6 +1037,8 @@ 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;
@@ -1011,19 +1056,18 @@ 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);
+	    exaDrawableDirty (pDrawable,
+			      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 +1078,13 @@ fallback:
 	fbFillRegionSolid (pDrawable, pRegion, 0,
 			   fbReplicatePixel (pixel, pDrawable->bitsPerPixel));
 	exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
+	while (nbox--)
+	{
+	    exaDrawableDirty (pDrawable,
+			      pBox->x1 + xoff, pBox->y1 + yoff,
+			      pBox->x2 + xoff, pBox->y2 + yoff);
+	    pBox++;
+	}
     }
 }
 
@@ -1047,9 +1098,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;
@@ -1069,6 +1122,9 @@ exaFillRegionTiled (DrawablePtr	pDrawabl
     pixmaps[1].as_src = TRUE;
     pixmaps[1].pPix = pTile;
 
+    /* We need to initialize x/yoff for tracking damage in the fallback case */
+    pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
+
     if (pDrawable->width > pExaScr->info->maxX ||
 	pDrawable->height > pExaScr->info->maxY ||
 	tileWidth > pExaScr->info->maxX ||
@@ -1081,18 +1137,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 +1172,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 +1181,12 @@ exaFillRegionTiled (DrawablePtr	pDrawabl
 		dstY += h;
 		tileY = 0;
 	    }
+	    exaDrawableDirty (pDrawable, 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 +1199,12 @@ fallback:
     fbFillRegionTiled (pDrawable, pRegion, pTile);
     exaFinishAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC);
     exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
+    while (nbox--)
+    {
+	exaDrawableDirty (pDrawable, pBox->x1 + xoff, pBox->y1 + yoff,
+			  pBox->x2 + xoff, pBox->y2 + yoff);
+	pBox++;
+    }
 }
 
 void
diff --git a/exa/exa_migration.c b/exa/exa_migration.c
index 57d651f..d24a1bf 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);
 }
 
 /**
@@ -213,6 +254,7 @@ 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 ?
@@ -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,30 +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();
-	}
+    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;
 }
 
 /**
@@ -460,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 b55802e..d5864dc 100644
--- a/exa/exa_offscreen.c
+++ b/exa/exa_offscreen.c
@@ -390,6 +390,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 90af553..c725b4d 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
@@ -168,16 +169,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 {
@@ -323,7 +324,7 @@ ExaCheckComposite (CARD8      op,
 		  CARD16     height);
 #endif
 
-/* exaoffscreen.c */
+/* exa_offscreen.c */
 void
 ExaOffscreenMarkUsed (PixmapPtr pPixmap);
 
@@ -347,7 +348,7 @@ void
 exaFinishAccess(DrawablePtr pDrawable, int index);
 
 void
-exaDrawableDirty(DrawablePtr pDrawable);
+exaDrawableDirty(DrawablePtr pDrawable, int x1, int y1, int x2, int y2);
 
 Bool
 exaDrawableIsOffscreen (DrawablePtr pDrawable);
diff --git a/exa/exa_render.c b/exa/exa_render.c
index 26b29ab..790a359 100644
--- a/exa/exa_render.c
+++ b/exa/exa_render.c
@@ -298,12 +298,13 @@ 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);
+	exaDrawableDirty (pDst->pDrawable,
+			  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;
@@ -437,12 +438,13 @@ exaTryDriverComposite(CARD8		op,
 				     pbox->y1 + dst_off_y,
 				     pbox->x2 - pbox->x1,
 				     pbox->y2 - pbox->y1);
+	exaDrawableDirty (pDst->pDrawable,
+			  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;
@@ -648,6 +650,8 @@ exaRasterizeTrapezoid (PicturePtr pPictu
 
     exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
     fbRasterizeTrapezoid(pPicture, trap, x_off, y_off);
+    exaDrawableDirty(pPicture->pDrawable, 0, 0,
+		     pPicture->pDrawable->width, pPicture->pDrawable->height);
     exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
 }
 
@@ -669,6 +673,8 @@ exaAddTriangles (PicturePtr pPicture, IN
     exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
     fbAddTriangles(pPicture, x_off, y_off, ntri, tris);
     exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
+    exaDrawableDirty(pPicture->pDrawable, 0, 0,
+		     pPicture->pDrawable->width, pPicture->pDrawable->height);
 }
 
 /**
@@ -958,7 +964,8 @@ exaGlyphs (CARD8	op,
 		exaCopyArea (&pScratchPixmap->drawable, &pPixmap->drawable, pGC,
 			     0, 0, glyph->info.width, glyph->info.height, 0, 0);
 	    } else {
-		exaDrawableDirty (&pPixmap->drawable);
+		exaDrawableDirty (&pPixmap->drawable, 0, 0,
+				  glyph->info.width, glyph->info.height);
 	    }
 
 	    if (maskFormat)
diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c
index f9df6ad..a309115 100644
--- a/exa/exa_unaccel.c
+++ b/exa/exa_unaccel.c
@@ -23,6 +23,26 @@
 
 #include "exa_priv.h"
 
+#define TRIM_BOX(box, pGC) if (pGC->pCompositeClip) { \
+	    BoxPtr extents = &pGC->pCompositeClip->extents;\
+	    if(box.x1 < extents->x1) box.x1 = extents->x1; \
+	    if(box.x2 > extents->x2) box.x2 = extents->x2; \
+	    if(box.y1 < extents->y1) box.y1 = extents->y1; \
+	    if(box.y2 > extents->y2) box.y2 = extents->y2; \
+	    }
+
+#define TRANSLATE_BOX(box, pDrawable) { \
+	    box.x1 += pDrawable->x; \
+	    box.x2 += pDrawable->x; \
+	    box.y1 += pDrawable->y; \
+	    box.y2 += pDrawable->y; \
+	    }
+
+#define TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC) { \
+	    TRANSLATE_BOX(box, pDrawable); \
+	    TRIM_BOX(box, pGC); \
+	    }
+
 /*
  * These functions wrap the low-level fb rendering functions and
  * synchronize framebuffer/accelerated drawing by stalling until
@@ -200,11 +220,35 @@ 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) {
+	BoxRec box = { .x1 = max(prect->x,0),
+		       .x2 = min(prect->x + prect->width,pDrawable->width),
+		       .y1 = max(prect->y,0),
+		       .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++;
+	    box.x1 = min(box.x1, prect->x);
+	    box.x2 = max(box.x2, prect->x + prect->width);
+	    box.y1 = min(box.y1, prect->y);
+	    box.y2 = max(box.y2, prect->y + prect->height);
+	}
+
+	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
+
+	exaDrawableDirty (pDrawable, box.x1, box.x2, box.y1, box.y2);
+    }
 }
 
 void
diff-tree 6060b612de6b41f872d034c6130770c1d189d0a3 (from f8535edec736cf19740bd41ed2adfe531f2c26ac)
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.

diff --git a/miext/damage/damage.c b/miext/damage/damage.c
index ef7bca4..5b94028 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);
 }
@@ -1822,12 +1883,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;
@@ -1911,6 +1974,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);
 }
 
@@ -1964,4 +2028,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