diff --git a/xorg-x11-server.spec b/xorg-x11-server.spec index 2bd14f0..3b0c202 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.4.99.906 -Release: 6%{?dist} +Release: 7%{?dist} URL: http://www.x.org License: MIT Group: User Interface/X @@ -42,6 +42,7 @@ Source11: fedora-setup-keyboard # OpenGL compositing manager feature/optimization patches. Patch100: xorg-x11-server-1.1.0-no-move-damage.patch Patch101: xserver-1.4.99-dont-backfill-bg-none.patch +Patch102: xserver-1.4.99-exa-master-upgrade.patch # Red Hat specific tweaking, not intended for upstream # XXX move these to the end of the list @@ -492,6 +493,9 @@ rm -rf $RPM_BUILD_ROOT %changelog +* Thu Aug 14 2008 Dave Airlie 1.4.99.906-7 +- EXA backport master EXA code for optimisations + * Wed Aug 13 2008 Adam Jackson 1.4.99.906-6 - xserver-1.5.0-enable-selinux.patch: Enable selinux again. diff --git a/xserver-1.4.99-exa-master-upgrade.patch b/xserver-1.4.99-exa-master-upgrade.patch new file mode 100644 index 0000000..24c5a7f --- /dev/null +++ b/xserver-1.4.99-exa-master-upgrade.patch @@ -0,0 +1,1031 @@ +From 904e9e77cba4dd64607da7cae983a8b49e175601 Mon Sep 17 00:00:00 2001 +From: Fedora X Ninjas +Date: Thu, 14 Aug 2008 18:45:46 +1000 +Subject: [PATCH] exa: update to exa from master - adds font caching + +--- + exa/Makefile.am | 1 + + exa/exa.c | 58 +++++++---- + exa/exa_accel.c | 185 ++++++++++++++++++++++++--------- + exa/exa_migration.c | 8 +- + exa/exa_priv.h | 67 +++++++++++-- + exa/exa_render.c | 287 ++++++++++++++++++++++++++++++++++++++++++++++----- + exa/exa_unaccel.c | 30 ++---- + 7 files changed, 508 insertions(+), 128 deletions(-) + +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 4bd3d81..c276d9a 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); +@@ -737,6 +752,8 @@ exaCloseScreen(int i, ScreenPtr pScreen) + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); + #endif + ++ exaGlyphsFini(pScreen); ++ + pScreen->CreateGC = pExaScr->SavedCreateGC; + pScreen->CloseScreen = pExaScr->SavedCloseScreen; + pScreen->GetImage = pExaScr->SavedGetImage; +@@ -750,8 +767,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 +931,14 @@ exaDriverInit (ScreenPtr pScreen, + pExaScr->SavedComposite = ps->Composite; + ps->Composite = exaComposite; + ++ 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 + +@@ -975,6 +993,8 @@ exaDriverInit (ScreenPtr pScreen, + } + } + ++ 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_accel.c b/exa/exa_accel.c +index d66dd47..8ac21b8 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); + +@@ -261,20 +265,16 @@ exaDoShmPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, + + if (format == ZPixmap) + { +- PixmapPtr pPixmap; ++ PixmapPtr pPixmap = ++ GetScratchPixmapHeader(pDrawable->pScreen, w, h, depth, ++ BitsPerPixel(depth), PixmapBytePad(w, depth), ++ (pointer)data); + +- pPixmap = GetScratchPixmapHeader(pDrawable->pScreen, w, h, depth, +- BitsPerPixel(depth), PixmapBytePad(w, depth), (pointer)data); + if (!pPixmap) + return FALSE; + +- if (exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle, +- pGC->alu)) +- exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); +- else +- ExaDoPrepareAccess (pDrawable, EXA_PREPARE_DEST); +- fbCopyArea((DrawablePtr)pPixmap, pDrawable, pGC, sx, sy, sw, sh, dx, dy); +- exaFinishAccess(pDrawable, EXA_PREPARE_DEST); ++ pGC->ops->CopyArea(&pPixmap->drawable, pDrawable, pGC, sx, sy, sw, sh, ++ dx, dy); + + FreeScratchPixmapHeader(pPixmap); + +@@ -301,14 +301,19 @@ exaShmPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, unsigned int format, + .x2 = pDrawable->x + dx + sw, .y2 = pDrawable->y + dy + sh }; + RegionRec region; + int xoff, yoff; +- RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); ++ RegionPtr pending_damage = NULL; + +- REGION_INIT(pScreen, ®ion, &box, 1); ++ if (pExaPixmap->pDamage) ++ pending_damage = DamagePendingRegion(pExaPixmap->pDamage); + +- exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); ++ if (pending_damage) { ++ REGION_INIT(pScreen, ®ion, &box, 1); + +- REGION_TRANSLATE(pScreen, ®ion, xoff, yoff); +- REGION_UNION(pScreen, pending_damage, pending_damage, ®ion); ++ exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); ++ ++ REGION_TRANSLATE(pScreen, ®ion, xoff, yoff); ++ REGION_UNION(pScreen, pending_damage, pending_damage, ®ion); ++ } + + if (!exaDoShmPutImage(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh, + dx, dy, data)) { +@@ -316,16 +321,18 @@ exaShmPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, unsigned int format, + pGC->alu)) + exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); + else +- ExaDoPrepareAccess (pDrawable, EXA_PREPARE_DEST); ++ exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, ®ion); + fbShmPutImage(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, + data); + exaFinishAccess(pDrawable, EXA_PREPARE_DEST); + } + +- REGION_TRANSLATE(pScreen, ®ion, -xoff, -yoff); +- DamageDamageRegion(pDrawable, ®ion); ++ if (pending_damage) { ++ REGION_TRANSLATE(pScreen, ®ion, -xoff, -yoff); ++ DamageDamageRegion(pDrawable, ®ion); + +- REGION_UNINIT(pScreen, ®ion); ++ REGION_UNINIT(pScreen, ®ion); ++ } + } + + ShmFuncs exaShmFuncs = { NULL, exaShmPutImage }; +@@ -533,16 +540,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) { +@@ -952,16 +979,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); + +- depthMask = FbFullMask(pDrawable->depth); ++ if (pending_damage) { ++ extents = *REGION_EXTENTS(pScreen, pending_damage); ++ ++ if (extents.x1 >= extents.x2 || extents.y1 >= extents.y2) ++ return; + +- if ((pGC->planemask & depthMask) != depthMask) ++ depthMask = FbFullMask(pDrawable->depth); ++ } ++ ++ if (!pending_damage || (pGC->planemask & depthMask) != depthMask) + { + ExaCheckImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppciInit, pglyphBase); + return; +@@ -1195,6 +1229,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; +@@ -1217,14 +1252,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); + } +@@ -1232,24 +1264,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; +@@ -1271,17 +1312,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_migration.c b/exa/exa_migration.c +index 5f22474..25ea73d 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" + +@@ -301,6 +299,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 +370,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 21e6f0b..9ec2a56 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,6 +245,15 @@ 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. +@@ -294,13 +338,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 +@@ -431,6 +468,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); +@@ -440,6 +484,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, +diff --git a/exa/exa_render.c b/exa/exa_render.c +index 1d7b897..7042285 100644 +--- a/exa/exa_render.c ++++ b/exa/exa_render.c +@@ -332,6 +332,235 @@ 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 xoff, yoff; ++ int x1 = MAXSHORT; ++ int y1 = MAXSHORT; ++ int x2 = MINSHORT; ++ int y2 = MINSHORT; ++ RegionPtr pending_damage; ++ 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); ++ ++ exaGetDrawableDeltas(pDst->pDrawable, pPixmap, &xoff, &yoff); ++ ++ REGION_TRANSLATE(pScreen, ®ion, xoff, yoff); ++ pending_damage = DamagePendingRegion(pExaPixmap->pDamage); ++ REGION_UNION(pScreen, pending_damage, pending_damage, ®ion); ++ REGION_TRANSLATE(pScreen, ®ion, -xoff, -yoff); ++ } ++ ++ /************************************************************/ ++ ++ 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, +@@ -842,23 +1071,26 @@ exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + DrawablePtr pDraw = pDst->pDrawable; + PixmapPtr pixmap = exaGetDrawablePixmap (pDraw); + ExaPixmapPriv (pixmap); +- RegionRec migration; +- RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); +- int xoff, yoff; + +- exaGetDrawableDeltas(pDraw, pixmap, &xoff, &yoff); ++ if (pExaPixmap->pDamage) { ++ RegionRec migration; ++ RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); ++ int xoff, yoff; ++ ++ exaGetDrawableDeltas(pDraw, pixmap, &xoff, &yoff); + +- xoff += pDraw->x; +- yoff += pDraw->y; ++ xoff += pDraw->x; ++ yoff += pDraw->y; + +- bounds.x1 += xoff; +- bounds.y1 += yoff; +- bounds.x2 += xoff; +- bounds.y2 += yoff; ++ 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); ++ REGION_UNION(pScreen, pending_damage, pending_damage, &migration); ++ REGION_UNINIT(pScreen, &migration); ++ } + + exaPrepareAccess(pDraw, EXA_PREPARE_DEST); + +@@ -945,23 +1177,26 @@ exaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + DrawablePtr pDraw = pDst->pDrawable; + PixmapPtr pixmap = exaGetDrawablePixmap (pDraw); + ExaPixmapPriv (pixmap); +- RegionRec migration; +- RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); +- int xoff, yoff; + +- exaGetDrawableDeltas(pDraw, pixmap, &xoff, &yoff); ++ if (pExaPixmap->pDamage) { ++ RegionRec migration; ++ RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); ++ int xoff, yoff; ++ ++ exaGetDrawableDeltas(pDraw, pixmap, &xoff, &yoff); + +- xoff += pDraw->x; +- yoff += pDraw->y; ++ xoff += pDraw->x; ++ yoff += pDraw->y; + +- bounds.x1 += xoff; +- bounds.y1 += yoff; +- bounds.x2 += xoff; +- bounds.y2 += yoff; ++ 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); ++ REGION_UNION(pScreen, pending_damage, pending_damage, &migration); ++ REGION_UNINIT(pScreen, &migration); ++ } + + exaPrepareAccess(pDraw, EXA_PREPARE_DEST); + (*ps->AddTriangles) (pDst, 0, 0, ntri, tris); +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; +-- +1.5.4.1 +