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