xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

exa_glyphs.c (26933B)


      1 /*
      2  * Copyright © 2008 Red Hat, Inc.
      3  * Partly based on code Copyright © 2000 SuSE, Inc.
      4  *
      5  * Permission to use, copy, modify, distribute, and sell this software and its
      6  * documentation for any purpose is hereby granted without fee, provided that
      7  * the above copyright notice appear in all copies and that both that
      8  * copyright notice and this permission notice appear in supporting
      9  * documentation, and that the name of Red Hat not be used in advertising or
     10  * publicity pertaining to distribution of the software without specific,
     11  * written prior permission.  Red Hat makes no representations about the
     12  * suitability of this software for any purpose.  It is provided "as is"
     13  * without express or implied warranty.
     14  *
     15  * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat
     17  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     18  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
     19  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     20  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     21  *
     22  * Permission to use, copy, modify, distribute, and sell this software and its
     23  * documentation for any purpose is hereby granted without fee, provided that
     24  * the above copyright notice appear in all copies and that both that
     25  * copyright notice and this permission notice appear in supporting
     26  * documentation, and that the name of SuSE not be used in advertising or
     27  * publicity pertaining to distribution of the software without specific,
     28  * written prior permission.  SuSE makes no representations about the
     29  * suitability of this software for any purpose.  It is provided "as is"
     30  * without express or implied warranty.
     31  *
     32  * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
     33  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
     34  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     35  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
     36  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     37  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     38  *
     39  * Author: Owen Taylor <otaylor@fishsoup.net>
     40  * Based on code by: Keith Packard
     41  */
     42 
     43 #ifdef HAVE_DIX_CONFIG_H
     44 #include <dix-config.h>
     45 #endif
     46 
     47 #include <stdlib.h>
     48 
     49 #include "exa_priv.h"
     50 
     51 #include "mipict.h"
     52 
     53 #if DEBUG_GLYPH_CACHE
     54 #define DBG_GLYPH_CACHE(a) ErrorF a
     55 #else
     56 #define DBG_GLYPH_CACHE(a)
     57 #endif
     58 
     59 /* Width of the pixmaps we use for the caches; this should be less than
     60  * max texture size of the driver; this may need to actually come from
     61  * the driver.
     62  */
     63 #define CACHE_PICTURE_WIDTH 1024
     64 
     65 /* Maximum number of glyphs we buffer on the stack before flushing
     66  * rendering to the mask or destination surface.
     67  */
     68 #define GLYPH_BUFFER_SIZE 256
     69 
     70 typedef struct {
     71     PicturePtr mask;
     72     ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE];
     73     int count;
     74 } ExaGlyphBuffer, *ExaGlyphBufferPtr;
     75 
     76 typedef enum {
     77     ExaGlyphSuccess,            /* Glyph added to render buffer */
     78     ExaGlyphFail,               /* out of memory, etc */
     79     ExaGlyphNeedFlush,          /* would evict a glyph already in the buffer */
     80 } ExaGlyphCacheResult;
     81 
     82 void
     83 exaGlyphsInit(ScreenPtr pScreen)
     84 {
     85     ExaScreenPriv(pScreen);
     86     int i = 0;
     87 
     88     memset(pExaScr->glyphCaches, 0, sizeof(pExaScr->glyphCaches));
     89 
     90     pExaScr->glyphCaches[i].format = PICT_a8;
     91     pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
     92         16;
     93     i++;
     94     pExaScr->glyphCaches[i].format = PICT_a8;
     95     pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
     96         32;
     97     i++;
     98     pExaScr->glyphCaches[i].format = PICT_a8r8g8b8;
     99     pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
    100         16;
    101     i++;
    102     pExaScr->glyphCaches[i].format = PICT_a8r8g8b8;
    103     pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
    104         32;
    105     i++;
    106 
    107     assert(i == EXA_NUM_GLYPH_CACHES);
    108 
    109     for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
    110         pExaScr->glyphCaches[i].columns =
    111             CACHE_PICTURE_WIDTH / pExaScr->glyphCaches[i].glyphWidth;
    112         pExaScr->glyphCaches[i].size = 256;
    113         pExaScr->glyphCaches[i].hashSize = 557;
    114     }
    115 }
    116 
    117 static void
    118 exaUnrealizeGlyphCaches(ScreenPtr pScreen, unsigned int format)
    119 {
    120     ExaScreenPriv(pScreen);
    121     int i;
    122 
    123     for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
    124         ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
    125 
    126         if (cache->format != format)
    127             continue;
    128 
    129         if (cache->picture) {
    130             FreePicture((void *) cache->picture, (XID) 0);
    131             cache->picture = NULL;
    132         }
    133 
    134         free(cache->hashEntries);
    135         cache->hashEntries = NULL;
    136 
    137         free(cache->glyphs);
    138         cache->glyphs = NULL;
    139         cache->glyphCount = 0;
    140     }
    141 }
    142 
    143 #define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
    144 
    145 /* All caches for a single format share a single pixmap for glyph storage,
    146  * allowing mixing glyphs of different sizes without paying a penalty
    147  * for switching between mask pixmaps. (Note that for a size of font
    148  * right at the border between two sizes, we might be switching for almost
    149  * every glyph.)
    150  *
    151  * This function allocates the storage pixmap, and then fills in the
    152  * rest of the allocated structures for all caches with the given format.
    153  */
    154 static Bool
    155 exaRealizeGlyphCaches(ScreenPtr pScreen, unsigned int format)
    156 {
    157     ExaScreenPriv(pScreen);
    158 
    159     int depth = PIXMAN_FORMAT_DEPTH(format);
    160     PictFormatPtr pPictFormat;
    161     PixmapPtr pPixmap;
    162     PicturePtr pPicture;
    163     CARD32 component_alpha;
    164     int height;
    165     int i;
    166     int error;
    167 
    168     pPictFormat = PictureMatchFormat(pScreen, depth, format);
    169     if (!pPictFormat)
    170         return FALSE;
    171 
    172     /* Compute the total vertical size needed for the format */
    173 
    174     height = 0;
    175     for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
    176         ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
    177         int rows;
    178 
    179         if (cache->format != format)
    180             continue;
    181 
    182         cache->yOffset = height;
    183 
    184         rows = (cache->size + cache->columns - 1) / cache->columns;
    185         height += rows * cache->glyphHeight;
    186     }
    187 
    188     /* Now allocate the pixmap and picture */
    189     pPixmap = (*pScreen->CreatePixmap) (pScreen,
    190                                         CACHE_PICTURE_WIDTH, height, depth, 0);
    191     if (!pPixmap)
    192         return FALSE;
    193 
    194     component_alpha = NeedsComponent(pPictFormat->format);
    195     pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
    196                              CPComponentAlpha, &component_alpha, serverClient,
    197                              &error);
    198 
    199     (*pScreen->DestroyPixmap) (pPixmap);        /* picture holds a refcount */
    200 
    201     if (!pPicture)
    202         return FALSE;
    203 
    204     /* And store the picture in all the caches for the format */
    205     for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
    206         ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
    207         int j;
    208 
    209         if (cache->format != format)
    210             continue;
    211 
    212         cache->picture = pPicture;
    213         cache->picture->refcnt++;
    214         cache->hashEntries = xallocarray(cache->hashSize, sizeof(int));
    215         cache->glyphs = xallocarray(cache->size, sizeof(ExaCachedGlyphRec));
    216         cache->glyphCount = 0;
    217 
    218         if (!cache->hashEntries || !cache->glyphs)
    219             goto bail;
    220 
    221         for (j = 0; j < cache->hashSize; j++)
    222             cache->hashEntries[j] = -1;
    223 
    224         cache->evictionPosition = rand() % cache->size;
    225     }
    226 
    227     /* Each cache references the picture individually */
    228     FreePicture((void *) pPicture, (XID) 0);
    229     return TRUE;
    230 
    231  bail:
    232     exaUnrealizeGlyphCaches(pScreen, format);
    233     return FALSE;
    234 }
    235 
    236 void
    237 exaGlyphsFini(ScreenPtr pScreen)
    238 {
    239     ExaScreenPriv(pScreen);
    240     int i;
    241 
    242     for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
    243         ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
    244 
    245         if (cache->picture)
    246             exaUnrealizeGlyphCaches(pScreen, cache->format);
    247     }
    248 }
    249 
    250 static int
    251 exaGlyphCacheHashLookup(ExaGlyphCachePtr cache, GlyphPtr pGlyph)
    252 {
    253     int slot;
    254 
    255     slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize;
    256 
    257     while (TRUE) {              /* hash table can never be full */
    258         int entryPos = cache->hashEntries[slot];
    259 
    260         if (entryPos == -1)
    261             return -1;
    262 
    263         if (memcmp
    264             (pGlyph->sha1, cache->glyphs[entryPos].sha1,
    265              sizeof(pGlyph->sha1)) == 0) {
    266             return entryPos;
    267         }
    268 
    269         slot--;
    270         if (slot < 0)
    271             slot = cache->hashSize - 1;
    272     }
    273 }
    274 
    275 static void
    276 exaGlyphCacheHashInsert(ExaGlyphCachePtr cache, GlyphPtr pGlyph, int pos)
    277 {
    278     int slot;
    279 
    280     memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1));
    281 
    282     slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize;
    283 
    284     while (TRUE) {              /* hash table can never be full */
    285         if (cache->hashEntries[slot] == -1) {
    286             cache->hashEntries[slot] = pos;
    287             return;
    288         }
    289 
    290         slot--;
    291         if (slot < 0)
    292             slot = cache->hashSize - 1;
    293     }
    294 }
    295 
    296 static void
    297 exaGlyphCacheHashRemove(ExaGlyphCachePtr cache, int pos)
    298 {
    299     int slot;
    300     int emptiedSlot = -1;
    301 
    302     slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize;
    303 
    304     while (TRUE) {              /* hash table can never be full */
    305         int entryPos = cache->hashEntries[slot];
    306 
    307         if (entryPos == -1)
    308             return;
    309 
    310         if (entryPos == pos) {
    311             cache->hashEntries[slot] = -1;
    312             emptiedSlot = slot;
    313         }
    314         else if (emptiedSlot != -1) {
    315             /* See if we can move this entry into the emptied slot, we can't
    316              * do that if if entry would have hashed between the current position
    317              * and the emptied slot. (taking wrapping into account). Bad positions
    318              * are:
    319              *
    320              * |   XXXXXXXXXX             |
    321              *     i         j
    322              *
    323              * |XXX                   XXXX|
    324              *     j                  i
    325              *
    326              * i - slot, j - emptiedSlot
    327              *
    328              * (Knuth 6.4R)
    329              */
    330 
    331             int entrySlot =
    332                 (*(CARD32 *) cache->glyphs[entryPos].sha1) % cache->hashSize;
    333 
    334             if (!((entrySlot >= slot && entrySlot < emptiedSlot) ||
    335                   (emptiedSlot < slot &&
    336                    (entrySlot < emptiedSlot || entrySlot >= slot)))) {
    337                 cache->hashEntries[emptiedSlot] = entryPos;
    338                 cache->hashEntries[slot] = -1;
    339                 emptiedSlot = slot;
    340             }
    341         }
    342 
    343         slot--;
    344         if (slot < 0)
    345             slot = cache->hashSize - 1;
    346     }
    347 }
    348 
    349 #define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth)
    350 #define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight)
    351 
    352 /* The most efficient thing to way to upload the glyph to the screen
    353  * is to use the UploadToScreen() driver hook; this allows us to
    354  * pipeline glyph uploads and to avoid creating gpu backed pixmaps for
    355  * glyphs that we'll never use again.
    356  *
    357  * If we can't do it with UploadToScreen (because the glyph has a gpu copy,
    358  * etc), we fall back to CompositePicture.
    359  *
    360  * We need to damage the cache pixmap manually in either case because the damage
    361  * layer unwrapped the picture screen before calling exaGlyphs.
    362  */
    363 static void
    364 exaGlyphCacheUploadGlyph(ScreenPtr pScreen,
    365                          ExaGlyphCachePtr cache, int x, int y, GlyphPtr pGlyph)
    366 {
    367     ExaScreenPriv(pScreen);
    368     PicturePtr pGlyphPicture = GetGlyphPicture(pGlyph, pScreen);
    369     PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable;
    370 
    371     ExaPixmapPriv(pGlyphPixmap);
    372     PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable;
    373 
    374     if (!pExaScr->info->UploadToScreen || pExaScr->swappedOut ||
    375         pExaPixmap->accel_blocked)
    376         goto composite;
    377 
    378     /* If the glyph pixmap is already uploaded, no point in doing
    379      * things this way */
    380     if (exaPixmapHasGpuCopy(pGlyphPixmap))
    381         goto composite;
    382 
    383     /* UploadToScreen only works if bpp match */
    384     if (pGlyphPixmap->drawable.bitsPerPixel !=
    385         pCachePixmap->drawable.bitsPerPixel)
    386         goto composite;
    387 
    388     if (pExaScr->do_migration) {
    389         ExaMigrationRec pixmaps[1];
    390 
    391         /* cache pixmap must have a gpu copy. */
    392         pixmaps[0].as_dst = TRUE;
    393         pixmaps[0].as_src = FALSE;
    394         pixmaps[0].pPix = pCachePixmap;
    395         pixmaps[0].pReg = NULL;
    396         exaDoMigration(pixmaps, 1, TRUE);
    397     }
    398 
    399     if (!exaPixmapHasGpuCopy(pCachePixmap))
    400         goto composite;
    401 
    402     /* x,y are in pixmap coordinates, no need for cache{X,Y}off */
    403     if (pExaScr->info->UploadToScreen(pCachePixmap,
    404                                       x,
    405                                       y,
    406                                       pGlyph->info.width,
    407                                       pGlyph->info.height,
    408                                       (char *) pExaPixmap->sys_ptr,
    409                                       pExaPixmap->sys_pitch))
    410         goto damage;
    411 
    412  composite:
    413     CompositePicture(PictOpSrc,
    414                      pGlyphPicture,
    415                      None,
    416                      cache->picture,
    417                      0, 0, 0, 0, x, y, pGlyph->info.width, pGlyph->info.height);
    418 
    419  damage:
    420     /* The cache pixmap isn't a window, so no need to offset coordinates. */
    421     exaPixmapDirty(pCachePixmap,
    422                    x, y, x + cache->glyphWidth, y + cache->glyphHeight);
    423 }
    424 
    425 static ExaGlyphCacheResult
    426 exaGlyphCacheBufferGlyph(ScreenPtr pScreen,
    427                          ExaGlyphCachePtr cache,
    428                          ExaGlyphBufferPtr buffer,
    429                          GlyphPtr pGlyph,
    430                          PicturePtr pSrc,
    431                          PicturePtr pDst,
    432                          INT16 xSrc,
    433                          INT16 ySrc,
    434                          INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst)
    435 {
    436     ExaCompositeRectPtr rect;
    437     int pos;
    438     int x, y;
    439 
    440     if (buffer->mask && buffer->mask != cache->picture)
    441         return ExaGlyphNeedFlush;
    442 
    443     if (!cache->picture) {
    444         if (!exaRealizeGlyphCaches(pScreen, cache->format))
    445             return ExaGlyphFail;
    446     }
    447 
    448     DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n",
    449                      cache->glyphWidth, cache->glyphHeight,
    450                      cache->format == PICT_a8 ? "A" : "ARGB",
    451                      (long) *(CARD32 *) pGlyph->sha1));
    452 
    453     pos = exaGlyphCacheHashLookup(cache, pGlyph);
    454     if (pos != -1) {
    455         DBG_GLYPH_CACHE(("  found existing glyph at %d\n", pos));
    456         x = CACHE_X(pos);
    457         y = CACHE_Y(pos);
    458     }
    459     else {
    460         if (cache->glyphCount < cache->size) {
    461             /* Space remaining; we fill from the start */
    462             pos = cache->glyphCount;
    463             x = CACHE_X(pos);
    464             y = CACHE_Y(pos);
    465             cache->glyphCount++;
    466             DBG_GLYPH_CACHE(("  storing glyph in free space at %d\n", pos));
    467 
    468             exaGlyphCacheHashInsert(cache, pGlyph, pos);
    469 
    470         }
    471         else {
    472             /* Need to evict an entry. We have to see if any glyphs
    473              * already in the output buffer were at this position in
    474              * the cache
    475              */
    476             pos = cache->evictionPosition;
    477             x = CACHE_X(pos);
    478             y = CACHE_Y(pos);
    479             DBG_GLYPH_CACHE(("  evicting glyph at %d\n", pos));
    480             if (buffer->count) {
    481                 int i;
    482 
    483                 for (i = 0; i < buffer->count; i++) {
    484                     if (pSrc ?
    485                         (buffer->rects[i].xMask == x &&
    486                          buffer->rects[i].yMask ==
    487                          y) : (buffer->rects[i].xSrc == x &&
    488                                buffer->rects[i].ySrc == y)) {
    489                         DBG_GLYPH_CACHE(("  must flush buffer\n"));
    490                         return ExaGlyphNeedFlush;
    491                     }
    492                 }
    493             }
    494 
    495             /* OK, we're all set, swap in the new glyph */
    496             exaGlyphCacheHashRemove(cache, pos);
    497             exaGlyphCacheHashInsert(cache, pGlyph, pos);
    498 
    499             /* And pick a new eviction position */
    500             cache->evictionPosition = rand() % cache->size;
    501         }
    502 
    503         exaGlyphCacheUploadGlyph(pScreen, cache, x, y, pGlyph);
    504     }
    505 
    506     buffer->mask = cache->picture;
    507 
    508     rect = &buffer->rects[buffer->count];
    509 
    510     if (pSrc) {
    511         rect->xSrc = xSrc;
    512         rect->ySrc = ySrc;
    513         rect->xMask = x;
    514         rect->yMask = y;
    515     }
    516     else {
    517         rect->xSrc = x;
    518         rect->ySrc = y;
    519         rect->xMask = 0;
    520         rect->yMask = 0;
    521     }
    522 
    523     rect->pDst = pDst;
    524     rect->xDst = xDst;
    525     rect->yDst = yDst;
    526     rect->width = pGlyph->info.width;
    527     rect->height = pGlyph->info.height;
    528 
    529     buffer->count++;
    530 
    531     return ExaGlyphSuccess;
    532 }
    533 
    534 #undef CACHE_X
    535 #undef CACHE_Y
    536 
    537 static ExaGlyphCacheResult
    538 exaBufferGlyph(ScreenPtr pScreen,
    539                ExaGlyphBufferPtr buffer,
    540                GlyphPtr pGlyph,
    541                PicturePtr pSrc,
    542                PicturePtr pDst,
    543                INT16 xSrc,
    544                INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst)
    545 {
    546     ExaScreenPriv(pScreen);
    547     unsigned int format = (GetGlyphPicture(pGlyph, pScreen))->format;
    548     int width = pGlyph->info.width;
    549     int height = pGlyph->info.height;
    550     ExaCompositeRectPtr rect;
    551     PicturePtr mask;
    552     int i;
    553 
    554     if (buffer->count == GLYPH_BUFFER_SIZE)
    555         return ExaGlyphNeedFlush;
    556 
    557     if (PICT_FORMAT_BPP(format) == 1)
    558         format = PICT_a8;
    559 
    560     for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
    561         ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
    562 
    563         if (format == cache->format &&
    564             width <= cache->glyphWidth && height <= cache->glyphHeight) {
    565             ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen,
    566                                                                   &pExaScr->
    567                                                                   glyphCaches
    568                                                                   [i],
    569                                                                   buffer,
    570                                                                   pGlyph,
    571                                                                   pSrc,
    572                                                                   pDst,
    573                                                                   xSrc, ySrc,
    574                                                                   xMask, yMask,
    575                                                                   xDst, yDst);
    576 
    577             switch (result) {
    578             case ExaGlyphFail:
    579                 break;
    580             case ExaGlyphSuccess:
    581             case ExaGlyphNeedFlush:
    582                 return result;
    583             }
    584         }
    585     }
    586 
    587     /* Couldn't find the glyph in the cache, use the glyph picture directly */
    588 
    589     mask = GetGlyphPicture(pGlyph, pScreen);
    590     if (buffer->mask && buffer->mask != mask)
    591         return ExaGlyphNeedFlush;
    592 
    593     buffer->mask = mask;
    594 
    595     rect = &buffer->rects[buffer->count];
    596     rect->xSrc = xSrc;
    597     rect->ySrc = ySrc;
    598     rect->xMask = xMask;
    599     rect->yMask = yMask;
    600     rect->xDst = xDst;
    601     rect->yDst = yDst;
    602     rect->width = width;
    603     rect->height = height;
    604 
    605     buffer->count++;
    606 
    607     return ExaGlyphSuccess;
    608 }
    609 
    610 static void
    611 exaGlyphsToMask(PicturePtr pMask, ExaGlyphBufferPtr buffer)
    612 {
    613     exaCompositeRects(PictOpAdd, buffer->mask, NULL, pMask,
    614                       buffer->count, buffer->rects);
    615 
    616     buffer->count = 0;
    617     buffer->mask = NULL;
    618 }
    619 
    620 static void
    621 exaGlyphsToDst(CARD8 op, PicturePtr pSrc, PicturePtr pDst, ExaGlyphBufferPtr buffer)
    622 {
    623     exaCompositeRects(op, pSrc, buffer->mask, pDst, buffer->count,
    624                       buffer->rects);
    625 
    626     buffer->count = 0;
    627     buffer->mask = NULL;
    628 }
    629 
    630 /* Cut and paste from render/glyph.c - probably should export it instead */
    631 static void
    632 GlyphExtents(int nlist, GlyphListPtr list, GlyphPtr * glyphs, BoxPtr extents)
    633 {
    634     int x1, x2, y1, y2;
    635     int n;
    636     GlyphPtr glyph;
    637     int x, y;
    638 
    639     x = 0;
    640     y = 0;
    641     extents->x1 = MAXSHORT;
    642     extents->x2 = MINSHORT;
    643     extents->y1 = MAXSHORT;
    644     extents->y2 = MINSHORT;
    645     while (nlist--) {
    646         x += list->xOff;
    647         y += list->yOff;
    648         n = list->len;
    649         list++;
    650         while (n--) {
    651             glyph = *glyphs++;
    652             x1 = x - glyph->info.x;
    653             if (x1 < MINSHORT)
    654                 x1 = MINSHORT;
    655             y1 = y - glyph->info.y;
    656             if (y1 < MINSHORT)
    657                 y1 = MINSHORT;
    658             x2 = x1 + glyph->info.width;
    659             if (x2 > MAXSHORT)
    660                 x2 = MAXSHORT;
    661             y2 = y1 + glyph->info.height;
    662             if (y2 > MAXSHORT)
    663                 y2 = MAXSHORT;
    664             if (x1 < extents->x1)
    665                 extents->x1 = x1;
    666             if (x2 > extents->x2)
    667                 extents->x2 = x2;
    668             if (y1 < extents->y1)
    669                 extents->y1 = y1;
    670             if (y2 > extents->y2)
    671                 extents->y2 = y2;
    672             x += glyph->info.xOff;
    673             y += glyph->info.yOff;
    674         }
    675     }
    676 }
    677 
    678 void
    679 exaGlyphs(CARD8 op,
    680           PicturePtr pSrc,
    681           PicturePtr pDst,
    682           PictFormatPtr maskFormat,
    683           INT16 xSrc,
    684           INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
    685 {
    686     PixmapPtr pMaskPixmap = 0;
    687     PicturePtr pMask = NULL;
    688     ScreenPtr pScreen = pDst->pDrawable->pScreen;
    689     int width = 0, height = 0;
    690     int x, y;
    691     int first_xOff = list->xOff, first_yOff = list->yOff;
    692     int n;
    693     GlyphPtr glyph;
    694     int error;
    695     BoxRec extents = { 0, 0, 0, 0 };
    696     CARD32 component_alpha;
    697     ExaGlyphBuffer buffer;
    698 
    699     if (maskFormat) {
    700         ExaScreenPriv(pScreen);
    701         GCPtr pGC;
    702         xRectangle rect;
    703 
    704         GlyphExtents(nlist, list, glyphs, &extents);
    705 
    706         if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
    707             return;
    708         width = extents.x2 - extents.x1;
    709         height = extents.y2 - extents.y1;
    710 
    711         if (maskFormat->depth == 1) {
    712             PictFormatPtr a8Format = PictureMatchFormat(pScreen, 8, PICT_a8);
    713 
    714             if (a8Format)
    715                 maskFormat = a8Format;
    716         }
    717 
    718         pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
    719                                                 maskFormat->depth,
    720                                                 CREATE_PIXMAP_USAGE_SCRATCH);
    721         if (!pMaskPixmap)
    722             return;
    723         component_alpha = NeedsComponent(maskFormat->format);
    724         pMask = CreatePicture(0, &pMaskPixmap->drawable,
    725                               maskFormat, CPComponentAlpha, &component_alpha,
    726                               serverClient, &error);
    727         if (!pMask ||
    728             (!component_alpha && pExaScr->info->CheckComposite &&
    729              !(*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, NULL, pMask)))
    730         {
    731             PictFormatPtr argbFormat;
    732 
    733             (*pScreen->DestroyPixmap) (pMaskPixmap);
    734 
    735             if (!pMask)
    736                 return;
    737 
    738             /* The driver can't seem to composite to a8, let's try argb (but
    739              * without component-alpha) */
    740             FreePicture((void *) pMask, (XID) 0);
    741 
    742             argbFormat = PictureMatchFormat(pScreen, 32, PICT_a8r8g8b8);
    743 
    744             if (argbFormat)
    745                 maskFormat = argbFormat;
    746 
    747             pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
    748                                                     maskFormat->depth,
    749                                                     CREATE_PIXMAP_USAGE_SCRATCH);
    750             if (!pMaskPixmap)
    751                 return;
    752 
    753             pMask = CreatePicture(0, &pMaskPixmap->drawable, maskFormat, 0, 0,
    754                                   serverClient, &error);
    755             if (!pMask) {
    756                 (*pScreen->DestroyPixmap) (pMaskPixmap);
    757                 return;
    758             }
    759         }
    760         pGC = GetScratchGC(pMaskPixmap->drawable.depth, pScreen);
    761         ValidateGC(&pMaskPixmap->drawable, pGC);
    762         rect.x = 0;
    763         rect.y = 0;
    764         rect.width = width;
    765         rect.height = height;
    766         (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
    767         FreeScratchGC(pGC);
    768         x = -extents.x1;
    769         y = -extents.y1;
    770     }
    771     else {
    772         x = 0;
    773         y = 0;
    774     }
    775     buffer.count = 0;
    776     buffer.mask = NULL;
    777     while (nlist--) {
    778         x += list->xOff;
    779         y += list->yOff;
    780         n = list->len;
    781         while (n--) {
    782             glyph = *glyphs++;
    783 
    784             if (glyph->info.width > 0 && glyph->info.height > 0) {
    785                 /* pGlyph->info.{x,y} compensate for empty space in the glyph. */
    786                 if (maskFormat) {
    787                     if (exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask,
    788                                        0, 0, 0, 0, x - glyph->info.x,
    789                                        y - glyph->info.y) ==
    790                         ExaGlyphNeedFlush) {
    791                         exaGlyphsToMask(pMask, &buffer);
    792                         exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask,
    793                                        0, 0, 0, 0, x - glyph->info.x,
    794                                        y - glyph->info.y);
    795                     }
    796                 }
    797                 else {
    798                     if (exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst,
    799                                        xSrc + (x - glyph->info.x) - first_xOff,
    800                                        ySrc + (y - glyph->info.y) - first_yOff,
    801                                        0, 0, x - glyph->info.x,
    802                                        y - glyph->info.y)
    803                         == ExaGlyphNeedFlush) {
    804                         exaGlyphsToDst(op, pSrc, pDst, &buffer);
    805                         exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst,
    806                                        xSrc + (x - glyph->info.x) - first_xOff,
    807                                        ySrc + (y - glyph->info.y) - first_yOff,
    808                                        0, 0, x - glyph->info.x,
    809                                        y - glyph->info.y);
    810                     }
    811                 }
    812             }
    813 
    814             x += glyph->info.xOff;
    815             y += glyph->info.yOff;
    816         }
    817         list++;
    818     }
    819 
    820     if (buffer.count) {
    821         if (maskFormat)
    822             exaGlyphsToMask(pMask, &buffer);
    823         else
    824             exaGlyphsToDst(op, pSrc, pDst, &buffer);
    825     }
    826 
    827     if (maskFormat) {
    828         x = extents.x1;
    829         y = extents.y1;
    830         CompositePicture(op,
    831                          pSrc,
    832                          pMask,
    833                          pDst,
    834                          xSrc + x - first_xOff,
    835                          ySrc + y - first_yOff, 0, 0, x, y, width, height);
    836         FreePicture((void *) pMask, (XID) 0);
    837         (*pScreen->DestroyPixmap) (pMaskPixmap);
    838     }
    839 }