diff --git a/xorg-x11-server.spec b/xorg-x11-server.spec index 4b6acff..459d57e 100644 --- a/xorg-x11-server.spec +++ b/xorg-x11-server.spec @@ -19,7 +19,7 @@ Summary: X.Org X11 X server Name: xorg-x11-server Version: 1.5.0 -Release: 1%{?dist} +Release: 2%{?dist} URL: http://www.x.org License: MIT Group: User Interface/X @@ -44,7 +44,7 @@ Source11: fedora-setup-keyboard Patch100: xorg-x11-server-1.1.0-no-move-damage.patch Patch101: xserver-1.4.99-dont-backfill-bg-none.patch # XXX does this need rebasing still? -#Patch102: xserver-1.4.99-exa-master-upgrade.patch +Patch102: xserver-1.5.0-exa-master-upgrade.patch Patch103: xserver-1.5.0-bg-none-root.patch # Red Hat specific tweaking, not intended for upstream @@ -498,6 +498,9 @@ rm -rf $RPM_BUILD_ROOT %changelog +* Wed Sep 10 2008 Dave Airlie 1.5.0-2 +- bring master exa back + * Wed Sep 03 2008 Adam Jackson 1.5.0-1 - xserver 1.5.0 - Revert to the EXA from 1.5.0, should be good enough one hopes. diff --git a/xserver-1.5.0-exa-master-upgrade.patch b/xserver-1.5.0-exa-master-upgrade.patch new file mode 100644 index 0000000..eeccce1 --- /dev/null +++ b/xserver-1.5.0-exa-master-upgrade.patch @@ -0,0 +1,2094 @@ +From e99347a3e82e6db47dd482169b6799968afc3893 Mon Sep 17 00:00:00 2001 +From: Dave Airlie +Date: Wed, 20 Aug 2008 10:11:07 -0400 +Subject: [PATCH] Upgrade to master EXA + +--- + + +diff --git a/exa/Makefile.am b/exa/Makefile.am +index e2f7ed3..2b3f1e4 100644 +--- a/exa/Makefile.am ++++ b/exa/Makefile.am +@@ -18,6 +18,7 @@ libexa_la_SOURCES = \ + exa.c \ + exa.h \ + exa_accel.c \ ++ exa_glyphs.c \ + exa_migration.c \ + exa_offscreen.c \ + exa_render.c \ +diff --git a/exa/exa.c b/exa/exa.c +index ccf148a..12c1549 100644 +--- a/exa/exa.c ++++ b/exa/exa.c +@@ -35,8 +35,6 @@ + #include + + #include "exa_priv.h" +-#include +-#include "dixfontstr.h" + #include "exa.h" + #include "cw.h" + +@@ -161,7 +159,7 @@ exaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2) + RegionPtr pDamageReg; + RegionRec region; + +- if (!pExaPixmap) ++ if (!pExaPixmap || !pExaPixmap->pDamage) + return; + + box.x1 = max(x1, 0); +@@ -261,6 +259,21 @@ exaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap, + pExaScr->info->pixmapPitchAlign); + } + ++ ++static void ++ExaDamageReport(DamagePtr pDamage, RegionPtr pReg, void *pClosure) ++{ ++ PixmapPtr pPixmap = pClosure; ++ ExaPixmapPriv(pPixmap); ++ RegionPtr pDamageReg = DamageRegion(pDamage); ++ ++ if (pExaPixmap->pendingDamage) { ++ REGION_UNION(pScreen, pDamageReg, pDamageReg, pReg); ++ pExaPixmap->pendingDamage = FALSE; ++ } ++} ++ ++ + /** + * exaCreatePixmap() creates a new pixmap. + * +@@ -321,6 +334,7 @@ exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth, + paddedWidth, NULL); + pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; + pExaPixmap->fb_ptr = NULL; ++ pExaPixmap->pDamage = NULL; + } else { + pExaPixmap->driverPriv = NULL; + /* Scratch pixmaps may have w/h equal to zero, and may not be +@@ -345,21 +359,22 @@ exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth, + fbDestroyPixmap(pPixmap); + return NULL; + } +- } +- +- pExaPixmap->area = NULL; + +- /* Set up damage tracking */ +- pExaPixmap->pDamage = DamageCreate (NULL, NULL, DamageReportNone, TRUE, +- pScreen, pPixmap); ++ /* Set up damage tracking */ ++ pExaPixmap->pDamage = DamageCreate (ExaDamageReport, NULL, ++ DamageReportRawRegion, TRUE, ++ pScreen, pPixmap); + +- if (pExaPixmap->pDamage == NULL) { +- fbDestroyPixmap (pPixmap); +- return NULL; +- } ++ if (pExaPixmap->pDamage == NULL) { ++ fbDestroyPixmap (pPixmap); ++ return NULL; ++ } + +- DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage); +- DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE); ++ DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage); ++ DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE); ++ } ++ ++ pExaPixmap->area = NULL; + + /* None of the pixmap bits are valid initially */ + REGION_NULL(pScreen, &pExaPixmap->validSys); +@@ -656,34 +671,25 @@ exaCreateGC (GCPtr pGC) + return TRUE; + } + +-void +-exaPrepareAccessWindow(WindowPtr pWin) ++static Bool ++exaChangeWindowAttributes(WindowPtr pWin, unsigned long mask) + { +- if (pWin->backgroundState == BackgroundPixmap) ++ Bool ret; ++ ++ if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap) + exaPrepareAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC); + +- if (pWin->borderIsPixel == FALSE) +- exaPrepareAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_SRC); +-} ++ if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE) ++ exaPrepareAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK); + +-void +-exaFinishAccessWindow(WindowPtr pWin) +-{ +- if (pWin->backgroundState == BackgroundPixmap) +- exaFinishAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC); ++ ret = fbChangeWindowAttributes(pWin, mask); + +- if (pWin->borderIsPixel == FALSE) +- exaFinishAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_SRC); +-} ++ if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE) ++ exaFinishAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK); + +-static Bool +-exaChangeWindowAttributes(WindowPtr pWin, unsigned long mask) +-{ +- Bool ret; ++ if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap) ++ exaFinishAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC); + +- exaPrepareAccessWindow(pWin); +- ret = fbChangeWindowAttributes(pWin, mask); +- exaFinishAccessWindow(pWin); + return ret; + } + +@@ -737,6 +743,9 @@ exaCloseScreen(int i, ScreenPtr pScreen) + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); + #endif + ++ if (ps->Glyphs == exaGlyphs) ++ exaGlyphsFini(pScreen); ++ + pScreen->CreateGC = pExaScr->SavedCreateGC; + pScreen->CloseScreen = pExaScr->SavedCloseScreen; + pScreen->GetImage = pExaScr->SavedGetImage; +@@ -750,8 +759,9 @@ exaCloseScreen(int i, ScreenPtr pScreen) + #ifdef RENDER + if (ps) { + ps->Composite = pExaScr->SavedComposite; ++ ps->Glyphs = pExaScr->SavedGlyphs; + ps->Trapezoids = pExaScr->SavedTrapezoids; +- ps->AddTraps = pExaScr->SavedAddTraps; ++ ps->Triangles = pExaScr->SavedTriangles; + } + #endif + +@@ -913,14 +923,16 @@ exaDriverInit (ScreenPtr pScreen, + pExaScr->SavedComposite = ps->Composite; + ps->Composite = exaComposite; + ++ if (pScreenInfo->PrepareComposite) { ++ pExaScr->SavedGlyphs = ps->Glyphs; ++ ps->Glyphs = exaGlyphs; ++ } ++ + pExaScr->SavedTriangles = ps->Triangles; + ps->Triangles = exaTriangles; + + pExaScr->SavedTrapezoids = ps->Trapezoids; + ps->Trapezoids = exaTrapezoids; +- +- pExaScr->SavedAddTraps = ps->AddTraps; +- ps->AddTraps = ExaCheckAddTraps; + } + #endif + +@@ -968,6 +980,9 @@ exaDriverInit (ScreenPtr pScreen, + } + } + ++ if (ps->Glyphs == exaGlyphs) ++ exaGlyphsInit(pScreen); ++ + LogMessage(X_INFO, "EXA(%d): Driver registered support for the following" + " operations:\n", pScreen->myNum); + assert(pScreenInfo->PrepareSolid != NULL); +diff --git a/exa/exa.h b/exa/exa.h +index 2562094..8d9bcea 100644 +--- a/exa/exa.h ++++ b/exa/exa.h +@@ -744,21 +744,36 @@ typedef struct _ExaDriver { + + /** @} */ + ++/* in exa.c */ + ExaDriverPtr + exaDriverAlloc(void); + + Bool +-exaDriverInit(ScreenPtr pScreen, ++exaDriverInit(ScreenPtr pScreen, + ExaDriverPtr pScreenInfo); + + void +-exaDriverFini(ScreenPtr pScreen); ++exaDriverFini(ScreenPtr pScreen); + + void + exaMarkSync(ScreenPtr pScreen); + void + exaWaitSync(ScreenPtr pScreen); + ++unsigned long ++exaGetPixmapOffset(PixmapPtr pPix); ++ ++unsigned long ++exaGetPixmapPitch(PixmapPtr pPix); ++ ++unsigned long ++exaGetPixmapSize(PixmapPtr pPix); ++ ++void * ++exaGetPixmapDriverPrivate(PixmapPtr p); ++ ++ ++/* in exa_offscreen.c */ + ExaOffscreenArea * + exaOffscreenAlloc(ScreenPtr pScreen, int size, int align, + Bool locked, +@@ -771,30 +786,23 @@ exaOffscreenFree(ScreenPtr pScreen, ExaOffscreenArea *area); + void + ExaOffscreenMarkUsed (PixmapPtr pPixmap); + +-unsigned long +-exaGetPixmapOffset(PixmapPtr pPix); +- +-unsigned long +-exaGetPixmapPitch(PixmapPtr pPix); +- +-unsigned long +-exaGetPixmapSize(PixmapPtr pPix); +- + void + exaEnableDisableFBAccess (int index, Bool enable); + ++ ++/* in exa_migration.c */ + void + exaMoveInPixmap (PixmapPtr pPixmap); + + void + exaMoveOutPixmap (PixmapPtr pPixmap); + +-void * +-exaGetPixmapDriverPrivate(PixmapPtr p); + ++/* in exa_unaccel.c */ + CARD32 + exaGetPixmapFirstPixel (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 3ec9625..1c07a0b 100644 +--- a/exa/exa_accel.c ++++ b/exa/exa_accel.c +@@ -144,7 +144,6 @@ exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, + ExaScreenPriv (pDrawable->pScreen); + PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); + ExaPixmapPriv(pPix); +- ExaMigrationRec pixmaps[1]; + RegionPtr pClip; + BoxPtr pbox; + int nbox; +@@ -166,11 +165,16 @@ exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, + if (pExaScr->swappedOut) + return FALSE; + +- pixmaps[0].as_dst = TRUE; +- pixmaps[0].as_src = FALSE; +- pixmaps[0].pPix = pPix; +- pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage); +- exaDoMigration (pixmaps, 1, TRUE); ++ if (pExaPixmap->pDamage) { ++ ExaMigrationRec pixmaps[1]; ++ ++ pixmaps[0].as_dst = TRUE; ++ pixmaps[0].as_src = FALSE; ++ pixmaps[0].pPix = pPix; ++ pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage); ++ ++ exaDoMigration (pixmaps, 1, TRUE); ++ } + + pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); + +@@ -441,16 +445,36 @@ exaCopyNtoN (DrawablePtr pSrcDrawable, + pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap); + + /* Check whether the accelerator can use this pixmap. +- * FIXME: If it cannot, use temporary pixmaps so that the drawing +- * happens within limits. ++ * If the pitch of the pixmaps is out of range, there's nothing ++ * we can do but fall back to software rendering. + */ +- if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) +- { ++ if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH || ++ pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH) + goto fallback; +- } else { +- exaDoMigration (pixmaps, 2, TRUE); ++ ++ /* If the width or the height of either of the pixmaps ++ * is out of range, check whether the boxes are actually out of the ++ * addressable range as well. If they aren't, we can still do ++ * the copying in hardware. ++ */ ++ if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) { ++ int i; ++ ++ for (i = 0; i < nbox; i++) { ++ /* src */ ++ if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX || ++ (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY) ++ goto fallback; ++ ++ /* dst */ ++ if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX || ++ (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY) ++ goto fallback; ++ } + } + ++ exaDoMigration (pixmaps, 2, TRUE); ++ + /* Mixed directions must be handled specially if the card is lame */ + if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) && + reverse != upsidedown) { +@@ -860,16 +884,23 @@ exaImageGlyphBlt (DrawablePtr pDrawable, + FbBits depthMask; + PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); + ExaPixmapPriv(pPixmap); +- RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); +- BoxRec extents = *REGION_EXTENTS(pScreen, pending_damage); ++ RegionPtr pending_damage = NULL; ++ BoxRec extents; + int xoff, yoff; + +- if (extents.x1 >= extents.x2 || extents.y1 >= extents.y2) +- return; ++ if (pExaPixmap->pDamage) ++ pending_damage = DamagePendingRegion(pExaPixmap->pDamage); ++ ++ if (pending_damage) { ++ extents = *REGION_EXTENTS(pScreen, pending_damage); ++ ++ if (extents.x1 >= extents.x2 || extents.y1 >= extents.y2) ++ return; + +- depthMask = FbFullMask(pDrawable->depth); ++ depthMask = FbFullMask(pDrawable->depth); ++ } + +- if ((pGC->planemask & depthMask) != depthMask) ++ if (!pending_damage || (pGC->planemask & depthMask) != depthMask) + { + ExaCheckImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppciInit, pglyphBase); + return; +@@ -1103,6 +1134,7 @@ exaFillRegionTiled (DrawablePtr pDrawable, + int nbox = REGION_NUM_RECTS (pRegion); + BoxPtr pBox = REGION_RECTS (pRegion); + Bool ret = FALSE; ++ int i; + + tileWidth = pTile->drawable.width; + tileHeight = pTile->drawable.height; +@@ -1125,14 +1157,11 @@ exaFillRegionTiled (DrawablePtr pDrawable, + pixmaps[1].pPix = pTile; + pixmaps[1].pReg = NULL; + +- exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); +- REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); +- + pExaPixmap = ExaGetPixmapPriv (pPixmap); + + if (pExaPixmap->accel_blocked || pTileExaPixmap->accel_blocked) + { +- goto out; ++ return FALSE; + } else { + exaDoMigration (pixmaps, 2, TRUE); + } +@@ -1140,24 +1169,33 @@ exaFillRegionTiled (DrawablePtr pDrawable, + pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); + + if (!pPixmap || !exaPixmapIsOffscreen(pTile)) +- goto out; ++ return FALSE; + + if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) + { +- while (nbox--) ++ if (xoff || yoff) ++ REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); ++ ++ for (i = 0; i < nbox; i++) + { +- int height = pBox->y2 - pBox->y1; +- int dstY = pBox->y1; ++ int height = pBox[i].y2 - pBox[i].y1; ++ int dstY = pBox[i].y1; + int tileY; + ++ if (alu == GXcopy) ++ height = min(height, tileHeight); ++ + modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY); + + while (height > 0) { +- int width = pBox->x2 - pBox->x1; +- int dstX = pBox->x1; ++ int width = pBox[i].x2 - pBox[i].x1; ++ int dstX = pBox[i].x1; + int tileX; + int h = tileHeight - tileY; + ++ if (alu == GXcopy) ++ width = min(width, tileWidth); ++ + if (h > height) + h = height; + height -= h; +@@ -1179,17 +1217,57 @@ exaFillRegionTiled (DrawablePtr pDrawable, + dstY += h; + tileY = 0; + } +- pBox++; + } + (*pExaScr->info->DoneCopy) (pPixmap); ++ ++ /* With GXcopy, we only need to do the basic algorithm up to the tile ++ * size; then, we can just keep doubling the destination in each ++ * direction until it fills the box. This way, the number of copy ++ * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where ++ * rx/ry is the ratio between box and tile width/height. This can make ++ * a big difference if each driver copy incurs a significant constant ++ * overhead. ++ */ ++ if (alu != GXcopy) ++ ret = TRUE; ++ else if ((*pExaScr->info->PrepareCopy) (pPixmap, pPixmap, 1, 1, alu, ++ planemask)) { ++ for (i = 0; i < nbox; i++) ++ { ++ int dstX = pBox[i].x1 + tileWidth; ++ int dstY = pBox[i].y1 + tileHeight; ++ int width = min(pBox[i].x2 - dstX, tileWidth); ++ int height = min(pBox[i].y2 - pBox[i].y1, tileHeight); ++ ++ while (dstX < pBox[i].x2) { ++ (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, ++ dstX, pBox[i].y1, width, height); ++ dstX += width; ++ width = min(pBox[i].x2 - dstX, width * 2); ++ } ++ ++ width = pBox[i].x2 - pBox[i].x1; ++ height = min(pBox[i].y2 - dstY, tileHeight); ++ ++ while (dstY < pBox[i].y2) { ++ (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, ++ pBox[i].x1, dstY, width, height); ++ dstY += height; ++ height = min(pBox[i].y2 - dstY, height * 2); ++ } ++ } ++ ++ (*pExaScr->info->DoneCopy) (pPixmap); ++ ++ ret = TRUE; ++ } ++ + exaMarkSync(pDrawable->pScreen); + +- ret = TRUE; ++ if (xoff || yoff) ++ REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); + } + +-out: +- REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); +- + return ret; + } + +diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c +new file mode 100644 +index 0000000..b23e7f6 +--- /dev/null ++++ b/exa/exa_glyphs.c +@@ -0,0 +1,897 @@ ++/* ++ * Copyright © 2008 Red Hat, Inc. ++ * Partly based on code Copyright © 2000 SuSE, Inc. ++ * ++ * Permission to use, copy, modify, distribute, and sell this software and its ++ * documentation for any purpose is hereby granted without fee, provided that ++ * the above copyright notice appear in all copies and that both that ++ * copyright notice and this permission notice appear in supporting ++ * documentation, and that the name of Red Hat not be used in advertising or ++ * publicity pertaining to distribution of the software without specific, ++ * written prior permission. Red Hat makes no representations about the ++ * suitability of this software for any purpose. It is provided "as is" ++ * without express or implied warranty. ++ * ++ * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat ++ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, 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. ++ * ++ * Permission to use, copy, modify, distribute, and sell this software and its ++ * documentation for any purpose is hereby granted without fee, provided that ++ * the above copyright notice appear in all copies and that both that ++ * copyright notice and this permission notice appear in supporting ++ * documentation, and that the name of SuSE not be used in advertising or ++ * publicity pertaining to distribution of the software without specific, ++ * written prior permission. SuSE makes no representations about the ++ * suitability of this software for any purpose. It is provided "as is" ++ * without express or implied warranty. ++ * ++ * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE ++ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, 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. ++ * ++ * Author: Owen Taylor ++ * Based on code by: Keith Packard ++ */ ++ ++#ifdef HAVE_DIX_CONFIG_H ++#include ++#endif ++ ++#include ++ ++#include "exa_priv.h" ++ ++#include "mipict.h" ++ ++#if DEBUG_GLYPH_CACHE ++#define DBG_GLYPH_CACHE(a) ErrorF a ++#else ++#define DBG_GLYPH_CACHE(a) ++#endif ++ ++/* Width of the pixmaps we use for the caches; this should be less than ++ * max texture size of the driver; this may need to actually come from ++ * the driver. ++ */ ++#define CACHE_PICTURE_WIDTH 1024 ++ ++/* Maximum number of glyphs we buffer on the stack before flushing ++ * rendering to the mask or destination surface. ++ */ ++#define GLYPH_BUFFER_SIZE 256 ++ ++typedef struct { ++ PicturePtr source; ++ ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE]; ++ int count; ++} ExaGlyphBuffer, *ExaGlyphBufferPtr; ++ ++typedef enum { ++ ExaGlyphSuccess, /* Glyph added to render buffer */ ++ ExaGlyphFail, /* out of memory, etc */ ++ ExaGlyphNeedFlush, /* would evict a glyph already in the buffer */ ++} ExaGlyphCacheResult; ++ ++void ++exaGlyphsInit(ScreenPtr pScreen) ++{ ++ ExaScreenPriv(pScreen); ++ int i = 0; ++ ++ memset(pExaScr->glyphCaches, 0, sizeof(pExaScr->glyphCaches)); ++ ++ pExaScr->glyphCaches[i].format = PICT_a8; ++ pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16; ++ i++; ++ pExaScr->glyphCaches[i].format = PICT_a8; ++ pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32; ++ i++; ++ pExaScr->glyphCaches[i].format = PICT_a8r8g8b8; ++ pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16; ++ i++; ++ pExaScr->glyphCaches[i].format = PICT_a8r8g8b8; ++ pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32; ++ i++; ++ ++ assert(i == EXA_NUM_GLYPH_CACHES); ++ ++ for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { ++ pExaScr->glyphCaches[i].columns = CACHE_PICTURE_WIDTH / pExaScr->glyphCaches[i].glyphWidth; ++ pExaScr->glyphCaches[i].size = 256; ++ pExaScr->glyphCaches[i].hashSize = 557; ++ } ++} ++ ++static void ++exaUnrealizeGlyphCaches(ScreenPtr pScreen, ++ unsigned int format) ++{ ++ ExaScreenPriv(pScreen); ++ int i; ++ ++ for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { ++ ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; ++ ++ if (cache->format != format) ++ continue; ++ ++ if (cache->picture) { ++ FreePicture ((pointer) cache->picture, (XID) 0); ++ cache->picture = NULL; ++ } ++ ++ if (cache->hashEntries) { ++ xfree(cache->hashEntries); ++ cache->hashEntries = NULL; ++ } ++ ++ if (cache->glyphs) { ++ xfree(cache->glyphs); ++ cache->glyphs = NULL; ++ } ++ cache->glyphCount = 0; ++ } ++} ++ ++/* All caches for a single format share a single pixmap for glyph storage, ++ * allowing mixing glyphs of different sizes without paying a penalty ++ * for switching between source pixmaps. (Note that for a size of font ++ * right at the border between two sizes, we might be switching for almost ++ * every glyph.) ++ * ++ * This function allocates the storage pixmap, and then fills in the ++ * rest of the allocated structures for all caches with the given format. ++ */ ++static Bool ++exaRealizeGlyphCaches(ScreenPtr pScreen, ++ unsigned int format) ++{ ++ ExaScreenPriv(pScreen); ++ ++ int depth = PIXMAN_FORMAT_DEPTH(format); ++ PictFormatPtr pPictFormat; ++ PixmapPtr pPixmap; ++ PicturePtr pPicture; ++ int height; ++ int i; ++ int error; ++ ++ pPictFormat = PictureMatchFormat(pScreen, depth, format); ++ if (!pPictFormat) ++ return FALSE; ++ ++ /* Compute the total vertical size needed for the format */ ++ ++ height = 0; ++ for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { ++ ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; ++ int rows; ++ ++ if (cache->format != format) ++ continue; ++ ++ cache->yOffset = height; ++ ++ rows = (cache->size + cache->columns - 1) / cache->columns; ++ height += rows * cache->glyphHeight; ++ } ++ ++ /* Now allocate the pixmap and picture */ ++ ++ pPixmap = (*pScreen->CreatePixmap) (pScreen, ++ CACHE_PICTURE_WIDTH, ++ height, depth, 0); ++ if (!pPixmap) ++ return FALSE; ++ ++ pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, ++ 0, 0, serverClient, &error); ++ ++ (*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */ ++ ++ if (!pPicture) ++ return FALSE; ++ ++ /* And store the picture in all the caches for the format */ ++ ++ for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { ++ ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; ++ int j; ++ ++ if (cache->format != format) ++ continue; ++ ++ cache->picture = pPicture; ++ cache->picture->refcnt++; ++ cache->hashEntries = xalloc(sizeof(int) * cache->hashSize); ++ cache->glyphs = xalloc(sizeof(ExaCachedGlyphRec) * cache->size); ++ cache->glyphCount = 0; ++ ++ if (!cache->hashEntries || !cache->glyphs) ++ goto bail; ++ ++ for (j = 0; j < cache->hashSize; j++) ++ cache->hashEntries[j] = -1; ++ ++ cache->evictionPosition = rand() % cache->size; ++ } ++ ++ /* Each cache references the picture individually */ ++ FreePicture ((pointer) pPicture, (XID) 0); ++ return TRUE; ++ ++bail: ++ exaUnrealizeGlyphCaches(pScreen, format); ++ return FALSE; ++} ++ ++void ++exaGlyphsFini (ScreenPtr pScreen) ++{ ++ ExaScreenPriv(pScreen); ++ int i; ++ ++ for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { ++ ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; ++ ++ if (cache->picture) ++ exaUnrealizeGlyphCaches(pScreen, cache->format); ++ } ++} ++ ++static int ++exaGlyphCacheHashLookup(ExaGlyphCachePtr cache, ++ GlyphPtr pGlyph) ++{ ++ int slot; ++ ++ slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; ++ ++ while (TRUE) { /* hash table can never be full */ ++ int entryPos = cache->hashEntries[slot]; ++ if (entryPos == -1) ++ return -1; ++ ++ if (memcmp(pGlyph->sha1, cache->glyphs[entryPos].sha1, sizeof(pGlyph->sha1)) == 0){ ++ return entryPos; ++ } ++ ++ slot--; ++ if (slot < 0) ++ slot = cache->hashSize - 1; ++ } ++} ++ ++static void ++exaGlyphCacheHashInsert(ExaGlyphCachePtr cache, ++ GlyphPtr pGlyph, ++ int pos) ++{ ++ int slot; ++ ++ memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1)); ++ ++ slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; ++ ++ while (TRUE) { /* hash table can never be full */ ++ if (cache->hashEntries[slot] == -1) { ++ cache->hashEntries[slot] = pos; ++ return; ++ } ++ ++ slot--; ++ if (slot < 0) ++ slot = cache->hashSize - 1; ++ } ++} ++ ++static void ++exaGlyphCacheHashRemove(ExaGlyphCachePtr cache, ++ int pos) ++{ ++ int slot; ++ int emptiedSlot = -1; ++ ++ slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize; ++ ++ while (TRUE) { /* hash table can never be full */ ++ int entryPos = cache->hashEntries[slot]; ++ ++ if (entryPos == -1) ++ return; ++ ++ if (entryPos == pos) { ++ cache->hashEntries[slot] = -1; ++ emptiedSlot = slot; ++ } else if (emptiedSlot != -1) { ++ /* See if we can move this entry into the emptied slot, we can't ++ * do that if if entry would have hashed between the current position ++ * and the emptied slot. (taking wrapping into account). Bad positions ++ * are: ++ * ++ * | XXXXXXXXXX | ++ * i j ++ * ++ * |XXX XXXX| ++ * j i ++ * ++ * i - slot, j - emptiedSlot ++ * ++ * (Knuth 6.4R) ++ */ ++ ++ int entrySlot = (*(CARD32 *) cache->glyphs[entryPos].sha1) % cache->hashSize; ++ ++ if (!((entrySlot >= slot && entrySlot < emptiedSlot) || ++ (emptiedSlot < slot && (entrySlot < emptiedSlot || entrySlot >= slot)))) ++ { ++ cache->hashEntries[emptiedSlot] = entryPos; ++ cache->hashEntries[slot] = -1; ++ emptiedSlot = slot; ++ } ++ } ++ ++ slot--; ++ if (slot < 0) ++ slot = cache->hashSize - 1; ++ } ++} ++ ++#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth) ++#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight) ++ ++/* The most efficient thing to way to upload the glyph to the screen ++ * is to use the UploadToScreen() driver hook; this allows us to ++ * pipeline glyph uploads and to avoid creating offscreen pixmaps for ++ * glyphs that we'll never use again. ++ */ ++static Bool ++exaGlyphCacheUploadGlyph(ScreenPtr pScreen, ++ ExaGlyphCachePtr cache, ++ int pos, ++ GlyphPtr pGlyph) ++{ ++ ExaScreenPriv(pScreen); ++ PicturePtr pGlyphPicture = GlyphPicture(pGlyph)[pScreen->myNum]; ++ PixmapPtr pGlyphPixmap = (PixmapPtr)pGlyphPicture->pDrawable; ++ ExaPixmapPriv(pGlyphPixmap); ++ PixmapPtr pCachePixmap = (PixmapPtr)cache->picture->pDrawable; ++ ExaMigrationRec pixmaps[1]; ++ ++ if (!pExaScr->info->UploadToScreen || pExaScr->swappedOut || pExaPixmap->accel_blocked) ++ return FALSE; ++ ++ /* If the glyph pixmap is already uploaded, no point in doing ++ * things this way */ ++ if (exaPixmapIsOffscreen(pGlyphPixmap)) ++ return FALSE; ++ ++ /* UploadToScreen only works if bpp match */ ++ if (pGlyphPixmap->drawable.bitsPerPixel != pCachePixmap->drawable.bitsPerPixel) ++ return FALSE; ++ ++ /* cache pixmap must be offscreen. */ ++ pixmaps[0].as_dst = TRUE; ++ pixmaps[0].as_src = FALSE; ++ pixmaps[0].pPix = pCachePixmap; ++ pixmaps[0].pReg = NULL; ++ exaDoMigration (pixmaps, 1, TRUE); ++ ++ if (!exaPixmapIsOffscreen(pCachePixmap)) ++ return FALSE; ++ ++ /* CACHE_{X,Y} are in pixmap coordinates, no need for cache{X,Y}off */ ++ if (!pExaScr->info->UploadToScreen(pCachePixmap, ++ CACHE_X(pos), ++ CACHE_Y(pos), ++ pGlyph->info.width, ++ pGlyph->info.height, ++ (char *)pExaPixmap->sys_ptr, ++ pExaPixmap->sys_pitch)) ++ return FALSE; ++ ++ /* This pixmap should never be bound to a window, so no need to offset coordinates. */ ++ exaPixmapDirty (pCachePixmap, ++ CACHE_X(pos), ++ CACHE_Y(pos), ++ CACHE_X(pos) + pGlyph->info.width, ++ CACHE_Y(pos) + pGlyph->info.height); ++ ++ return TRUE; ++} ++ ++static ExaGlyphCacheResult ++exaGlyphCacheBufferGlyph(ScreenPtr pScreen, ++ ExaGlyphCachePtr cache, ++ ExaGlyphBufferPtr buffer, ++ GlyphPtr pGlyph, ++ int xGlyph, ++ int yGlyph) ++{ ++ ExaCompositeRectPtr rect; ++ int pos; ++ ++ if (buffer->source && buffer->source != cache->picture) ++ return ExaGlyphNeedFlush; ++ ++ if (!cache->picture) { ++ if (!exaRealizeGlyphCaches(pScreen, cache->format)) ++ return ExaGlyphFail; ++ } ++ ++ DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n", ++ cache->glyphWidth, cache->glyphHeight, cache->format == PICT_a8 ? "A" : "ARGB", ++ (long)*(CARD32 *) pGlyph->sha1)); ++ ++ pos = exaGlyphCacheHashLookup(cache, pGlyph); ++ if (pos != -1) { ++ DBG_GLYPH_CACHE((" found existing glyph at %d\n", pos)); ++ } else { ++ if (cache->glyphCount < cache->size) { ++ /* Space remaining; we fill from the start */ ++ pos = cache->glyphCount; ++ cache->glyphCount++; ++ DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos)); ++ ++ exaGlyphCacheHashInsert(cache, pGlyph, pos); ++ ++ } else { ++ /* Need to evict an entry. We have to see if any glyphs ++ * already in the output buffer were at this position in ++ * the cache ++ */ ++ ++ pos = cache->evictionPosition; ++ DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos)); ++ if (buffer->count) { ++ int x, y; ++ int i; ++ ++ x = CACHE_X(pos); ++ y = CACHE_Y(pos); ++ ++ for (i = 0; i < buffer->count; i++) { ++ if (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y) { ++ DBG_GLYPH_CACHE((" must flush buffer\n")); ++ return ExaGlyphNeedFlush; ++ } ++ } ++ } ++ ++ /* OK, we're all set, swap in the new glyph */ ++ exaGlyphCacheHashRemove(cache, pos); ++ exaGlyphCacheHashInsert(cache, pGlyph, pos); ++ ++ /* And pick a new eviction position */ ++ cache->evictionPosition = rand() % cache->size; ++ } ++ ++ /* Now actually upload the glyph into the cache picture; if ++ * we can't do it with UploadToScreen (because the glyph is ++ * offscreen, etc), we fall back to CompositePicture. ++ */ ++ if (!exaGlyphCacheUploadGlyph(pScreen, cache, pos, pGlyph)) { ++ CompositePicture (PictOpSrc, ++ GlyphPicture(pGlyph)[pScreen->myNum], ++ None, ++ cache->picture, ++ 0, 0, ++ 0, 0, ++ CACHE_X(pos), ++ CACHE_Y(pos), ++ pGlyph->info.width, ++ pGlyph->info.height); ++ } ++ ++ } ++ ++ ++ buffer->source = cache->picture; ++ ++ rect = &buffer->rects[buffer->count]; ++ rect->xSrc = CACHE_X(pos); ++ rect->ySrc = CACHE_Y(pos); ++ rect->xDst = xGlyph - pGlyph->info.x; ++ rect->yDst = yGlyph - pGlyph->info.y; ++ rect->width = pGlyph->info.width; ++ rect->height = pGlyph->info.height; ++ ++ buffer->count++; ++ ++ return ExaGlyphSuccess; ++} ++ ++#undef CACHE_X ++#undef CACHE_Y ++ ++static ExaGlyphCacheResult ++exaBufferGlyph(ScreenPtr pScreen, ++ ExaGlyphBufferPtr buffer, ++ GlyphPtr pGlyph, ++ int xGlyph, ++ int yGlyph) ++{ ++ ExaScreenPriv(pScreen); ++ unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format; ++ int width = pGlyph->info.width; ++ int height = pGlyph->info.height; ++ ExaCompositeRectPtr rect; ++ PicturePtr source; ++ int i; ++ ++ if (buffer->count == GLYPH_BUFFER_SIZE) ++ return ExaGlyphNeedFlush; ++ ++ if (PICT_FORMAT_BPP(format) == 1) ++ format = PICT_a8; ++ ++ for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { ++ ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; ++ ++ if (format == cache->format && ++ width <= cache->glyphWidth && ++ height <= cache->glyphHeight) { ++ ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen, &pExaScr->glyphCaches[i], ++ buffer, ++ pGlyph, xGlyph, yGlyph); ++ switch (result) { ++ case ExaGlyphFail: ++ break; ++ case ExaGlyphSuccess: ++ case ExaGlyphNeedFlush: ++ return result; ++ } ++ } ++ } ++ ++ /* Couldn't find the glyph in the cache, use the glyph picture directly */ ++ ++ source = GlyphPicture(pGlyph)[pScreen->myNum]; ++ if (buffer->source && buffer->source != source) ++ return ExaGlyphNeedFlush; ++ ++ buffer->source = source; ++ ++ rect = &buffer->rects[buffer->count]; ++ rect->xSrc = 0; ++ rect->ySrc = 0; ++ rect->xDst = xGlyph - pGlyph->info.x; ++ rect->yDst = yGlyph - pGlyph->info.y; ++ rect->width = pGlyph->info.width; ++ rect->height = pGlyph->info.height; ++ ++ buffer->count++; ++ ++ return ExaGlyphSuccess; ++} ++ ++static void ++exaGlyphsToMask(PicturePtr pMask, ++ ExaGlyphBufferPtr buffer) ++{ ++ exaCompositeRects(PictOpAdd, buffer->source, pMask, ++ buffer->count, buffer->rects); ++ ++ buffer->count = 0; ++ buffer->source = NULL; ++} ++ ++static void ++exaGlyphsToDst(CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pDst, ++ ExaGlyphBufferPtr buffer, ++ INT16 xSrc, ++ INT16 ySrc, ++ INT16 xDst, ++ INT16 yDst) ++{ ++ int i; ++ ++ for (i = 0; i < buffer->count; i++) { ++ ExaCompositeRectPtr rect = &buffer->rects[i]; ++ ++ CompositePicture (op, ++ pSrc, ++ buffer->source, ++ pDst, ++ xSrc + rect->xDst - xDst, ++ ySrc + rect->yDst - yDst, ++ rect->xSrc, ++ rect->ySrc, ++ rect->xDst, ++ rect->yDst, ++ rect->width, ++ rect->height); ++ } ++ ++ buffer->count = 0; ++ buffer->source = NULL; ++} ++ ++/* Cut and paste from render/glyph.c - probably should export it instead */ ++static void ++GlyphExtents (int nlist, ++ GlyphListPtr list, ++ GlyphPtr *glyphs, ++ BoxPtr extents) ++{ ++ int x1, x2, y1, y2; ++ int n; ++ GlyphPtr glyph; ++ int x, y; ++ ++ x = 0; ++ y = 0; ++ extents->x1 = MAXSHORT; ++ extents->x2 = MINSHORT; ++ extents->y1 = MAXSHORT; ++ extents->y2 = MINSHORT; ++ while (nlist--) ++ { ++ x += list->xOff; ++ y += list->yOff; ++ n = list->len; ++ list++; ++ while (n--) ++ { ++ glyph = *glyphs++; ++ x1 = x - glyph->info.x; ++ if (x1 < MINSHORT) ++ x1 = MINSHORT; ++ y1 = y - glyph->info.y; ++ if (y1 < MINSHORT) ++ y1 = MINSHORT; ++ x2 = x1 + glyph->info.width; ++ if (x2 > MAXSHORT) ++ x2 = MAXSHORT; ++ y2 = y1 + glyph->info.height; ++ if (y2 > MAXSHORT) ++ y2 = MAXSHORT; ++ if (x1 < extents->x1) ++ extents->x1 = x1; ++ if (x2 > extents->x2) ++ extents->x2 = x2; ++ if (y1 < extents->y1) ++ extents->y1 = y1; ++ if (y2 > extents->y2) ++ extents->y2 = y2; ++ x += glyph->info.xOff; ++ y += glyph->info.yOff; ++ } ++ } ++} ++ ++/** ++ * Returns TRUE if the glyphs in the lists intersect. Only checks based on ++ * bounding box, which appears to be good enough to catch most cases at least. ++ */ ++static Bool ++exaGlyphsIntersect(int nlist, GlyphListPtr list, GlyphPtr *glyphs) ++{ ++ int x1, x2, y1, y2; ++ int n; ++ GlyphPtr glyph; ++ int x, y; ++ BoxRec extents; ++ Bool first = TRUE; ++ ++ x = 0; ++ y = 0; ++ while (nlist--) { ++ x += list->xOff; ++ y += list->yOff; ++ n = list->len; ++ list++; ++ while (n--) { ++ glyph = *glyphs++; ++ ++ if (glyph->info.width == 0 || glyph->info.height == 0) { ++ x += glyph->info.xOff; ++ y += glyph->info.yOff; ++ continue; ++ } ++ ++ x1 = x - glyph->info.x; ++ if (x1 < MINSHORT) ++ x1 = MINSHORT; ++ y1 = y - glyph->info.y; ++ if (y1 < MINSHORT) ++ y1 = MINSHORT; ++ x2 = x1 + glyph->info.width; ++ if (x2 > MAXSHORT) ++ x2 = MAXSHORT; ++ y2 = y1 + glyph->info.height; ++ if (y2 > MAXSHORT) ++ y2 = MAXSHORT; ++ ++ if (first) { ++ extents.x1 = x1; ++ extents.y1 = y1; ++ extents.x2 = x2; ++ extents.y2 = y2; ++ first = FALSE; ++ } else { ++ if (x1 < extents.x2 && x2 > extents.x1 && ++ y1 < extents.y2 && y2 > extents.y1) ++ { ++ return TRUE; ++ } ++ ++ if (x1 < extents.x1) ++ extents.x1 = x1; ++ if (x2 > extents.x2) ++ extents.x2 = x2; ++ if (y1 < extents.y1) ++ extents.y1 = y1; ++ if (y2 > extents.y2) ++ extents.y2 = y2; ++ } ++ x += glyph->info.xOff; ++ y += glyph->info.yOff; ++ } ++ } ++ ++ return FALSE; ++} ++ ++#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) ++ ++void ++exaGlyphs (CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pDst, ++ PictFormatPtr maskFormat, ++ INT16 xSrc, ++ INT16 ySrc, ++ int nlist, ++ GlyphListPtr list, ++ GlyphPtr *glyphs) ++{ ++ PicturePtr pPicture; ++ PixmapPtr pMaskPixmap = 0; ++ PicturePtr pMask; ++ ScreenPtr pScreen = pDst->pDrawable->pScreen; ++ int width = 0, height = 0; ++ int x, y; ++ int xDst = list->xOff, yDst = list->yOff; ++ int n; ++ GlyphPtr glyph; ++ int error; ++ BoxRec extents = {0, 0, 0, 0}; ++ CARD32 component_alpha; ++ ExaGlyphBuffer buffer; ++ ++ /* If we don't have a mask format but all the glyphs have the same format ++ * and don't intersect, use the glyph format as mask format for the full ++ * benefits of the glyph cache. ++ */ ++ if (!maskFormat) { ++ Bool sameFormat = TRUE; ++ int i; ++ ++ maskFormat = list[0].format; ++ ++ for (i = 0; i < nlist; i++) { ++ if (maskFormat->format != list[i].format->format) { ++ sameFormat = FALSE; ++ break; ++ } ++ } ++ ++ if (!sameFormat || (maskFormat->depth != 1 && ++ exaGlyphsIntersect(nlist, list, glyphs))) { ++ maskFormat = NULL; ++ } ++ } ++ ++ if (maskFormat) ++ { ++ GCPtr pGC; ++ xRectangle rect; ++ ++ GlyphExtents (nlist, list, glyphs, &extents); ++ ++ if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) ++ return; ++ width = extents.x2 - extents.x1; ++ height = extents.y2 - extents.y1; ++ ++ if (maskFormat->depth == 1) { ++ PictFormatPtr a8Format = PictureMatchFormat (pScreen, 8, PICT_a8); ++ ++ if (a8Format) ++ maskFormat = a8Format; ++ } ++ ++ pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, ++ maskFormat->depth, ++ CREATE_PIXMAP_USAGE_SCRATCH); ++ if (!pMaskPixmap) ++ return; ++ component_alpha = NeedsComponent(maskFormat->format); ++ pMask = CreatePicture (0, &pMaskPixmap->drawable, ++ maskFormat, CPComponentAlpha, &component_alpha, ++ serverClient, &error); ++ if (!pMask) ++ { ++ (*pScreen->DestroyPixmap) (pMaskPixmap); ++ return; ++ } ++ pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen); ++ ValidateGC (&pMaskPixmap->drawable, pGC); ++ rect.x = 0; ++ rect.y = 0; ++ rect.width = width; ++ rect.height = height; ++ (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect); ++ FreeScratchGC (pGC); ++ x = -extents.x1; ++ y = -extents.y1; ++ } ++ else ++ { ++ pMask = pDst; ++ x = 0; ++ y = 0; ++ } ++ buffer.count = 0; ++ buffer.source = NULL; ++ while (nlist--) ++ { ++ x += list->xOff; ++ y += list->yOff; ++ n = list->len; ++ while (n--) ++ { ++ glyph = *glyphs++; ++ pPicture = GlyphPicture (glyph)[pScreen->myNum]; ++ ++ if (glyph->info.width > 0 && glyph->info.height > 0 && ++ exaBufferGlyph(pScreen, &buffer, glyph, x, y) == ExaGlyphNeedFlush) ++ { ++ if (maskFormat) ++ exaGlyphsToMask(pMask, &buffer); ++ else ++ exaGlyphsToDst(op, pSrc, pDst, &buffer, ++ xSrc, ySrc, xDst, yDst); ++ ++ exaBufferGlyph(pScreen, &buffer, glyph, x, y); ++ } ++ ++ x += glyph->info.xOff; ++ y += glyph->info.yOff; ++ } ++ list++; ++ } ++ ++ if (maskFormat) ++ exaGlyphsToMask(pMask, &buffer); ++ else ++ exaGlyphsToDst(op, pSrc, pDst, &buffer, ++ xSrc, ySrc, xDst, yDst); ++ ++ if (maskFormat) ++ { ++ x = extents.x1; ++ y = extents.y1; ++ CompositePicture (op, ++ pSrc, ++ pMask, ++ pDst, ++ xSrc + x - xDst, ++ ySrc + y - yDst, ++ 0, 0, ++ x, y, ++ width, height); ++ FreePicture ((pointer) pMask, (XID) 0); ++ (*pScreen->DestroyPixmap) (pMaskPixmap); ++ } ++} +diff --git a/exa/exa_migration.c b/exa/exa_migration.c +index 5f22474..2bb2ad9 100644 +--- a/exa/exa_migration.c ++++ b/exa/exa_migration.c +@@ -33,8 +33,6 @@ + #include + + #include "exa_priv.h" +-#include +-#include "dixfontstr.h" + #include "exa.h" + #include "cw.h" + +@@ -45,6 +43,39 @@ + #endif + + /** ++ * Returns TRUE if the pixmap has damage. ++ * EXA only migrates the parts of a destination ++ * that are affected by rendering. ++ * It uses the current damage as indication. ++ * So anything that does not need to be updated won't be. ++ * For clarity this seperate function was made. ++ * Note that some situations don't use this, ++ * because their calls are wrapped by the damage layer. ++ */ ++Bool ++exaDamageDestForMigration(DrawablePtr pDrawable, PixmapPtr pPix, RegionPtr region) ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ (void) pScreen; /* the macros don't use pScreen currently */ ++ ExaPixmapPriv (pPix); ++ int x_offset, y_offset; ++ RegionPtr pending_damage; ++ ++ if (!pExaPixmap->pDamage) ++ return FALSE; ++ ++ exaGetDrawableDeltas(pDrawable, pPix, &x_offset, &y_offset); ++ ++ REGION_TRANSLATE(pScreen, region, x_offset, y_offset); ++ pending_damage = DamagePendingRegion(pExaPixmap->pDamage); ++ REGION_UNION(pScreen, pending_damage, pending_damage, region); ++ /* Restore region as we got it. */ ++ REGION_TRANSLATE(pScreen, region, -x_offset, -y_offset); ++ ++ return TRUE; ++} ++ ++/** + * Returns TRUE if the pixmap is not movable. This is the case where it's a + * fake pixmap for the frontbuffer (no pixmap private) or it's a scratch + * pixmap created by some other X Server internals (the score says it's +@@ -211,9 +242,9 @@ exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, + pBox->x1, pBox->y1, + pBox->x2 - pBox->x1, + pBox->y2 - pBox->y1, +- pExaPixmap->sys_ptr ++ (char *) (pExaPixmap->sys_ptr + + pBox->y1 * pExaPixmap->sys_pitch +- + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8, ++ + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8), + pExaPixmap->sys_pitch)) + { + if (!access_prepared) { +@@ -301,6 +332,9 @@ exaDoMoveInPixmap (ExaMigrationPtr migrate) + ExaScreenPriv (pScreen); + ExaPixmapPriv (pPixmap); + ++ if (migrate->as_dst) ++ pExaPixmap->pendingDamage = TRUE; ++ + /* If we're VT-switched away, no touching card memory allowed. */ + if (pExaScr->swappedOut) + return; +@@ -369,6 +403,9 @@ exaDoMoveOutPixmap (ExaMigrationPtr migrate) + PixmapPtr pPixmap = migrate->pPix; + ExaPixmapPriv (pPixmap); + ++ if (migrate->as_dst) ++ pExaPixmap->pendingDamage = TRUE; ++ + if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap)) + return; + +diff --git a/exa/exa_priv.h b/exa/exa_priv.h +index e4b6b54..0ebe07b 100644 +--- a/exa/exa_priv.h ++++ b/exa/exa_priv.h +@@ -61,6 +61,7 @@ + #define DEBUG_MIGRATE 0 + #define DEBUG_PIXMAP 0 + #define DEBUG_OFFSCREEN 0 ++#define DEBUG_GLYPH_CACHE 0 + + #if DEBUG_TRACE_FALL + #define EXA_FALLBACK(x) \ +@@ -95,6 +96,38 @@ enum ExaMigrationHeuristic { + ExaMigrationSmart + }; + ++typedef struct { ++ unsigned char sha1[20]; ++} ExaCachedGlyphRec, *ExaCachedGlyphPtr; ++ ++typedef struct { ++ /* The identity of the cache, statically configured at initialization */ ++ unsigned int format; ++ int glyphWidth; ++ int glyphHeight; ++ ++ int size; /* Size of cache; eventually this should be dynamically determined */ ++ ++ /* Hash table mapping from glyph sha1 to position in the glyph; we use ++ * open addressing with a hash table size determined based on size and large ++ * enough so that we always have a good amount of free space, so we can ++ * use linear probing. (Linear probing is preferrable to double hashing ++ * here because it allows us to easily remove entries.) ++ */ ++ int *hashEntries; ++ int hashSize; ++ ++ ExaCachedGlyphPtr glyphs; ++ int glyphCount; /* Current number of glyphs */ ++ ++ PicturePtr picture; /* Where the glyphs of the cache are stored */ ++ int yOffset; /* y location within the picture where the cache starts */ ++ int columns; /* Number of columns the glyphs are layed out in */ ++ int evictionPosition; /* Next random position to evict a glyph */ ++} ExaGlyphCacheRec, *ExaGlyphCachePtr; ++ ++#define EXA_NUM_GLYPH_CACHES 4 ++ + typedef void (*EnableDisableFBAccessProcPtr)(int, Bool); + typedef struct { + ExaDriverPtr info; +@@ -114,7 +147,6 @@ typedef struct { + TrianglesProcPtr SavedTriangles; + GlyphsProcPtr SavedGlyphs; + TrapezoidsProcPtr SavedTrapezoids; +- AddTrapsProcPtr SavedAddTraps; + #endif + + Bool swappedOut; +@@ -123,6 +155,8 @@ typedef struct { + unsigned disableFbCount; + Bool optimize_migration; + unsigned offScreenCounter; ++ ++ ExaGlyphCacheRec glyphCaches[EXA_NUM_GLYPH_CACHES]; + } ExaScreenPrivRec, *ExaScreenPrivPtr; + + /* +@@ -192,6 +226,7 @@ typedef struct { + * location. + */ + DamagePtr pDamage; ++ Bool pendingDamage; + /** + * The valid regions mark the valid bits (at least, as they're derived from + * damage, which may be overreported) of a pixmap's system and FB copies. +@@ -210,18 +245,21 @@ typedef struct _ExaMigrationRec { + RegionPtr pReg; + } ExaMigrationRec, *ExaMigrationPtr; + ++typedef struct { ++ INT16 xSrc; ++ INT16 ySrc; ++ INT16 xDst; ++ INT16 yDst; ++ INT16 width; ++ INT16 height; ++} ExaCompositeRectRec, *ExaCompositeRectPtr; ++ + /** + * exaDDXDriverInit must be implemented by the DDX using EXA, and is the place + * to set EXA options or hook in screen functions to handle using EXA as the AA. + */ + void exaDDXDriverInit (ScreenPtr pScreen); + +-void +-exaPrepareAccessWindow(WindowPtr pWin); +- +-void +-exaFinishAccessWindow(WindowPtr pWin); +- + /* exa_unaccel.c */ + void + exaPrepareAccessGC(GCPtr pGC); +@@ -294,13 +332,6 @@ ExaCheckGetSpans (DrawablePtr pDrawable, + int nspans, + char *pdstStart); + +-void +-ExaCheckAddTraps (PicturePtr pPicture, +- INT16 x_off, +- INT16 y_off, +- int ntrap, +- xTrap *traps); +- + /* exa_accel.c */ + + static _X_INLINE Bool +@@ -422,6 +453,13 @@ exaComposite(CARD8 op, + CARD16 height); + + void ++exaCompositeRects(CARD8 op, ++ PicturePtr Src, ++ PicturePtr pDst, ++ int nrect, ++ ExaCompositeRectPtr rects); ++ ++void + exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntrap, xTrapezoid *traps); +@@ -431,6 +469,13 @@ exaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntri, xTriangle *tris); + ++/* exa_glyph.c */ ++void ++exaGlyphsInit(ScreenPtr pScreen); ++ ++void ++exaGlyphsFini (ScreenPtr pScreen); ++ + void + exaGlyphs (CARD8 op, + PicturePtr pSrc, +@@ -449,4 +494,7 @@ exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel); + void + exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area); + ++Bool ++exaDamageDestForMigration(DrawablePtr pDrawable, PixmapPtr pPix, RegionPtr region); ++ + #endif /* EXAPRIV_H */ +diff --git a/exa/exa_render.c b/exa/exa_render.c +index 1d7b897..bafa309 100644 +--- a/exa/exa_render.c ++++ b/exa/exa_render.c +@@ -332,6 +332,228 @@ exaTryDriverSolidFill(PicturePtr pSrc, + } + + static int ++exaTryDriverCompositeRects(CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pDst, ++ int nrect, ++ ExaCompositeRectPtr rects) ++{ ++ ExaScreenPriv (pDst->pDrawable->pScreen); ++ int src_off_x, src_off_y, dst_off_x, dst_off_y; ++ PixmapPtr pSrcPix, pDstPix; ++ ExaPixmapPrivPtr pSrcExaPix, pDstExaPix; ++ struct _Pixmap scratch; ++ ExaMigrationRec pixmaps[2]; ++ ++ if (!pExaScr->info->PrepareComposite) ++ return -1; ++ ++ pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); ++ pSrcExaPix = ExaGetPixmapPriv(pSrcPix); ++ ++ pDstPix = exaGetDrawablePixmap(pDst->pDrawable); ++ pDstExaPix = ExaGetPixmapPriv(pDstPix); ++ ++ /* Check whether the accelerator can use these pixmaps. ++ * FIXME: If it cannot, use temporary pixmaps so that the drawing ++ * happens within limits. ++ */ ++ if (pSrcExaPix->accel_blocked || ++ pDstExaPix->accel_blocked) ++ { ++ return -1; ++ } ++ ++ if (pExaScr->info->CheckComposite && ++ !(*pExaScr->info->CheckComposite) (op, pSrc, NULL, pDst)) ++ { ++ return -1; ++ } ++ ++ exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); ++ ++ pixmaps[0].as_dst = TRUE; ++ pixmaps[0].as_src = exaOpReadsDestination(op); ++ pixmaps[0].pPix = pDstPix; ++ pixmaps[0].pReg = NULL; ++ pixmaps[1].as_dst = FALSE; ++ pixmaps[1].as_src = TRUE; ++ pixmaps[1].pPix = pSrcPix; ++ pixmaps[1].pReg = NULL; ++ exaDoMigration(pixmaps, 2, TRUE); ++ ++ pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); ++ if (!exaPixmapIsOffscreen(pDstPix)) ++ return 0; ++ ++ if (!pSrcPix && pExaScr->info->UploadToScratch) ++ { ++ pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable); ++ if ((*pExaScr->info->UploadToScratch) (pSrcPix, &scratch)) ++ pSrcPix = &scratch; ++ } ++ ++ if (!pSrcPix) ++ return 0; ++ ++ if (!(*pExaScr->info->PrepareComposite) (op, pSrc, NULL, pDst, pSrcPix, ++ NULL, pDstPix)) ++ return -1; ++ ++ while (nrect--) ++ { ++ INT16 xDst = rects->xDst + pDst->pDrawable->x; ++ INT16 yDst = rects->yDst + pDst->pDrawable->y; ++ INT16 xSrc = rects->xSrc + pSrc->pDrawable->x; ++ INT16 ySrc = rects->ySrc + pSrc->pDrawable->y; ++ ++ RegionRec region; ++ BoxPtr pbox; ++ int nbox; ++ ++ if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, ++ xSrc, ySrc, 0, 0, xDst, yDst, ++ rects->width, rects->height)) ++ goto next_rect; ++ ++ REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); ++ ++ nbox = REGION_NUM_RECTS(®ion); ++ pbox = REGION_RECTS(®ion); ++ ++ xSrc = xSrc + src_off_x - xDst - dst_off_x; ++ ySrc = ySrc + src_off_y - yDst - dst_off_y; ++ ++ while (nbox--) ++ { ++ (*pExaScr->info->Composite) (pDstPix, ++ pbox->x1 + xSrc, ++ pbox->y1 + ySrc, ++ 0, 0, ++ pbox->x1, ++ pbox->y1, ++ pbox->x2 - pbox->x1, ++ pbox->y2 - pbox->y1); ++ pbox++; ++ } ++ ++ next_rect: ++ REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); ++ ++ rects++; ++ } ++ ++ (*pExaScr->info->DoneComposite) (pDstPix); ++ exaMarkSync(pDst->pDrawable->pScreen); ++ ++ return 1; ++} ++ ++/** ++ * Copy a number of rectangles from source to destination in a single ++ * operation. This is specialized for building a glyph mask: we don'y ++ * have a mask argument because we don't need it for that, and we ++ * don't have he special-case fallbacks found in exaComposite() - if the ++ * driver can support it, we use the driver functionality, otherwise we ++ * fallback straight to software. ++ */ ++void ++exaCompositeRects(CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pDst, ++ int nrect, ++ ExaCompositeRectPtr rects) ++{ ++ PixmapPtr pPixmap = exaGetDrawablePixmap(pDst->pDrawable); ++ ExaPixmapPriv(pPixmap); ++ RegionRec region; ++ int n; ++ ExaCompositeRectPtr r; ++ ++ if (pExaPixmap->pDamage) { ++ int x1 = MAXSHORT; ++ int y1 = MAXSHORT; ++ int x2 = MINSHORT; ++ int y2 = MINSHORT; ++ BoxRec box; ++ ++ /* We have to manage the damage ourselves, since CompositeRects isn't ++ * something in the screen that can be managed by the damage extension, ++ * and EXA depends on damage to track what needs to be migrated between ++ * offscreen and onscreen. ++ */ ++ ++ /* Compute the overall extents of the composited region - we're making ++ * the assumption here that we are compositing a bunch of glyphs that ++ * cluster closely together and damaging each glyph individually would ++ * be a loss compared to damaging the bounding box. ++ */ ++ n = nrect; ++ r = rects; ++ while (n--) { ++ int rect_x2 = r->xDst + r->width; ++ int rect_y2 = r->yDst + r->width; ++ ++ if (r->xDst < x1) x1 = r->xDst; ++ if (r->xDst < y1) y1 = r->xDst; ++ if (rect_x2 > x2) x2 = rect_x2; ++ if (rect_y2 > y2) y2 = rect_y2; ++ ++ r++; ++ } ++ ++ if (x2 <= x1 && y2 <= y1) ++ return; ++ ++ box.x1 = x1; ++ box.x2 = x2 < MAXSHORT ? x2 : MAXSHORT; ++ box.y1 = y1; ++ box.y2 = y2 < MAXSHORT ? y2 : MAXSHORT; ++ ++ /* The pixmap migration code relies on pendingDamage indicating ++ * the bounds of the current rendering, so we need to force ++ * the actual damage into that region before we do anything, and ++ * (see use of DamagePendingRegion in exaCopyDirty) ++ */ ++ ++ REGION_INIT(pScreen, ®ion, &box, 1); ++ ++ exaDamageDestForMigration(pDst->pDrawable, pPixmap, ®ion); ++ } ++ ++ /************************************************************/ ++ ++ ValidatePicture (pSrc); ++ ValidatePicture (pDst); ++ ++ if (exaTryDriverCompositeRects(op, pSrc, pDst, nrect, rects) != 1) { ++ n = nrect; ++ r = rects; ++ while (n--) { ++ ExaCheckComposite (op, pSrc, NULL, pDst, ++ r->xSrc, r->ySrc, ++ 0, 0, ++ r->xDst, r->yDst, ++ r->width, r->height); ++ r++; ++ } ++ } ++ ++ /************************************************************/ ++ ++ if (pExaPixmap->pDamage) { ++ /* Now we have to flush the damage out from pendingDamage => damage ++ * Calling DamageDamageRegion has that effect. (We could pass ++ * in an empty region here, but we pass in the same region we ++ * use above; the effect is the same.) ++ */ ++ ++ DamageDamageRegion(pDst->pDrawable, ®ion); ++ REGION_UNINIT(pScreen, ®ion); ++ } ++} ++ ++static int + exaTryDriverComposite(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, +@@ -843,22 +1065,16 @@ exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PixmapPtr pixmap = exaGetDrawablePixmap (pDraw); + ExaPixmapPriv (pixmap); + RegionRec migration; +- RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); +- int xoff, yoff; +- +- exaGetDrawableDeltas(pDraw, pixmap, &xoff, &yoff); + +- xoff += pDraw->x; +- yoff += pDraw->y; ++ if (pExaPixmap->pDamage) { ++ bounds.x1 += pDraw->x; ++ bounds.y1 += pDraw->y; ++ bounds.x2 += pDraw->x; ++ bounds.y2 += pDraw->y; + +- bounds.x1 += xoff; +- bounds.y1 += yoff; +- bounds.x2 += xoff; +- bounds.y2 += yoff; +- +- REGION_INIT(pScreen, &migration, &bounds, 1); +- REGION_UNION(pScreen, pending_damage, pending_damage, &migration); +- REGION_UNINIT(pScreen, &migration); ++ REGION_INIT(pScreen, &migration, &bounds, 1); ++ exaDamageDestForMigration(pDraw, pixmap, &migration); ++ } + + exaPrepareAccess(pDraw, EXA_PREPARE_DEST); + +@@ -866,6 +1082,13 @@ exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + (*ps->RasterizeTrapezoid) (pDst, traps, 0, 0); + + exaFinishAccess(pDraw, EXA_PREPARE_DEST); ++ ++ /* Damage manually, because Trapezoids expects to hit Composite normally. */ ++ /* Composite is wrapped by damage, but Trapezoids isn't. */ ++ if (pExaPixmap->pDamage) { ++ DamageDamageRegion(pDraw, &migration); ++ REGION_UNINIT(pScreen, &migration); ++ } + } + else if (maskFormat) + { +@@ -946,26 +1169,27 @@ exaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PixmapPtr pixmap = exaGetDrawablePixmap (pDraw); + ExaPixmapPriv (pixmap); + RegionRec migration; +- RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); +- int xoff, yoff; +- +- exaGetDrawableDeltas(pDraw, pixmap, &xoff, &yoff); +- +- xoff += pDraw->x; +- yoff += pDraw->y; + +- bounds.x1 += xoff; +- bounds.y1 += yoff; +- bounds.x2 += xoff; +- bounds.y2 += yoff; ++ if (pExaPixmap->pDamage) { ++ bounds.x1 += pDraw->x; ++ bounds.y1 += pDraw->y; ++ bounds.x2 += pDraw->x; ++ bounds.y2 += pDraw->y; + +- REGION_INIT(pScreen, &migration, &bounds, 1); +- REGION_UNION(pScreen, pending_damage, pending_damage, &migration); +- REGION_UNINIT(pScreen, &migration); ++ REGION_INIT(pScreen, &migration, &bounds, 1); ++ exaDamageDestForMigration(pDraw, pixmap, &migration); ++ } + + exaPrepareAccess(pDraw, EXA_PREPARE_DEST); + (*ps->AddTriangles) (pDst, 0, 0, ntri, tris); + exaFinishAccess(pDraw, EXA_PREPARE_DEST); ++ ++ /* Damage manually, because Triangles expects to hit Composite normally. */ ++ /* Composite is wrapped by damage, but Triangles isn't. */ ++ if (pExaPixmap->pDamage) { ++ DamageDamageRegion(pDraw, &migration); ++ REGION_UNINIT(pScreen, &migration); ++ } + } + else if (maskFormat) + { +diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c +index d7bd06c..d5d6a30 100644 +--- a/exa/exa_unaccel.c ++++ b/exa/exa_unaccel.c +@@ -97,12 +97,15 @@ ExaCheckPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, + int x, int y, int w, int h, int leftPad, int format, + char *bits) + { ++ ExaPixmapPriv(exaGetDrawablePixmap(pDrawable)); ++ + EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); + if (exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle, + pGC->alu)) + exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); + else +- ExaDoPrepareAccess (pDrawable, EXA_PREPARE_DEST); ++ exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pExaPixmap->pDamage ? ++ DamagePendingRegion(pExaPixmap->pDamage) : NULL); + fbPutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits); + exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + } +@@ -350,20 +353,6 @@ ExaCheckComposite (CARD8 op, + REGION_UNINIT(pScreen, ®ion); + } + +-void +-ExaCheckAddTraps (PicturePtr pPicture, +- INT16 x_off, +- INT16 y_off, +- int ntrap, +- xTrap *traps) +-{ +- EXA_FALLBACK(("to pict %p (%c)\n", +- exaDrawableLocation(pPicture->pDrawable))); +- exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); +- fbAddTraps (pPicture, x_off, y_off, ntrap, traps); +- exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); +-} +- + /** + * Gets the 0,0 pixel of a pixmap. Used for doing solid fills of tiled pixmaps + * that happen to be 1x1. Pixmap must be at least 8bpp. +@@ -373,23 +362,22 @@ ExaCheckAddTraps (PicturePtr pPicture, + CARD32 + exaGetPixmapFirstPixel (PixmapPtr pPixmap) + { +- ExaScreenPriv(pPixmap->drawable.pScreen); + CARD32 pixel; + void *fb; + Bool need_finish = FALSE; + BoxRec box; + RegionRec migration; + ExaPixmapPriv (pPixmap); +- Bool sys_valid = !miPointInRegion(&pExaPixmap->validSys, 0, 0, &box); +- Bool damaged = miPointInRegion(DamageRegion(pExaPixmap->pDamage), 0, 0, +- &box); ++ Bool sys_valid = pExaPixmap->pDamage && ++ !miPointInRegion(&pExaPixmap->validSys, 0, 0, &box); ++ Bool damaged = pExaPixmap->pDamage && ++ miPointInRegion(DamageRegion(pExaPixmap->pDamage), 0, 0, &box); + Bool offscreen = exaPixmapIsOffscreen(pPixmap); + + fb = pExaPixmap->sys_ptr; + + /* Try to avoid framebuffer readbacks */ +- if (pExaScr->info->CreatePixmap || +- (!offscreen && !sys_valid && !damaged) || ++ if ((!offscreen && !sys_valid && !damaged) || + (offscreen && (!sys_valid || damaged))) + { + box.x1 = 0; +diff --git a/hw/xfree86/exa/exa.man.pre b/hw/xfree86/exa/exa.man.pre +index 14859bc..31e1cfe 100644 +--- a/hw/xfree86/exa/exa.man.pre ++++ b/hw/xfree86/exa/exa.man.pre +@@ -31,12 +31,6 @@ Disables acceleration of downloading of pixmap data from the framebuffer. + Not usable with drivers which rely on DownloadFromScreen succeeding. + Default: No. + .TP +-.BI "Option \*qEXAOptimizeMigration\*q \*q" boolean \*q +-Enables an additional optimization for migration of destination pixmaps. This +-may improve performance in some cases (e.g. when switching virtual desktops with +-no compositing manager) but causes corruption in others (e.g. when starting +-compiz). Default: No. +-.TP + .BI "Option \*qMigrationHeuristic\*q \*q" anystr \*q + Chooses an alternate pixmap migration heuristic, for debugging purposes. The + default is intended to be the best performing one for general use, though others +diff --git a/hw/xfree86/exa/examodule.c b/hw/xfree86/exa/examodule.c +index e18da0a..4a8d8f2 100644 +--- a/hw/xfree86/exa/examodule.c ++++ b/hw/xfree86/exa/examodule.c +@@ -145,7 +145,7 @@ exaDDXDriverInit(ScreenPtr pScreen) + pExaScr->optimize_migration = + xf86ReturnOptValBool(pScreenPriv->options, + EXAOPT_OPTIMIZE_MIGRATION, +- FALSE); ++ TRUE); + } + + if (xf86ReturnOptValBool(pScreenPriv->options, +@@ -179,13 +179,6 @@ exaDDXDriverInit(ScreenPtr pScreen) + + } + +-/*ARGSUSED*/ +-static const OptionInfoRec * +-EXAAvailableOptions(void *unused) +-{ +- return (EXAOptions); +-} +- + static XF86ModuleVersionInfo exaVersRec = + { + "exa",