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
exaGlyphsInit(ScreenPtr pScreen)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
exaUnrealizeGlyphCaches(ScreenPtr pScreen,unsigned int format)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
exaRealizeGlyphCaches(ScreenPtr pScreen,unsigned int format)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
exaGlyphsFini(ScreenPtr pScreen)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
exaGlyphCacheHashLookup(ExaGlyphCachePtr cache,GlyphPtr pGlyph)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
exaGlyphCacheHashInsert(ExaGlyphCachePtr cache,GlyphPtr pGlyph,int pos)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
exaGlyphCacheHashRemove(ExaGlyphCachePtr cache,int pos)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
exaGlyphCacheUploadGlyph(ScreenPtr pScreen,ExaGlyphCachePtr cache,int x,int y,GlyphPtr pGlyph)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
exaGlyphCacheBufferGlyph(ScreenPtr pScreen,ExaGlyphCachePtr cache,ExaGlyphBufferPtr buffer,GlyphPtr pGlyph,PicturePtr pSrc,PicturePtr pDst,INT16 xSrc,INT16 ySrc,INT16 xMask,INT16 yMask,INT16 xDst,INT16 yDst)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
exaBufferGlyph(ScreenPtr pScreen,ExaGlyphBufferPtr buffer,GlyphPtr pGlyph,PicturePtr pSrc,PicturePtr pDst,INT16 xSrc,INT16 ySrc,INT16 xMask,INT16 yMask,INT16 xDst,INT16 yDst)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
exaGlyphsToMask(PicturePtr pMask,ExaGlyphBufferPtr buffer)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
exaGlyphsToDst(CARD8 op,PicturePtr pSrc,PicturePtr pDst,ExaGlyphBufferPtr buffer)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
GlyphExtents(int nlist,GlyphListPtr list,GlyphPtr * glyphs,BoxPtr extents)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
exaGlyphs(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int nlist,GlyphListPtr list,GlyphPtr * glyphs)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 }
840