From 453260b6405314c97884b48b8531127dc555f380 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Arkadiusz=20Mi=C5=9Bkiewicz?= Date: Wed, 2 Jul 2008 17:17:37 +0000 Subject: [PATCH] - glyph cache backported from master Changed files: xorg-xserver-server-glyph.patch -> 1.1 --- xorg-xserver-server-glyph.patch | 1888 +++++++++++++++++++++++++++++++ 1 file changed, 1888 insertions(+) create mode 100644 xorg-xserver-server-glyph.patch diff --git a/xorg-xserver-server-glyph.patch b/xorg-xserver-server-glyph.patch new file mode 100644 index 0000000..1fd07bc --- /dev/null +++ b/xorg-xserver-server-glyph.patch @@ -0,0 +1,1888 @@ +commit 54184110f6f3e5d7276d5431e739a4fcf0c3523e +Author: Owen Taylor +Date: Mon Apr 28 21:00:54 2008 +0200 + + EXA: Use a single large glyph cache pixmap + + Add back exaGlyphs(); the new version copies the glyph images + onto a single large glyph pixmap and draws from their to the + destination surface. This reduces the management of small + offscreen areas and will allow us to avoid texture unit setup + between each glyph. + +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 3a6ad98..809fb4b 100644 +--- a/exa/exa.c ++++ b/exa/exa.c +@@ -739,6 +739,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; +@@ -754,7 +754,9 @@ + #ifdef RENDER + if (ps) { + ps->Composite = pExaScr->SavedComposite; ++ ps->Glyphs = pExaScr->SavedGlyphs; + ps->Trapezoids = pExaScr->SavedTrapezoids; ++ ps->Triangles = pExaScr->SavedTriangles; + ps->AddTraps = pExaScr->SavedAddTraps; + } + #endif +@@ -914,6 +918,9 @@ exaDriverInit (ScreenPtr pScreen, + pExaScr->SavedComposite = ps->Composite; + ps->Composite = exaComposite; + ++ pExaScr->SavedGlyphs = ps->Glyphs; ++ ps->Glyphs = exaGlyphs; ++ + pExaScr->SavedTriangles = ps->Triangles; + ps->Triangles = exaTriangles; + +@@ -973,6 +980,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_glyphs.c b/exa/exa_glyphs.c +new file mode 100644 +index 0000000..3fe433a +--- /dev/null ++++ b/exa/exa_glyphs.c +@@ -0,0 +1,745 @@ ++/* ++ * 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 ++ ++/* Instructions for rendering a single glyph */ ++typedef struct { ++ INT16 xSrc; ++ INT16 ySrc; ++ INT16 xDst; ++ INT16 yDst; ++ INT16 width; ++ INT16 height; ++} ExaGlyphRenderRec, *ExaGlyphRenderPtr; ++ ++/* 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; ++ ExaGlyphRenderRec glyphs[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; ++ ++ 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){ ++ DBG_GLYPH_CACHE((" found entry at %d\n", slot)); ++ return entryPos; ++ } ++ ++ DBG_GLYPH_CACHE((" lookup linear probe bumpalong\n")); ++ 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) { ++ DBG_GLYPH_CACHE((" inserting entry at %d\n", slot)); ++ 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; ++ } ++} ++ ++static ExaGlyphCacheResult ++exaGlyphCacheBufferGlyph(ScreenPtr pScreen, ++ ExaGlyphCachePtr cache, ++ ExaGlyphBufferPtr buffer, ++ GlyphPtr pGlyph, ++ int xGlyph, ++ int yGlyph) ++{ ++ ExaGlyphRenderPtr glyphRec; ++ 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 = (pos % cache->columns) * cache->glyphWidth; ++ y = (pos / cache->columns) * cache->glyphHeight; ++ ++ for (i = 0; i < buffer->count; i++) { ++ if (buffer->glyphs[i].xSrc == x && buffer->glyphs[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 */ ++ ++ CompositePicture (PictOpSrc, ++ GlyphPicture(pGlyph)[pScreen->myNum], ++ None, ++ cache->picture, ++ 0, 0, ++ 0, 0, ++ (pos % cache->columns) * cache->glyphWidth, ++ (pos / cache->columns) * cache->glyphHeight, ++ pGlyph->info.width, ++ pGlyph->info.height); ++ } ++ ++ ++ buffer->source = cache->picture; ++ ++ glyphRec = &buffer->glyphs[buffer->count]; ++ glyphRec->xSrc = (pos % cache->columns) * cache->glyphWidth; ++ glyphRec->ySrc = (pos / cache->columns) * cache->glyphHeight; ++ glyphRec->xDst = xGlyph - pGlyph->info.x; ++ glyphRec->yDst = yGlyph - pGlyph->info.y; ++ glyphRec->width = pGlyph->info.width; ++ glyphRec->height = pGlyph->info.height; ++ ++ buffer->count++; ++ ++ return ExaGlyphSuccess; ++} ++ ++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.width; ++ ExaGlyphRenderPtr glyphRec; ++ PicturePtr source; ++ int i; ++ ++ if (buffer->count == GLYPH_BUFFER_SIZE) ++ return ExaGlyphNeedFlush; ++ ++ 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; ++ ++ glyphRec = &buffer->glyphs[buffer->count]; ++ glyphRec->xSrc = 0; ++ glyphRec->ySrc = 0; ++ glyphRec->xDst = xGlyph - pGlyph->info.x; ++ glyphRec->yDst = yGlyph - pGlyph->info.y; ++ glyphRec->width = pGlyph->info.width; ++ glyphRec->height = pGlyph->info.height; ++ ++ buffer->count++; ++ ++ return ExaGlyphSuccess; ++} ++ ++static void ++exaGlyphsToMask(PicturePtr pMask, ++ ExaGlyphBufferPtr buffer) ++{ ++ int i; ++ ++ for (i = 0; i < buffer->count; i++) { ++ ExaGlyphRenderPtr glyphRec = &buffer->glyphs[i]; ++ ++ CompositePicture (PictOpAdd, ++ buffer->source, ++ None, ++ pMask, ++ glyphRec->xSrc, ++ glyphRec->ySrc, ++ 0, 0, ++ glyphRec->xDst, ++ glyphRec->yDst, ++ glyphRec->width, ++ glyphRec->height); ++ } ++ ++ 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++) { ++ ExaGlyphRenderPtr glyphRec = &buffer->glyphs[i]; ++ ++ CompositePicture (op, ++ pSrc, ++ buffer->source, ++ pDst, ++ xSrc + glyphRec->xDst - xDst, ++ ySrc + glyphRec->yDst - yDst, ++ glyphRec->xSrc, ++ glyphRec->ySrc, ++ glyphRec->xDst, ++ glyphRec->yDst, ++ glyphRec->width, ++ glyphRec->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; ++ } ++ } ++} ++ ++#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 (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; ++ 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 (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_priv.h b/exa/exa_priv.h +index 0138e4a..aaceeb8 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,37 @@ 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 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; +@@ -122,6 +154,8 @@ typedef struct { + unsigned disableFbCount; + Bool optimize_migration; + unsigned offScreenCounter; ++ ++ ExaGlyphCacheRec glyphCaches[EXA_NUM_GLYPH_CACHES]; + } ExaScreenPrivRec, *ExaScreenPrivPtr; + + /* +@@ -432,6 +466,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, +commit 40eb14c9482457969e0bde97c49edad536285e02 +Author: Owen Taylor +Date: Mon Apr 28 21:00:54 2008 +0200 + + EXA: Add exaCompositeRects() + + Add a function to composite multiple independent rectangles + from the same source to the same destination in a single + operation: this is useful for building a glyph mask. + +diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c +index 3fe433a..55fdb01 100644 +--- a/exa/exa_glyphs.c ++++ b/exa/exa_glyphs.c +@@ -56,16 +56,6 @@ + #define DBG_GLYPH_CACHE(a) + #endif + +-/* Instructions for rendering a single glyph */ +-typedef struct { +- INT16 xSrc; +- INT16 ySrc; +- INT16 xDst; +- INT16 yDst; +- INT16 width; +- INT16 height; +-} ExaGlyphRenderRec, *ExaGlyphRenderPtr; +- + /* 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. +@@ -79,7 +69,7 @@ typedef struct { + + typedef struct { + PicturePtr source; +- ExaGlyphRenderRec glyphs[GLYPH_BUFFER_SIZE]; ++ ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE]; + int count; + } ExaGlyphBuffer, *ExaGlyphBufferPtr; + +@@ -364,7 +354,7 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen, + int xGlyph, + int yGlyph) + { +- ExaGlyphRenderPtr glyphRec; ++ ExaCompositeRectPtr rect; + int pos; + + if (buffer->source && buffer->source != cache->picture) +@@ -407,7 +397,7 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen, + y = (pos / cache->columns) * cache->glyphHeight; + + for (i = 0; i < buffer->count; i++) { +- if (buffer->glyphs[i].xSrc == x && buffer->glyphs[i].ySrc == y) { ++ if (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y) { + DBG_GLYPH_CACHE((" must flush buffer\n")); + return ExaGlyphNeedFlush; + } +@@ -439,13 +429,13 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen, + + buffer->source = cache->picture; + +- glyphRec = &buffer->glyphs[buffer->count]; +- glyphRec->xSrc = (pos % cache->columns) * cache->glyphWidth; +- glyphRec->ySrc = (pos / cache->columns) * cache->glyphHeight; +- glyphRec->xDst = xGlyph - pGlyph->info.x; +- glyphRec->yDst = yGlyph - pGlyph->info.y; +- glyphRec->width = pGlyph->info.width; +- glyphRec->height = pGlyph->info.height; ++ rect = &buffer->rects[buffer->count]; ++ rect->xSrc = (pos % cache->columns) * cache->glyphWidth; ++ rect->ySrc = (pos / cache->columns) * cache->glyphHeight; ++ rect->xDst = xGlyph - pGlyph->info.x; ++ rect->yDst = yGlyph - pGlyph->info.y; ++ rect->width = pGlyph->info.width; ++ rect->height = pGlyph->info.height; + + buffer->count++; + +@@ -463,7 +453,7 @@ exaBufferGlyph(ScreenPtr pScreen, + unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format; + int width = pGlyph->info.width; + int height = pGlyph->info.width; +- ExaGlyphRenderPtr glyphRec; ++ ExaCompositeRectPtr rect; + PicturePtr source; + int i; + +@@ -497,13 +487,13 @@ exaBufferGlyph(ScreenPtr pScreen, + + buffer->source = source; + +- glyphRec = &buffer->glyphs[buffer->count]; +- glyphRec->xSrc = 0; +- glyphRec->ySrc = 0; +- glyphRec->xDst = xGlyph - pGlyph->info.x; +- glyphRec->yDst = yGlyph - pGlyph->info.y; +- glyphRec->width = pGlyph->info.width; +- glyphRec->height = pGlyph->info.height; ++ 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++; + +@@ -514,23 +504,8 @@ static void + exaGlyphsToMask(PicturePtr pMask, + ExaGlyphBufferPtr buffer) + { +- int i; +- +- for (i = 0; i < buffer->count; i++) { +- ExaGlyphRenderPtr glyphRec = &buffer->glyphs[i]; +- +- CompositePicture (PictOpAdd, +- buffer->source, +- None, +- pMask, +- glyphRec->xSrc, +- glyphRec->ySrc, +- 0, 0, +- glyphRec->xDst, +- glyphRec->yDst, +- glyphRec->width, +- glyphRec->height); +- } ++ exaCompositeRects(PictOpAdd, buffer->source, pMask, ++ buffer->count, buffer->rects); + + buffer->count = 0; + buffer->source = NULL; +@@ -549,20 +524,20 @@ exaGlyphsToDst(CARD8 op, + int i; + + for (i = 0; i < buffer->count; i++) { +- ExaGlyphRenderPtr glyphRec = &buffer->glyphs[i]; ++ ExaCompositeRectPtr rect = &buffer->rects[i]; + + CompositePicture (op, + pSrc, + buffer->source, + pDst, +- xSrc + glyphRec->xDst - xDst, +- ySrc + glyphRec->yDst - yDst, +- glyphRec->xSrc, +- glyphRec->ySrc, +- glyphRec->xDst, +- glyphRec->yDst, +- glyphRec->width, +- glyphRec->height); ++ xSrc + rect->xDst - xDst, ++ ySrc + rect->yDst - yDst, ++ rect->xSrc, ++ rect->ySrc, ++ rect->xDst, ++ rect->yDst, ++ rect->width, ++ rect->height); + } + + buffer->count = 0; +diff --git a/exa/exa_priv.h b/exa/exa_priv.h +index aaceeb8..0d5d0f5 100644 +--- a/exa/exa_priv.h ++++ b/exa/exa_priv.h +@@ -243,6 +243,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. +@@ -457,6 +466,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); +diff --git a/exa/exa_render.c b/exa/exa_render.c +index 1d7b897..43b0029 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]; ++ ++ 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); ++ ++ int xoff, yoff; ++ int x1 = MAXSHORT; ++ int y1 = MAXSHORT; ++ int x2 = MINSHORT; ++ int y2 = MINSHORT; ++ RegionRec region; ++ RegionPtr pending_damage; ++ BoxRec box; ++ int n; ++ ExaCompositeRectPtr r; ++ ++ /* 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++; ++ } ++ } ++ ++ /************************************************************/ ++ ++ /* 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, +commit fcb5949928f1c27f67f40c094c3c673786574422 +Author: Owen Taylor +Date: Mon Apr 28 21:00:54 2008 +0200 + + EXA: Fix overlapping glyphs in glyph cache + + Allocate each cache at a different vertical position in the + per-format pixmap. Fix width/height confusion when choosing + the cache for a glyph. + +diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c +index 55fdb01..851e439 100644 +--- a/exa/exa_glyphs.c ++++ b/exa/exa_glyphs.c +@@ -173,12 +173,13 @@ exaRealizeGlyphCaches(ScreenPtr pScreen, + for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { + ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; + int rows; +- ++ + if (cache->format != format) + continue; + +- rows = (cache->size + cache->columns - 1) / cache->columns; ++ cache->yOffset = height; + ++ rows = (cache->size + cache->columns - 1) / cache->columns; + height += rows * cache->glyphHeight; + } + +@@ -346,6 +347,9 @@ exaGlyphCacheHashRemove(ExaGlyphCachePtr cache, + } + } + ++#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth) ++#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight) ++ + static ExaGlyphCacheResult + exaGlyphCacheBufferGlyph(ScreenPtr pScreen, + ExaGlyphCachePtr cache, +@@ -393,8 +397,8 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen, + int x, y; + int i; + +- x = (pos % cache->columns) * cache->glyphWidth; +- y = (pos / cache->columns) * cache->glyphHeight; ++ 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) { +@@ -420,8 +424,8 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen, + cache->picture, + 0, 0, + 0, 0, +- (pos % cache->columns) * cache->glyphWidth, +- (pos / cache->columns) * cache->glyphHeight, ++ CACHE_X(pos), ++ CACHE_Y(pos), + pGlyph->info.width, + pGlyph->info.height); + } +@@ -430,8 +434,8 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen, + buffer->source = cache->picture; + + rect = &buffer->rects[buffer->count]; +- rect->xSrc = (pos % cache->columns) * cache->glyphWidth; +- rect->ySrc = (pos / cache->columns) * cache->glyphHeight; ++ 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; +@@ -442,6 +446,9 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen, + return ExaGlyphSuccess; + } + ++#undef CACHE_X ++#undef CACHE_Y ++ + static ExaGlyphCacheResult + exaBufferGlyph(ScreenPtr pScreen, + ExaGlyphBufferPtr buffer, +@@ -452,7 +459,7 @@ exaBufferGlyph(ScreenPtr pScreen, + ExaScreenPriv(pScreen); + unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format; + int width = pGlyph->info.width; +- int height = pGlyph->info.width; ++ int height = pGlyph->info.height; + ExaCompositeRectPtr rect; + PicturePtr source; + int i; +diff --git a/exa/exa_priv.h b/exa/exa_priv.h +index 0d5d0f5..8a17f65 100644 +--- a/exa/exa_priv.h ++++ b/exa/exa_priv.h +@@ -61,7 +61,7 @@ + #define DEBUG_MIGRATE 0 + #define DEBUG_PIXMAP 0 + #define DEBUG_OFFSCREEN 0 +-#define DEBUG_GLYPH_CACHE 0 ++#define DEBUG_GLYPH_CACHE 1 + + #if DEBUG_TRACE_FALL + #define EXA_FALLBACK(x) \ +@@ -121,6 +121,7 @@ typedef struct { + 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; +commit cc08c06665ffe29ad44d023d75d0f86e5338875d +Author: Owen Taylor +Date: Mon Apr 28 21:00:55 2008 +0200 + + EXA: Use UploadToScreen() for uploads to glyph cache + + When possible, use UploadToScreen() rather than CompositePicture() + to upload glyphs onto the glyph cache pixmap. This avoids allocating + offscreen memory for each glyph making management of offscreen + areas much more efficient. + +diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c +index 27ecd4a..95ff4d8 100644 +--- a/exa/exa_glyphs.c ++++ b/exa/exa_glyphs.c +@@ -347,6 +347,56 @@ exaGlyphCacheHashRemove(ExaGlyphCachePtr cache, + #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]; ++ int cacheXoff, cacheYoff; ++ ++ 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; ++ ++ /* 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); ++ ++ pCachePixmap = exaGetOffscreenPixmap ((DrawablePtr)pCachePixmap, &cacheXoff, &cacheYoff); ++ if (!pCachePixmap) ++ return FALSE; ++ ++ if (!pExaScr->info->UploadToScreen(pCachePixmap, ++ CACHE_X(pos) + cacheXoff, ++ CACHE_Y(pos) + cacheYoff, ++ pGlyph->info.width, ++ pGlyph->info.height, ++ (char *)pExaPixmap->sys_ptr, ++ pExaPixmap->sys_pitch)) ++ return FALSE; ++ ++ return TRUE; ++} ++ + static ExaGlyphCacheResult + exaGlyphCacheBufferGlyph(ScreenPtr pScreen, + ExaGlyphCachePtr cache, +@@ -413,18 +463,23 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen, + cache->evictionPosition = rand() % cache->size; + } + +- /* Now actually upload the glyph into the cache picture */ ++ /* 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); ++ } + +- 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); + } + + +commit e7eaac59c424a205dd106fc7d70734ff4b390f28 +Author: Michel Dänzer +Date: Mon Apr 28 21:00:55 2008 +0200 + + EXA: Glyph cache upload tweaks. + + Track damage after using UploadToScreen directly. + + Don't waste any effort on empty glyphs. + +diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c +index 95ff4d8..b618365 100644 +--- a/exa/exa_glyphs.c ++++ b/exa/exa_glyphs.c +@@ -394,6 +394,12 @@ exaGlyphCacheUploadGlyph(ScreenPtr pScreen, + pExaPixmap->sys_pitch)) + return FALSE; + ++ exaPixmapDirty (pCachePixmap, ++ CACHE_X(pos) + cacheXoff, ++ CACHE_Y(pos) + cacheYoff, ++ CACHE_X(pos) + cacheXoff + pGlyph->info.width, ++ CACHE_Y(pos) + cacheYoff + pGlyph->info.height); ++ + return TRUE; + } + +@@ -737,7 +743,8 @@ exaGlyphs (CARD8 op, + glyph = *glyphs++; + pPicture = GlyphPicture (glyph)[pScreen->myNum]; + +- if (exaBufferGlyph(pScreen, &buffer, glyph, x, y) == ExaGlyphNeedFlush) ++ if (glyph->info.width > 0 && glyph->info.height > 0 && ++ exaBufferGlyph(pScreen, &buffer, glyph, x, y) == ExaGlyphNeedFlush) + { + if (maskFormat) + exaGlyphsToMask(pMask, &buffer); +commit 8349732a6720652bfbad7874a952be73a0e8e77b +Author: Michel Dänzer +Date: Mon Apr 28 21:09:35 2008 +0200 + + EXA: Try to accelerate non-antialiased text via the glyph cache as well. + + Treat 1 bit glyphs and masks as PICT_a8 in the glyph cache. We're not able to + accelerate them otherwise. + +diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c +index 08ec097..ff665d5 100644 +--- a/exa/exa_glyphs.c ++++ b/exa/exa_glyphs.c +@@ -374,6 +374,10 @@ exaGlyphCacheUploadGlyph(ScreenPtr pScreen, + 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; +@@ -524,6 +528,9 @@ exaBufferGlyph(ScreenPtr pScreen, + + 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]; +@@ -796,6 +803,14 @@ exaGlyphs (CARD8 op, + 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); + +commit 29586101dc11d498b212510f8dedbfeca7f8c859 +Author: Michel Dänzer +Date: Sat May 24 20:01:41 2008 +0200 + + EXA: Only record damage generated by rendering operations. + + Recording damage from other operations (e.g. creating a client damage record) + may confuse the migration code resulting in corruption. + + Option "EXAOptimizeMigration" appears safe now, so enable it by default. Also + remove it from the manpage, as it should only be necessary on request in the + course of bug report diagnostics anymore. + +diff --git a/exa/exa.c b/exa/exa.c +index 809fb4b..fc04748 100644 +--- a/exa/exa.c ++++ b/exa/exa.c +@@ -261,6 +261,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. + * +@@ -352,7 +367,7 @@ exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth, + pExaPixmap->area = NULL; + + /* Set up damage tracking */ +- pExaPixmap->pDamage = DamageCreate (NULL, NULL, DamageReportNone, TRUE, ++ pExaPixmap->pDamage = DamageCreate (ExaDamageReport, NULL, DamageReportRawRegion, TRUE, + pScreen, pPixmap); + + if (pExaPixmap->pDamage == NULL) { +diff --git a/exa/exa_accel.c b/exa/exa_accel.c +index edaec23..1dbb269 100644 +--- a/exa/exa_accel.c ++++ b/exa/exa_accel.c +@@ -262,6 +262,7 @@ exaDoShmPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, + if (format == ZPixmap) + { + PixmapPtr pPixmap; ++ ExaPixmapPriv(exaGetDrawablePixmap(pDrawable)); + + pPixmap = GetScratchPixmapHeader(pDrawable->pScreen, w, h, depth, + BitsPerPixel(depth), PixmapBytePad(w, depth), (pointer)data); +@@ -272,7 +273,8 @@ exaDoShmPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, + pGC->alu)) + exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); + else +- ExaDoPrepareAccess (pDrawable, EXA_PREPARE_DEST); ++ exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, ++ DamagePendingRegion(pExaPixmap->pDamage)); + fbCopyArea((DrawablePtr)pPixmap, pDrawable, pGC, sx, sy, sw, sh, dx, dy); + exaFinishAccess(pDrawable, EXA_PREPARE_DEST); + +@@ -316,7 +318,7 @@ 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); +diff --git a/exa/exa_migration.c b/exa/exa_migration.c +index 5f22474..3c79f68 100644 +--- a/exa/exa_migration.c ++++ b/exa/exa_migration.c +@@ -301,6 +301,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 +372,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 f3b72ae..9ec2a56 100644 +--- a/exa/exa_priv.h ++++ b/exa/exa_priv.h +@@ -226,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. +diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c +index c55ef03..5a25764 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, ++ DamagePendingRegion(pExaPixmap->pDamage)); + fbPutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits); + exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + } +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..63ea8c5 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, +commit 528b4e36ade482df99747081688ae52cfaeb28eb +Author: Alan Hourihane +Date: Wed Jun 18 22:34:02 2008 +0100 + + Set driverPriv immediately on CreatePixmap. + + If it's NULL anyway, we bail, if not, it lets + ModifyPixmapHeader know about the private. + +diff --git a/exa/exa.c b/exa/exa.c +index fc04748..48352bd 100644 +--- a/exa/exa.c ++++ b/exa/exa.c +@@ -314,7 +314,6 @@ exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth, + + if (driver_alloc) { + size_t paddedWidth, datasize; +- void *driver_priv; + + paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); + if (paddedWidth / 4 > 32767 || h > 32767) +@@ -327,22 +326,21 @@ exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth, + + datasize = h * paddedWidth; + +- driver_priv = pExaScr->info->CreatePixmap(pScreen, datasize, 0); +- if (!driver_priv) { ++ pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, datasize, 0); ++ if (!pExaPixmap->driverPriv) { + fbDestroyPixmap(pPixmap); + return NULL; + } + + (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0, + paddedWidth, NULL); +- pExaPixmap->driverPriv = driver_priv; + pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; + pExaPixmap->fb_ptr = NULL; + } else { +- pExaPixmap->driverPriv = NULL; +- /* Scratch pixmaps may have w/h equal to zero, and may not be +- * migrated. +- */ ++ pExaPixmap->driverPriv = NULL; ++ /* Scratch pixmaps may have w/h equal to zero, and may not be ++ * migrated. ++ */ + if (!w || !h) + pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; + else +commit 13fd2256300b61d88b840952d838f834523f5dd7 +Author: Owen Taylor +Date: Mon Apr 28 21:00:55 2008 +0200 + + EXA: Clean up debug messages + +diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c +index 851e439..27ecd4a 100644 +--- a/exa/exa_glyphs.c ++++ b/exa/exa_glyphs.c +@@ -260,11 +260,9 @@ exaGlyphCacheHashLookup(ExaGlyphCachePtr cache, + return -1; + + if (memcmp(pGlyph->sha1, cache->glyphs[entryPos].sha1, sizeof(pGlyph->sha1)) == 0){ +- DBG_GLYPH_CACHE((" found entry at %d\n", slot)); + return entryPos; + } + +- DBG_GLYPH_CACHE((" lookup linear probe bumpalong\n")); + slot--; + if (slot < 0) + slot = cache->hashSize - 1; +@@ -284,7 +282,6 @@ exaGlyphCacheHashInsert(ExaGlyphCachePtr cache, + + while (TRUE) { /* hash table can never be full */ + if (cache->hashEntries[slot] == -1) { +- DBG_GLYPH_CACHE((" inserting entry at %d\n", slot)); + cache->hashEntries[slot] = pos; + return; + } +diff --git a/exa/exa_priv.h b/exa/exa_priv.h +index 8a17f65..f3b72ae 100644 +--- a/exa/exa_priv.h ++++ b/exa/exa_priv.h +@@ -61,7 +61,7 @@ + #define DEBUG_MIGRATE 0 + #define DEBUG_PIXMAP 0 + #define DEBUG_OFFSCREEN 0 +-#define DEBUG_GLYPH_CACHE 1 ++#define DEBUG_GLYPH_CACHE 0 + + #if DEBUG_TRACE_FALL + #define EXA_FALLBACK(x) \ -- 2.44.0