1428d7b3dSmrg/*
2428d7b3dSmrg * Copyright © 2010 Intel Corporation
3428d7b3dSmrg * Partly based on code Copyright © 2008 Red Hat, Inc.
4428d7b3dSmrg * Partly based on code Copyright © 2000 SuSE, Inc.
5428d7b3dSmrg *
6428d7b3dSmrg * Permission to use, copy, modify, distribute, and sell this software and its
7428d7b3dSmrg * documentation for any purpose is hereby granted without fee, provided that
8428d7b3dSmrg * the above copyright notice appear in all copies and that both that
9428d7b3dSmrg * copyright notice and this permission notice appear in supporting
10428d7b3dSmrg * documentation, and that the name of Intel not be used in advertising or
11428d7b3dSmrg * publicity pertaining to distribution of the software without specific,
12428d7b3dSmrg * written prior permission.  Intel makes no representations about the
13428d7b3dSmrg * suitability of this software for any purpose.  It is provided "as is"
14428d7b3dSmrg * without express or implied warranty.
15428d7b3dSmrg *
16428d7b3dSmrg * INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17428d7b3dSmrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INTEL
18428d7b3dSmrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19428d7b3dSmrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20428d7b3dSmrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21428d7b3dSmrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22428d7b3dSmrg *
23428d7b3dSmrg * Permission to use, copy, modify, distribute, and sell this software and its
24428d7b3dSmrg * documentation for any purpose is hereby granted without fee, provided that
25428d7b3dSmrg * the above copyright notice appear in all copies and that both that
26428d7b3dSmrg * copyright notice and this permission notice appear in supporting
27428d7b3dSmrg * documentation, and that the name of Red Hat not be used in advertising or
28428d7b3dSmrg * publicity pertaining to distribution of the software without specific,
29428d7b3dSmrg * written prior permission.  Red Hat makes no representations about the
30428d7b3dSmrg * suitability of this software for any purpose.  It is provided "as is"
31428d7b3dSmrg * without express or implied warranty.
32428d7b3dSmrg *
33428d7b3dSmrg * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
34428d7b3dSmrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat
35428d7b3dSmrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
36428d7b3dSmrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
37428d7b3dSmrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
38428d7b3dSmrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
39428d7b3dSmrg *
40428d7b3dSmrg * Permission to use, copy, modify, distribute, and sell this software and its
41428d7b3dSmrg * documentation for any purpose is hereby granted without fee, provided that
42428d7b3dSmrg * the above copyright notice appear in all copies and that both that
43428d7b3dSmrg * copyright notice and this permission notice appear in supporting
44428d7b3dSmrg * documentation, and that the name of SuSE not be used in advertising or
45428d7b3dSmrg * publicity pertaining to distribution of the software without specific,
46428d7b3dSmrg * written prior permission.  SuSE makes no representations about the
47428d7b3dSmrg * suitability of this software for any purpose.  It is provided "as is"
48428d7b3dSmrg * without express or implied warranty.
49428d7b3dSmrg *
50428d7b3dSmrg * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
51428d7b3dSmrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
52428d7b3dSmrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
53428d7b3dSmrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
54428d7b3dSmrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
55428d7b3dSmrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
56428d7b3dSmrg *
57428d7b3dSmrg * Author: Chris Wilson <chris@chris-wilson.co.uk>
58428d7b3dSmrg * Based on code by: Keith Packard <keithp@keithp.com> and Owen Taylor <otaylor@fishsoup.net>
59428d7b3dSmrg */
60428d7b3dSmrg
61428d7b3dSmrg#ifdef HAVE_CONFIG_H
62428d7b3dSmrg#include "config.h"
63428d7b3dSmrg#endif
64428d7b3dSmrg
65428d7b3dSmrg#include "sna.h"
66428d7b3dSmrg#include "sna_render.h"
67428d7b3dSmrg#include "sna_render_inline.h"
68428d7b3dSmrg#include "fb/fbpict.h"
69428d7b3dSmrg
70428d7b3dSmrg#define FALLBACK 0
71428d7b3dSmrg#define NO_GLYPH_CACHE 0
72428d7b3dSmrg#define NO_GLYPHS_TO_DST 0
73428d7b3dSmrg#define FORCE_GLYPHS_TO_DST 0
74428d7b3dSmrg#define NO_GLYPHS_VIA_MASK 0
75428d7b3dSmrg#define FORCE_SMALL_MASK 0 /* -1 = never, 1 = always */
76428d7b3dSmrg#define NO_GLYPHS_SLOW 0
77428d7b3dSmrg#define NO_DISCARD_MASK 0
78428d7b3dSmrg
79428d7b3dSmrg#define CACHE_PICTURE_SIZE 1024
80428d7b3dSmrg#define GLYPH_MIN_SIZE 8
81428d7b3dSmrg#define GLYPH_MAX_SIZE 64
82428d7b3dSmrg#define GLYPH_CACHE_SIZE (CACHE_PICTURE_SIZE * CACHE_PICTURE_SIZE / (GLYPH_MIN_SIZE * GLYPH_MIN_SIZE))
83428d7b3dSmrg
84428d7b3dSmrg#define N_STACK_GLYPHS 512
85428d7b3dSmrg#define NO_ATLAS ((PicturePtr)-1)
86428d7b3dSmrg#define GLYPH_TOLERANCE 3
87428d7b3dSmrg
88428d7b3dSmrg#define glyph_valid(g) *((uint32_t *)&(g)->info.width)
89428d7b3dSmrg#define glyph_copy_size(r, g) *(uint32_t *)&(r)->width = *(uint32_t *)&g->info.width
90428d7b3dSmrg
91428d7b3dSmrg#if HAS_PIXMAN_GLYPHS
92428d7b3dSmrgstatic  pixman_glyph_cache_t *__global_glyph_cache;
93428d7b3dSmrg#endif
94428d7b3dSmrg
95428d7b3dSmrg#if HAS_DEBUG_FULL
96428d7b3dSmrgstatic void _assert_pixmap_contains_box(PixmapPtr pixmap, BoxPtr box, const char *function)
97428d7b3dSmrg{
98428d7b3dSmrg	if (box->x1 < 0 || box->y1 < 0 ||
99428d7b3dSmrg	    box->x2 > pixmap->drawable.width ||
100428d7b3dSmrg	    box->y2 > pixmap->drawable.height)
101428d7b3dSmrg	{
102428d7b3dSmrg		FatalError("%s: damage box is beyond the pixmap: box=(%d, %d), (%d, %d), pixmap=(%d, %d)\n",
103428d7b3dSmrg			   function,
104428d7b3dSmrg			   box->x1, box->y1, box->x2, box->y2,
105428d7b3dSmrg			   pixmap->drawable.width,
106428d7b3dSmrg			   pixmap->drawable.height);
107428d7b3dSmrg	}
108428d7b3dSmrg}
109428d7b3dSmrg#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__)
110428d7b3dSmrg#else
111428d7b3dSmrg#define assert_pixmap_contains_box(p, b)
112428d7b3dSmrg#endif
113428d7b3dSmrg
114428d7b3dSmrgextern DevPrivateKeyRec sna_glyph_key;
115428d7b3dSmrg
116428d7b3dSmrgstatic inline struct sna_glyph *sna_glyph(GlyphPtr glyph)
117428d7b3dSmrg{
118428d7b3dSmrg	return __get_private(glyph, sna_glyph_key);
119428d7b3dSmrg}
120428d7b3dSmrg
121428d7b3dSmrgstatic inline struct sna_glyph *sna_glyph0(GlyphPtr glyph)
122428d7b3dSmrg{
123428d7b3dSmrg	return (struct sna_glyph *)glyph->devPrivates;
124428d7b3dSmrg}
125428d7b3dSmrg
126428d7b3dSmrgstatic inline bool can_use_glyph0(void)
127428d7b3dSmrg{
128428d7b3dSmrg#if HAS_DEVPRIVATEKEYREC
129428d7b3dSmrg	return sna_glyph_key.offset == 0;
130428d7b3dSmrg#else
131428d7b3dSmrg	return 0;
132428d7b3dSmrg#endif
133428d7b3dSmrg}
134428d7b3dSmrg
135428d7b3dSmrg#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
136428d7b3dSmrg
137428d7b3dSmrgstatic bool op_is_bounded(uint8_t op)
138428d7b3dSmrg{
139428d7b3dSmrg	switch (op) {
140428d7b3dSmrg	case PictOpOver:
141428d7b3dSmrg	case PictOpOutReverse:
142428d7b3dSmrg	case PictOpAdd:
143428d7b3dSmrg	case PictOpXor:
144428d7b3dSmrg		return true;
145428d7b3dSmrg	default:
146428d7b3dSmrg		return false;
147428d7b3dSmrg	}
148428d7b3dSmrg}
149428d7b3dSmrg
150428d7b3dSmrgvoid sna_glyphs_close(struct sna *sna)
151428d7b3dSmrg{
152428d7b3dSmrg	struct sna_render *render = &sna->render;
153428d7b3dSmrg	unsigned int i;
154428d7b3dSmrg
155428d7b3dSmrg	DBG(("%s\n", __FUNCTION__));
156428d7b3dSmrg
157428d7b3dSmrg	for (i = 0; i < ARRAY_SIZE(render->glyph); i++) {
158428d7b3dSmrg		struct sna_glyph_cache *cache = &render->glyph[i];
159428d7b3dSmrg
160428d7b3dSmrg		if (cache->picture)
161428d7b3dSmrg			FreePicture(cache->picture, 0);
162428d7b3dSmrg
163428d7b3dSmrg		free(cache->glyphs);
164428d7b3dSmrg	}
165428d7b3dSmrg	memset(render->glyph, 0, sizeof(render->glyph));
166428d7b3dSmrg
167428d7b3dSmrg	if (render->white_image) {
168428d7b3dSmrg		pixman_image_unref(render->white_image);
169428d7b3dSmrg		render->white_image = NULL;
170428d7b3dSmrg	}
171428d7b3dSmrg	if (render->white_picture) {
172428d7b3dSmrg		FreePicture(render->white_picture, 0);
173428d7b3dSmrg		render->white_picture = NULL;
174428d7b3dSmrg	}
175428d7b3dSmrg}
176428d7b3dSmrg
177428d7b3dSmrg/* All caches for a single format share a single pixmap for glyph storage,
178428d7b3dSmrg * allowing mixing glyphs of different sizes without paying a penalty
179428d7b3dSmrg * for switching between source pixmaps. (Note that for a size of font
180428d7b3dSmrg * right at the border between two sizes, we might be switching for almost
181428d7b3dSmrg * every glyph.)
182428d7b3dSmrg *
183428d7b3dSmrg * This function allocates the storage pixmap, and then fills in the
184428d7b3dSmrg * rest of the allocated structures for all caches with the given format.
185428d7b3dSmrg */
186428d7b3dSmrgbool sna_glyphs_create(struct sna *sna)
187428d7b3dSmrg{
188428d7b3dSmrg	ScreenPtr screen = sna->scrn->pScreen;
189428d7b3dSmrg	pixman_color_t white = { 0xffff, 0xffff, 0xffff, 0xffff };
190428d7b3dSmrg	unsigned int formats[] = {
191428d7b3dSmrg		PIXMAN_a8,
192428d7b3dSmrg		PIXMAN_a8r8g8b8,
193428d7b3dSmrg	};
194428d7b3dSmrg	unsigned int i;
195428d7b3dSmrg	int error;
196428d7b3dSmrg
197428d7b3dSmrg	DBG(("%s\n", __FUNCTION__));
198428d7b3dSmrg
199428d7b3dSmrg#if HAS_PIXMAN_GLYPHS
200428d7b3dSmrg	if (__global_glyph_cache == NULL) {
201428d7b3dSmrg		__global_glyph_cache = pixman_glyph_cache_create();
202428d7b3dSmrg		if (__global_glyph_cache == NULL)
203428d7b3dSmrg			goto bail;
204428d7b3dSmrg	}
205428d7b3dSmrg#endif
206428d7b3dSmrg
207428d7b3dSmrg	sna->render.white_image = pixman_image_create_solid_fill(&white);
208428d7b3dSmrg	if (sna->render.white_image == NULL)
209428d7b3dSmrg		goto bail;
210428d7b3dSmrg
211428d7b3dSmrg	if (!can_render(sna)) {
212428d7b3dSmrg		DBG(("%s: no render acceleration, no render glyph caches\n",
213428d7b3dSmrg		     __FUNCTION__));
214428d7b3dSmrg		return true;
215428d7b3dSmrg	}
216428d7b3dSmrg
217428d7b3dSmrg	if (xf86IsEntityShared(sna->scrn->entityList[0])) {
218428d7b3dSmrg		DBG(("%s: shared GlyphPictures, no render glyph caches\n",
219428d7b3dSmrg		     __FUNCTION__));
220428d7b3dSmrg		return true;
221428d7b3dSmrg	}
222428d7b3dSmrg
223428d7b3dSmrg	for (i = 0; i < ARRAY_SIZE(formats); i++) {
224428d7b3dSmrg		struct sna_glyph_cache *cache = &sna->render.glyph[i];
225428d7b3dSmrg		struct sna_pixmap *priv;
226428d7b3dSmrg		PixmapPtr pixmap;
227428d7b3dSmrg		PicturePtr picture = NULL;
228428d7b3dSmrg		PictFormatPtr pPictFormat;
229428d7b3dSmrg		CARD32 component_alpha;
230428d7b3dSmrg		int depth = PIXMAN_FORMAT_DEPTH(formats[i]);
231428d7b3dSmrg
232428d7b3dSmrg		pPictFormat = PictureMatchFormat(screen, depth, formats[i]);
233428d7b3dSmrg		if (!pPictFormat)
234428d7b3dSmrg			goto bail;
235428d7b3dSmrg
236428d7b3dSmrg		/* Now allocate the pixmap and picture */
237428d7b3dSmrg		pixmap = screen->CreatePixmap(screen,
238428d7b3dSmrg					      CACHE_PICTURE_SIZE,
239428d7b3dSmrg					      CACHE_PICTURE_SIZE,
240428d7b3dSmrg					      depth,
241428d7b3dSmrg					      SNA_CREATE_SCRATCH);
242428d7b3dSmrg		if (!pixmap) {
243428d7b3dSmrg			DBG(("%s: failed to allocate pixmap for Glyph cache\n",
244428d7b3dSmrg			     __FUNCTION__));
245428d7b3dSmrg			goto bail;
246428d7b3dSmrg		}
247428d7b3dSmrg
248428d7b3dSmrg		priv = sna_pixmap(pixmap);
249428d7b3dSmrg		if (priv != NULL) {
250428d7b3dSmrg			/* Prevent the cache from ever being paged out */
251428d7b3dSmrg			assert(priv->gpu_bo);
252428d7b3dSmrg			priv->pinned = PIN_SCANOUT;
253428d7b3dSmrg
254428d7b3dSmrg			component_alpha = NeedsComponent(pPictFormat->format);
255428d7b3dSmrg			picture = CreatePicture(0, &pixmap->drawable, pPictFormat,
256428d7b3dSmrg						CPComponentAlpha, &component_alpha,
257428d7b3dSmrg						serverClient, &error);
258428d7b3dSmrg		}
259428d7b3dSmrg
260428d7b3dSmrg		screen->DestroyPixmap(pixmap);
261428d7b3dSmrg		if (!picture)
262428d7b3dSmrg			goto bail;
263428d7b3dSmrg
264428d7b3dSmrg		ValidatePicture(picture);
265428d7b3dSmrg		assert(picture->pDrawable == &pixmap->drawable);
266428d7b3dSmrg
267428d7b3dSmrg		cache->count = cache->evict = 0;
268428d7b3dSmrg		cache->picture = picture;
269428d7b3dSmrg		cache->glyphs = calloc(sizeof(struct sna_glyph *),
270428d7b3dSmrg				       GLYPH_CACHE_SIZE);
271428d7b3dSmrg		if (!cache->glyphs)
272428d7b3dSmrg			goto bail;
273428d7b3dSmrg
274428d7b3dSmrg		cache->evict = rand() % GLYPH_CACHE_SIZE;
275428d7b3dSmrg	}
276428d7b3dSmrg
277428d7b3dSmrg	sna->render.white_picture =
278428d7b3dSmrg		CreateSolidPicture(0, (xRenderColor *)&white, &error);
279428d7b3dSmrg	if (sna->render.white_picture == NULL)
280428d7b3dSmrg		goto bail;
281428d7b3dSmrg
282428d7b3dSmrg	return true;
283428d7b3dSmrg
284428d7b3dSmrgbail:
285428d7b3dSmrg	sna_glyphs_close(sna);
286428d7b3dSmrg	return false;
287428d7b3dSmrg}
288428d7b3dSmrg
289428d7b3dSmrgstatic void
290428d7b3dSmrgglyph_cache_upload(struct sna_glyph_cache *cache,
291428d7b3dSmrg		   GlyphPtr glyph, PicturePtr glyph_picture,
292428d7b3dSmrg		   int16_t x, int16_t y)
293428d7b3dSmrg{
294428d7b3dSmrg	DBG(("%s: upload glyph %p to cache (%d, %d)x(%d, %d)\n",
295428d7b3dSmrg	     __FUNCTION__,
296428d7b3dSmrg	     glyph, x, y,
297428d7b3dSmrg	     glyph_picture->pDrawable->width,
298428d7b3dSmrg	     glyph_picture->pDrawable->height));
299428d7b3dSmrg	sna_composite(PictOpSrc,
300428d7b3dSmrg		      glyph_picture, 0, cache->picture,
301428d7b3dSmrg		      0, 0,
302428d7b3dSmrg		      0, 0,
303428d7b3dSmrg		      x, y,
304428d7b3dSmrg		      glyph_picture->pDrawable->width,
305428d7b3dSmrg		      glyph_picture->pDrawable->height);
306428d7b3dSmrg}
307428d7b3dSmrg
308428d7b3dSmrgstatic void
309428d7b3dSmrgglyph_extents(int nlist,
310428d7b3dSmrg	      GlyphListPtr list,
311428d7b3dSmrg	      GlyphPtr *glyphs,
312428d7b3dSmrg	      BoxPtr extents)
313428d7b3dSmrg{
314428d7b3dSmrg	int x1, x2, y1, y2;
315428d7b3dSmrg	int x, y;
316428d7b3dSmrg
317428d7b3dSmrg	x1 = y1 = MAXSHORT;
318428d7b3dSmrg	x2 = y2 = MINSHORT;
319428d7b3dSmrg	x = y = 0;
320428d7b3dSmrg	while (nlist--) {
321428d7b3dSmrg		int n = list->len;
322428d7b3dSmrg		x += list->xOff;
323428d7b3dSmrg		y += list->yOff;
324428d7b3dSmrg		list++;
325428d7b3dSmrg		while (n--) {
326428d7b3dSmrg			GlyphPtr glyph = *glyphs++;
327428d7b3dSmrg
328428d7b3dSmrg			if (glyph_valid(glyph)) {
329428d7b3dSmrg				int v;
330428d7b3dSmrg
331428d7b3dSmrg				v = x - glyph->info.x;
332428d7b3dSmrg				if (v < x1)
333428d7b3dSmrg					x1 = v;
334428d7b3dSmrg				v += glyph->info.width;
335428d7b3dSmrg				if (v > x2)
336428d7b3dSmrg					x2 = v;
337428d7b3dSmrg
338428d7b3dSmrg				v = y - glyph->info.y;
339428d7b3dSmrg				if (v < y1)
340428d7b3dSmrg					y1 = v;
341428d7b3dSmrg				v += glyph->info.height;
342428d7b3dSmrg				if (v > y2)
343428d7b3dSmrg					y2 = v;
344428d7b3dSmrg			}
345428d7b3dSmrg
346428d7b3dSmrg			x += glyph->info.xOff;
347428d7b3dSmrg			y += glyph->info.yOff;
348428d7b3dSmrg		}
349428d7b3dSmrg	}
350428d7b3dSmrg
351428d7b3dSmrg	extents->x1 = x1 > MINSHORT ? x1 : MINSHORT;
352428d7b3dSmrg	extents->y1 = y1 > MINSHORT ? y1 : MINSHORT;
353428d7b3dSmrg	extents->x2 = x2 < MAXSHORT ? x2 : MAXSHORT;
354428d7b3dSmrg	extents->y2 = y2 < MAXSHORT ? y2 : MAXSHORT;
355428d7b3dSmrg}
356428d7b3dSmrg
357428d7b3dSmrg#if HAS_DEBUG_FULL
358428d7b3dSmrgstatic int
359428d7b3dSmrgglyph_count(int nlist,
360428d7b3dSmrg	    GlyphListPtr list)
361428d7b3dSmrg{
362428d7b3dSmrg	int count = 0;
363428d7b3dSmrg	while (nlist--) {
364428d7b3dSmrg		count += list->len;
365428d7b3dSmrg		list++;
366428d7b3dSmrg	}
367428d7b3dSmrg	return count;
368428d7b3dSmrg}
369428d7b3dSmrg#endif
370428d7b3dSmrg
371428d7b3dSmrgstatic inline unsigned int
372428d7b3dSmrgglyph_size_to_count(int size)
373428d7b3dSmrg{
374428d7b3dSmrg	size /= GLYPH_MIN_SIZE;
375428d7b3dSmrg	return size * size;
376428d7b3dSmrg}
377428d7b3dSmrg
378428d7b3dSmrgstatic inline unsigned int
379428d7b3dSmrgglyph_count_to_mask(int count)
380428d7b3dSmrg{
381428d7b3dSmrg	return ~(count - 1);
382428d7b3dSmrg}
383428d7b3dSmrg
384428d7b3dSmrgstatic inline unsigned int
385428d7b3dSmrgglyph_size_to_mask(int size)
386428d7b3dSmrg{
387428d7b3dSmrg	return glyph_count_to_mask(glyph_size_to_count(size));
388428d7b3dSmrg}
389428d7b3dSmrg
390428d7b3dSmrgstatic int
391428d7b3dSmrgglyph_cache(ScreenPtr screen,
392428d7b3dSmrg	    struct sna_render *render,
393428d7b3dSmrg	    GlyphPtr glyph)
394428d7b3dSmrg{
395428d7b3dSmrg	PicturePtr glyph_picture;
396428d7b3dSmrg	struct sna_glyph_cache *cache;
397428d7b3dSmrg	struct sna_glyph *p;
398428d7b3dSmrg	int size, mask, pos, s;
399428d7b3dSmrg
400428d7b3dSmrg	assert(glyph_valid(glyph));
401428d7b3dSmrg
402428d7b3dSmrg	glyph_picture = GetGlyphPicture(glyph, screen);
403428d7b3dSmrg	if (unlikely(glyph_picture == NULL)) {
404428d7b3dSmrg		glyph->info.width = glyph->info.height = 0;
405428d7b3dSmrg		return false;
406428d7b3dSmrg	}
407428d7b3dSmrg
408428d7b3dSmrg	if (NO_GLYPH_CACHE ||
409428d7b3dSmrg	    glyph->info.width > GLYPH_MAX_SIZE ||
410428d7b3dSmrg	    glyph->info.height > GLYPH_MAX_SIZE) {
411428d7b3dSmrg		PixmapPtr pixmap = (PixmapPtr)glyph_picture->pDrawable;
412428d7b3dSmrg		assert(glyph_picture->pDrawable->type == DRAWABLE_PIXMAP);
413428d7b3dSmrg		if (pixmap->drawable.depth >= 8) {
414428d7b3dSmrg			pixmap->usage_hint = 0;
415428d7b3dSmrg			sna_pixmap_force_to_gpu(pixmap, MOVE_READ);
416428d7b3dSmrg		}
417428d7b3dSmrg
418428d7b3dSmrg		/* no cache for this glyph */
419428d7b3dSmrg		p = sna_glyph(glyph);
420428d7b3dSmrg		p->atlas = glyph_picture;
421428d7b3dSmrg		p->coordinate.x = p->coordinate.y = 0;
422428d7b3dSmrg		return true;
423428d7b3dSmrg	}
424428d7b3dSmrg
425428d7b3dSmrg	for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2)
426428d7b3dSmrg		if (glyph->info.width <= size && glyph->info.height <= size)
427428d7b3dSmrg			break;
428428d7b3dSmrg
429428d7b3dSmrg	cache = &render->glyph[PICT_FORMAT_RGB(glyph_picture->format) != 0];
430428d7b3dSmrg	s = glyph_size_to_count(size);
431428d7b3dSmrg	mask = glyph_count_to_mask(s);
432428d7b3dSmrg	pos = (cache->count + s - 1) & mask;
433428d7b3dSmrg	if (pos < GLYPH_CACHE_SIZE) {
434428d7b3dSmrg		cache->count = pos + s;
435428d7b3dSmrg	} else {
436428d7b3dSmrg		p = NULL;
437428d7b3dSmrg		for (s = size; s <= GLYPH_MAX_SIZE; s *= 2) {
438428d7b3dSmrg			int i = cache->evict & glyph_size_to_mask(s);
439428d7b3dSmrg			p = cache->glyphs[i];
440428d7b3dSmrg			if (p == NULL)
441428d7b3dSmrg				continue;
442428d7b3dSmrg
443428d7b3dSmrg			if (p->size >= s) {
444428d7b3dSmrg				cache->glyphs[i] = NULL;
445428d7b3dSmrg				p->atlas = NULL;
446428d7b3dSmrg				pos = i;
447428d7b3dSmrg			} else
448428d7b3dSmrg				p = NULL;
449428d7b3dSmrg			break;
450428d7b3dSmrg		}
451428d7b3dSmrg		if (p == NULL) {
452428d7b3dSmrg			int count = glyph_size_to_count(size);
453428d7b3dSmrg			pos = cache->evict & glyph_count_to_mask(count);
454428d7b3dSmrg			for (s = 0; s < count; s++) {
455428d7b3dSmrg				p = cache->glyphs[pos + s];
456428d7b3dSmrg				if (p != NULL) {
457428d7b3dSmrg					p->atlas =NULL;
458428d7b3dSmrg					cache->glyphs[pos + s] = NULL;
459428d7b3dSmrg				}
460428d7b3dSmrg			}
461428d7b3dSmrg		}
462428d7b3dSmrg
463428d7b3dSmrg		/* And pick a new eviction position */
464428d7b3dSmrg		cache->evict = rand() % GLYPH_CACHE_SIZE;
465428d7b3dSmrg	}
466428d7b3dSmrg	assert(cache->glyphs[pos] == NULL);
467428d7b3dSmrg
468428d7b3dSmrg	p = sna_glyph(glyph);
469428d7b3dSmrg	DBG(("%s(%d): adding glyph to cache %d, pos %d\n",
470428d7b3dSmrg	     __FUNCTION__, screen->myNum,
471428d7b3dSmrg	     PICT_FORMAT_RGB(glyph_picture->format) != 0, pos));
472428d7b3dSmrg	cache->glyphs[pos] = p;
473428d7b3dSmrg	p->atlas = cache->picture;
474428d7b3dSmrg	p->size = size;
475428d7b3dSmrg	p->pos = pos << 1 | (PICT_FORMAT_RGB(glyph_picture->format) != 0);
476428d7b3dSmrg	s = pos / ((GLYPH_MAX_SIZE / GLYPH_MIN_SIZE) * (GLYPH_MAX_SIZE / GLYPH_MIN_SIZE));
477428d7b3dSmrg	p->coordinate.x = s % (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE) * GLYPH_MAX_SIZE;
478428d7b3dSmrg	p->coordinate.y = (s / (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE)) * GLYPH_MAX_SIZE;
479428d7b3dSmrg	for (s = GLYPH_MIN_SIZE; s < GLYPH_MAX_SIZE; s *= 2) {
480428d7b3dSmrg		if (pos & 1)
481428d7b3dSmrg			p->coordinate.x += s;
482428d7b3dSmrg		if (pos & 2)
483428d7b3dSmrg			p->coordinate.y += s;
484428d7b3dSmrg		pos >>= 2;
485428d7b3dSmrg	}
486428d7b3dSmrg
487428d7b3dSmrg	glyph_cache_upload(cache, glyph, glyph_picture,
488428d7b3dSmrg			   p->coordinate.x, p->coordinate.y);
489428d7b3dSmrg
490428d7b3dSmrg	return true;
491428d7b3dSmrg}
492428d7b3dSmrg
493428d7b3dSmrgstatic void apply_damage(struct sna_composite_op *op,
494428d7b3dSmrg			 const struct sna_composite_rectangles *r)
495428d7b3dSmrg{
496428d7b3dSmrg	BoxRec box;
497428d7b3dSmrg
498428d7b3dSmrg	if (op->damage == NULL)
499428d7b3dSmrg		return;
500428d7b3dSmrg
501428d7b3dSmrg	box.x1 = r->dst.x + op->dst.x;
502428d7b3dSmrg	box.y1 = r->dst.y + op->dst.y;
503428d7b3dSmrg	box.x2 = box.x1 + r->width;
504428d7b3dSmrg	box.y2 = box.y1 + r->height;
505428d7b3dSmrg
506428d7b3dSmrg	assert_pixmap_contains_box(op->dst.pixmap, &box);
507428d7b3dSmrg	sna_damage_add_box(op->damage, &box);
508428d7b3dSmrg}
509428d7b3dSmrg
510428d7b3dSmrgstatic void apply_damage_clipped_to_dst(struct sna_composite_op *op,
511428d7b3dSmrg					const struct sna_composite_rectangles *r,
512428d7b3dSmrg					DrawablePtr dst)
513428d7b3dSmrg{
514428d7b3dSmrg	BoxRec box;
515428d7b3dSmrg
516428d7b3dSmrg	if (op->damage == NULL)
517428d7b3dSmrg		return;
518428d7b3dSmrg
519428d7b3dSmrg	box.x1 = r->dst.x + op->dst.x;
520428d7b3dSmrg	box.y1 = r->dst.y + op->dst.y;
521428d7b3dSmrg	box.x2 = box.x1 + r->width;
522428d7b3dSmrg	box.y2 = box.y1 + r->height;
523428d7b3dSmrg
524428d7b3dSmrg	if (box.x1 < dst->x)
525428d7b3dSmrg		box.x1 = dst->x;
526428d7b3dSmrg
527428d7b3dSmrg	if (box.x2 > op->dst.width)
528428d7b3dSmrg		box.x2 = op->dst.width;
529428d7b3dSmrg
530428d7b3dSmrg	if (box.y1 < dst->y)
531428d7b3dSmrg		box.y1 = dst->y;
532428d7b3dSmrg
533428d7b3dSmrg	if (box.y2 > op->dst.height)
534428d7b3dSmrg		box.y2 = op->dst.height;
535428d7b3dSmrg
536428d7b3dSmrg	assert_pixmap_contains_box(op->dst.pixmap, &box);
537428d7b3dSmrg	sna_damage_add_box(op->damage, &box);
538428d7b3dSmrg}
539428d7b3dSmrg
540428d7b3dSmrgstatic inline bool region_matches_pixmap(const RegionRec *r, PixmapPtr pixmap)
541428d7b3dSmrg{
542428d7b3dSmrg	return (r->extents.x2 - r->extents.x1 >= pixmap->drawable.width &&
543428d7b3dSmrg		r->extents.y2 - r->extents.y1 >= pixmap->drawable.height);
544428d7b3dSmrg}
545428d7b3dSmrg
546428d7b3dSmrgstatic inline bool clipped_glyphs(PicturePtr dst, int nlist, GlyphListPtr list, GlyphPtr *glyphs)
547428d7b3dSmrg{
548428d7b3dSmrg	BoxRec box;
549428d7b3dSmrg
550428d7b3dSmrg	if (dst->pCompositeClip->data == NULL &&
551428d7b3dSmrg	    region_matches_pixmap(dst->pCompositeClip,
552428d7b3dSmrg				  get_drawable_pixmap(dst->pDrawable))) {
553428d7b3dSmrg		DBG(("%s: no, clip region (%d, %d), (%d, %d) matches drawable pixmap=%ld size=%dx%d\n",
554428d7b3dSmrg		     __FUNCTION__,
555428d7b3dSmrg		     dst->pCompositeClip->extents.x1,
556428d7b3dSmrg		     dst->pCompositeClip->extents.y1,
557428d7b3dSmrg		     dst->pCompositeClip->extents.x2,
558428d7b3dSmrg		     dst->pCompositeClip->extents.y2,
559428d7b3dSmrg		     get_drawable_pixmap(dst->pDrawable),
560428d7b3dSmrg		     get_drawable_pixmap(dst->pDrawable)->drawable.width,
561428d7b3dSmrg		     get_drawable_pixmap(dst->pDrawable)->drawable.height));
562428d7b3dSmrg		return false;
563428d7b3dSmrg	}
564428d7b3dSmrg
565428d7b3dSmrg	glyph_extents(nlist, list, glyphs, &box);
566428d7b3dSmrg
567428d7b3dSmrg	box.x1 += dst->pDrawable->x;
568428d7b3dSmrg	box.x2 += dst->pDrawable->x;
569428d7b3dSmrg	box.y1 += dst->pDrawable->y;
570428d7b3dSmrg	box.y2 += dst->pDrawable->y;
571428d7b3dSmrg
572428d7b3dSmrg	DBG(("%s? %d glyph in %d lists extents (%d, %d), (%d, %d), region (%d, %d), (%d, %d): %s\n",
573428d7b3dSmrg	     __FUNCTION__, glyph_count(nlist, list), nlist, box.x1, box.y1, box.x2, box.y2,
574428d7b3dSmrg	     dst->pCompositeClip->extents.x1, dst->pCompositeClip->extents.y1,
575428d7b3dSmrg	     dst->pCompositeClip->extents.x2, dst->pCompositeClip->extents.y2,
576428d7b3dSmrg	     pixman_region_contains_rectangle(dst->pCompositeClip,
577428d7b3dSmrg					      &box) != PIXMAN_REGION_IN ?  "yes" : "no"));
578428d7b3dSmrg
579428d7b3dSmrg	return pixman_region_contains_rectangle(dst->pCompositeClip,
580428d7b3dSmrg						&box) != PIXMAN_REGION_IN;
581428d7b3dSmrg}
582428d7b3dSmrg
583428d7b3dSmrgflatten static bool
584428d7b3dSmrgglyphs_to_dst(struct sna *sna,
585428d7b3dSmrg	      CARD8 op,
586428d7b3dSmrg	      PicturePtr src,
587428d7b3dSmrg	      PicturePtr dst,
588428d7b3dSmrg	      INT16 src_x, INT16 src_y,
589428d7b3dSmrg	      int nlist, GlyphListPtr list, GlyphPtr *glyphs)
590428d7b3dSmrg{
591428d7b3dSmrg	struct sna_composite_op tmp;
592428d7b3dSmrg	ScreenPtr screen = dst->pDrawable->pScreen;
593428d7b3dSmrg	PicturePtr glyph_atlas;
594428d7b3dSmrg	const BoxRec *rects;
595428d7b3dSmrg	int nrect;
596428d7b3dSmrg	int16_t x, y;
597428d7b3dSmrg
598428d7b3dSmrg	if (NO_GLYPHS_TO_DST)
599428d7b3dSmrg		return false;
600428d7b3dSmrg
601428d7b3dSmrg	memset(&tmp, 0, sizeof(tmp));
602428d7b3dSmrg
603428d7b3dSmrg	DBG(("%s(op=%d, src=(%d, %d), nlist=%d,  dst=(%d, %d)+(%d, %d))\n",
604428d7b3dSmrg	     __FUNCTION__, op, src_x, src_y, nlist,
605428d7b3dSmrg	     list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y));
606428d7b3dSmrg
607428d7b3dSmrg	if (clipped_glyphs(dst, nlist, list, glyphs)) {
608428d7b3dSmrg		rects = region_rects(dst->pCompositeClip);
609428d7b3dSmrg		nrect = region_num_rects(dst->pCompositeClip);
610428d7b3dSmrg	} else
611428d7b3dSmrg		nrect = 0;
612428d7b3dSmrg
613428d7b3dSmrg	x = dst->pDrawable->x;
614428d7b3dSmrg	y = dst->pDrawable->y;
615428d7b3dSmrg	src_x -= list->xOff + x;
616428d7b3dSmrg	src_y -= list->yOff + y;
617428d7b3dSmrg
618428d7b3dSmrg	glyph_atlas = NO_ATLAS;
619428d7b3dSmrg	while (nlist--) {
620428d7b3dSmrg		int n = list->len;
621428d7b3dSmrg		x += list->xOff;
622428d7b3dSmrg		y += list->yOff;
623428d7b3dSmrg		while (n--) {
624428d7b3dSmrg			GlyphPtr glyph = *glyphs++;
625428d7b3dSmrg			struct sna_glyph *p;
626428d7b3dSmrg			int i;
627428d7b3dSmrg
628428d7b3dSmrg			p = sna_glyph(glyph);
629428d7b3dSmrg			if (unlikely(p->atlas != glyph_atlas)) {
630428d7b3dSmrg				if (unlikely(!glyph_valid(glyph)))
631428d7b3dSmrg					goto next_glyph;
632428d7b3dSmrg
633428d7b3dSmrg				if (glyph_atlas != NO_ATLAS) {
634428d7b3dSmrg					tmp.done(sna, &tmp);
635428d7b3dSmrg					glyph_atlas = NO_ATLAS;
636428d7b3dSmrg				}
637428d7b3dSmrg
638428d7b3dSmrg				if (p->atlas == NULL &&
639428d7b3dSmrg				    !glyph_cache(screen, &sna->render, glyph))
640428d7b3dSmrg					goto next_glyph;
641428d7b3dSmrg
642428d7b3dSmrg				if (!sna->render.composite(sna,
643428d7b3dSmrg							   op, src, p->atlas, dst,
644428d7b3dSmrg							   0, 0, 0, 0, 0, 0,
645428d7b3dSmrg							   0, 0,
646428d7b3dSmrg							   COMPOSITE_PARTIAL, &tmp))
647428d7b3dSmrg					return false;
648428d7b3dSmrg
649428d7b3dSmrg				glyph_atlas = p->atlas;
650428d7b3dSmrg			}
651428d7b3dSmrg
652428d7b3dSmrg			if (nrect) {
653428d7b3dSmrg				int xi = x - glyph->info.x;
654428d7b3dSmrg				int yi = y - glyph->info.y;
655428d7b3dSmrg
656428d7b3dSmrg				if (xi < dst->pCompositeClip->extents.x2 &&
657428d7b3dSmrg				    yi < dst->pCompositeClip->extents.y2 &&
658428d7b3dSmrg				    xi + glyph->info.width  > dst->pCompositeClip->extents.x1 &&
659428d7b3dSmrg				    yi + glyph->info.height > dst->pCompositeClip->extents.y1) {
660428d7b3dSmrg					for (i = 0; i < nrect; i++) {
661428d7b3dSmrg						struct sna_composite_rectangles r;
662428d7b3dSmrg						int16_t dx, dy;
663428d7b3dSmrg						int16_t x2, y2;
664428d7b3dSmrg
665428d7b3dSmrg						r.dst.x = xi;
666428d7b3dSmrg						r.dst.y = yi;
667428d7b3dSmrg						x2 = xi + glyph->info.width;
668428d7b3dSmrg						y2 = yi + glyph->info.height;
669428d7b3dSmrg						dx = dy = 0;
670428d7b3dSmrg
671428d7b3dSmrg						DBG(("%s: glyph=(%d, %d), (%d, %d), clip=(%d, %d), (%d, %d)\n",
672428d7b3dSmrg						     __FUNCTION__,
673428d7b3dSmrg						     r.dst.x, r.dst.y, x2, y2,
674428d7b3dSmrg						     rects[i].x1, rects[i].y1,
675428d7b3dSmrg						     rects[i].x2, rects[i].y2));
676428d7b3dSmrg						if (rects[i].y1 >= y2)
677428d7b3dSmrg							break;
678428d7b3dSmrg
679428d7b3dSmrg						if (r.dst.x < rects[i].x1)
680428d7b3dSmrg							dx = rects[i].x1 - r.dst.x, r.dst.x = rects[i].x1;
681428d7b3dSmrg						if (x2 > rects[i].x2)
682428d7b3dSmrg							x2 = rects[i].x2;
683428d7b3dSmrg						if (r.dst.y < rects[i].y1)
684428d7b3dSmrg							dy = rects[i].y1 - r.dst.y, r.dst.y = rects[i].y1;
685428d7b3dSmrg						if (y2 > rects[i].y2)
686428d7b3dSmrg							y2 = rects[i].y2;
687428d7b3dSmrg
688428d7b3dSmrg						assert(dx >= 0 && dy >= 0);
689428d7b3dSmrg
690428d7b3dSmrg						if (r.dst.x < x2 && r.dst.y < y2) {
691428d7b3dSmrg							DBG(("%s: blt=(%d, %d), (%d, %d)\n",
692428d7b3dSmrg							     __FUNCTION__, r.dst.x, r.dst.y, x2, y2));
693428d7b3dSmrg
694428d7b3dSmrg							r.src.x = r.dst.x + src_x;
695428d7b3dSmrg							r.src.y = r.dst.y + src_y;
696428d7b3dSmrg							r.mask.x = dx + p->coordinate.x;
697428d7b3dSmrg							r.mask.y = dy + p->coordinate.y;
698428d7b3dSmrg							r.width  = x2 - r.dst.x;
699428d7b3dSmrg							r.height = y2 - r.dst.y;
700428d7b3dSmrg							tmp.blt(sna, &tmp, &r);
701428d7b3dSmrg							apply_damage(&tmp, &r);
702428d7b3dSmrg						}
703428d7b3dSmrg					}
704428d7b3dSmrg				}
705428d7b3dSmrg			} else {
706428d7b3dSmrg				struct sna_composite_rectangles r;
707428d7b3dSmrg
708428d7b3dSmrg				r.dst.x = x - glyph->info.x;
709428d7b3dSmrg				r.dst.y = y - glyph->info.y;
710428d7b3dSmrg				r.src.x = r.dst.x + src_x;
711428d7b3dSmrg				r.src.y = r.dst.y + src_y;
712428d7b3dSmrg				r.mask = p->coordinate;
713428d7b3dSmrg				glyph_copy_size(&r, glyph);
714428d7b3dSmrg
715428d7b3dSmrg				DBG(("%s: glyph=(%d, %d)x(%d, %d), unclipped\n",
716428d7b3dSmrg				     __FUNCTION__,
717428d7b3dSmrg				     r.dst.x, r.dst.y,
718428d7b3dSmrg				     r.width, r.height));
719428d7b3dSmrg
720428d7b3dSmrg				tmp.blt(sna, &tmp, &r);
721428d7b3dSmrg				apply_damage_clipped_to_dst(&tmp, &r, dst->pDrawable);
722428d7b3dSmrg			}
723428d7b3dSmrg
724428d7b3dSmrgnext_glyph:
725428d7b3dSmrg			x += glyph->info.xOff;
726428d7b3dSmrg			y += glyph->info.yOff;
727428d7b3dSmrg		}
728428d7b3dSmrg		list++;
729428d7b3dSmrg	}
730428d7b3dSmrg	if (glyph_atlas != NO_ATLAS)
731428d7b3dSmrg		tmp.done(sna, &tmp);
732428d7b3dSmrg
733428d7b3dSmrg	return true;
734428d7b3dSmrg}
735428d7b3dSmrg
736428d7b3dSmrgflatten static bool
737428d7b3dSmrgglyphs0_to_dst(struct sna *sna,
738428d7b3dSmrg	       CARD8 op,
739428d7b3dSmrg	       PicturePtr src,
740428d7b3dSmrg	       PicturePtr dst,
741428d7b3dSmrg	       INT16 src_x, INT16 src_y,
742428d7b3dSmrg	       int nlist, GlyphListPtr list, GlyphPtr *glyphs)
743428d7b3dSmrg{
744428d7b3dSmrg	struct sna_composite_op tmp;
745428d7b3dSmrg	ScreenPtr screen = dst->pDrawable->pScreen;
746428d7b3dSmrg	PicturePtr glyph_atlas = NO_ATLAS;
747428d7b3dSmrg	int x, y;
748428d7b3dSmrg
749428d7b3dSmrg	if (NO_GLYPHS_TO_DST)
750428d7b3dSmrg		return false;
751428d7b3dSmrg
752428d7b3dSmrg	memset(&tmp, 0, sizeof(tmp));
753428d7b3dSmrg
754428d7b3dSmrg	DBG(("%s(op=%d, src=(%d, %d), nlist=%d,  dst=(%d, %d)+(%d, %d))\n",
755428d7b3dSmrg	     __FUNCTION__, op, src_x, src_y, nlist,
756428d7b3dSmrg	     list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y));
757428d7b3dSmrg
758428d7b3dSmrg	x = dst->pDrawable->x;
759428d7b3dSmrg	y = dst->pDrawable->y;
760428d7b3dSmrg	src_x -= list->xOff + x;
761428d7b3dSmrg	src_y -= list->yOff + y;
762428d7b3dSmrg
763428d7b3dSmrg	if (clipped_glyphs(dst, nlist, list, glyphs)) {
764428d7b3dSmrg		const BoxRec *rects = region_rects(dst->pCompositeClip);
765428d7b3dSmrg		int nrect = region_num_rects(dst->pCompositeClip);
766428d7b3dSmrg		if (nrect == 0)
767428d7b3dSmrg			return true;
768428d7b3dSmrg
769428d7b3dSmrg		while (nlist--) {
770428d7b3dSmrg			int n = list->len;
771428d7b3dSmrg			x += list->xOff;
772428d7b3dSmrg			y += list->yOff;
773428d7b3dSmrg			while (n--) {
774428d7b3dSmrg				GlyphPtr glyph = *glyphs++;
775428d7b3dSmrg				struct sna_glyph *p = sna_glyph0(glyph);
776428d7b3dSmrg				int i, xi, yi;
777428d7b3dSmrg
778428d7b3dSmrg				if (unlikely(p->atlas != glyph_atlas)) {
779428d7b3dSmrg					if (unlikely(!glyph_valid(glyph)))
780428d7b3dSmrg						goto next_glyph_N;
781428d7b3dSmrg
782428d7b3dSmrg					if (glyph_atlas != NO_ATLAS) {
783428d7b3dSmrg						tmp.done(sna, &tmp);
784428d7b3dSmrg						glyph_atlas = NO_ATLAS;
785428d7b3dSmrg					}
786428d7b3dSmrg
787428d7b3dSmrg					if (unlikely(p->atlas == NULL)) {
788428d7b3dSmrg						if (!glyph_cache(screen, &sna->render, glyph))
789428d7b3dSmrg							goto next_glyph_N;
790428d7b3dSmrg					}
791428d7b3dSmrg
792428d7b3dSmrg					if (!sna->render.composite(sna,
793428d7b3dSmrg								   op, src, p->atlas, dst,
794428d7b3dSmrg								   0, 0, 0, 0, 0, 0,
795428d7b3dSmrg								   0, 0,
796428d7b3dSmrg								   COMPOSITE_PARTIAL, &tmp))
797428d7b3dSmrg						return false;
798428d7b3dSmrg
799428d7b3dSmrg					glyph_atlas = p->atlas;
800428d7b3dSmrg				}
801428d7b3dSmrg
802428d7b3dSmrg				xi = x - glyph->info.x;
803428d7b3dSmrg				yi = y - glyph->info.y;
804428d7b3dSmrg
805428d7b3dSmrg				if (xi < dst->pCompositeClip->extents.x2 &&
806428d7b3dSmrg				    yi < dst->pCompositeClip->extents.y2 &&
807428d7b3dSmrg				    xi + glyph->info.width  > dst->pCompositeClip->extents.x1 &&
808428d7b3dSmrg				    yi + glyph->info.height > dst->pCompositeClip->extents.y1) {
809428d7b3dSmrg					for (i = 0; i < nrect; i++) {
810428d7b3dSmrg						struct sna_composite_rectangles r;
811428d7b3dSmrg						int16_t dx, dy;
812428d7b3dSmrg						int16_t x2, y2;
813428d7b3dSmrg
814428d7b3dSmrg						r.dst.x = xi;
815428d7b3dSmrg						r.dst.y = yi;
816428d7b3dSmrg						x2 = xi + glyph->info.width;
817428d7b3dSmrg						y2 = yi + glyph->info.height;
818428d7b3dSmrg						dx = dy = 0;
819428d7b3dSmrg
820428d7b3dSmrg						DBG(("%s: glyph=(%d, %d), (%d, %d), clip=(%d, %d), (%d, %d)\n",
821428d7b3dSmrg						     __FUNCTION__,
822428d7b3dSmrg						     r.dst.x, r.dst.y, x2, y2,
823428d7b3dSmrg						     rects[i].x1, rects[i].y1,
824428d7b3dSmrg						     rects[i].x2, rects[i].y2));
825428d7b3dSmrg						if (rects[i].y1 >= y2)
826428d7b3dSmrg							break;
827428d7b3dSmrg
828428d7b3dSmrg						if (r.dst.x < rects[i].x1)
829428d7b3dSmrg							dx = rects[i].x1 - r.dst.x, r.dst.x = rects[i].x1;
830428d7b3dSmrg						if (x2 > rects[i].x2)
831428d7b3dSmrg							x2 = rects[i].x2;
832428d7b3dSmrg						if (r.dst.y < rects[i].y1)
833428d7b3dSmrg							dy = rects[i].y1 - r.dst.y, r.dst.y = rects[i].y1;
834428d7b3dSmrg						if (y2 > rects[i].y2)
835428d7b3dSmrg							y2 = rects[i].y2;
836428d7b3dSmrg
837428d7b3dSmrg						assert(dx >= 0 && dy >= 0);
838428d7b3dSmrg
839428d7b3dSmrg						if (r.dst.x < x2 && r.dst.y < y2) {
840428d7b3dSmrg							DBG(("%s: blt=(%d, %d), (%d, %d)\n",
841428d7b3dSmrg							     __FUNCTION__, r.dst.x, r.dst.y, x2, y2));
842428d7b3dSmrg
843428d7b3dSmrg							r.src.x = r.dst.x + src_x;
844428d7b3dSmrg							r.src.y = r.dst.y + src_y;
845428d7b3dSmrg							r.mask.x = dx + p->coordinate.x;
846428d7b3dSmrg							r.mask.y = dy + p->coordinate.y;
847428d7b3dSmrg							r.width  = x2 - r.dst.x;
848428d7b3dSmrg							r.height = y2 - r.dst.y;
849428d7b3dSmrg							tmp.blt(sna, &tmp, &r);
850428d7b3dSmrg							apply_damage(&tmp, &r);
851428d7b3dSmrg						}
852428d7b3dSmrg					}
853428d7b3dSmrg				}
854428d7b3dSmrg
855428d7b3dSmrgnext_glyph_N:
856428d7b3dSmrg				x += glyph->info.xOff;
857428d7b3dSmrg				y += glyph->info.yOff;
858428d7b3dSmrg			}
859428d7b3dSmrg			list++;
860428d7b3dSmrg		}
861428d7b3dSmrg	} else while (nlist--) {
862428d7b3dSmrg		int n = list->len;
863428d7b3dSmrg		x += list->xOff;
864428d7b3dSmrg		y += list->yOff;
865428d7b3dSmrg		while (n--) {
866428d7b3dSmrg			GlyphPtr glyph = *glyphs++;
867428d7b3dSmrg			struct sna_glyph *p = sna_glyph0(glyph);
868428d7b3dSmrg			struct sna_composite_rectangles r;
869428d7b3dSmrg
870428d7b3dSmrg			if (unlikely(p->atlas != glyph_atlas)) {
871428d7b3dSmrg				if (unlikely(!glyph_valid(glyph)))
872428d7b3dSmrg					goto next_glyph_0;
873428d7b3dSmrg
874428d7b3dSmrg				if (glyph_atlas != NO_ATLAS) {
875428d7b3dSmrg					tmp.done(sna, &tmp);
876428d7b3dSmrg					glyph_atlas = NO_ATLAS;
877428d7b3dSmrg				}
878428d7b3dSmrg
879428d7b3dSmrg				if (unlikely(p->atlas == NULL)) {
880428d7b3dSmrg					if (!glyph_cache(screen, &sna->render, glyph))
881428d7b3dSmrg						goto next_glyph_0;
882428d7b3dSmrg				}
883428d7b3dSmrg
884428d7b3dSmrg				if (!sna->render.composite(sna,
885428d7b3dSmrg							   op, src, p->atlas, dst,
886428d7b3dSmrg							   0, 0, 0, 0, 0, 0,
887428d7b3dSmrg							   0, 0,
888428d7b3dSmrg							   COMPOSITE_PARTIAL, &tmp))
889428d7b3dSmrg					return false;
890428d7b3dSmrg
891428d7b3dSmrg				glyph_atlas = p->atlas;
892428d7b3dSmrg			}
893428d7b3dSmrg
894428d7b3dSmrg			r.dst.x = x - glyph->info.x;
895428d7b3dSmrg			r.dst.y = y - glyph->info.y;
896428d7b3dSmrg			r.src.x = r.dst.x + src_x;
897428d7b3dSmrg			r.src.y = r.dst.y + src_y;
898428d7b3dSmrg			r.mask = p->coordinate;
899428d7b3dSmrg			glyph_copy_size(&r, glyph);
900428d7b3dSmrg
901428d7b3dSmrg			DBG(("%s: glyph=(%d, %d)x(%d, %d), unclipped\n",
902428d7b3dSmrg			     __FUNCTION__,
903428d7b3dSmrg			     r.dst.x, r.dst.y,
904428d7b3dSmrg			     r.width, r.height));
905428d7b3dSmrg
906428d7b3dSmrg			tmp.blt(sna, &tmp, &r);
907428d7b3dSmrg			apply_damage_clipped_to_dst(&tmp, &r, dst->pDrawable);
908428d7b3dSmrg
909428d7b3dSmrgnext_glyph_0:
910428d7b3dSmrg			x += glyph->info.xOff;
911428d7b3dSmrg			y += glyph->info.yOff;
912428d7b3dSmrg		}
913428d7b3dSmrg		list++;
914428d7b3dSmrg	}
915428d7b3dSmrg	if (glyph_atlas != NO_ATLAS)
916428d7b3dSmrg		tmp.done(sna, &tmp);
917428d7b3dSmrg
918428d7b3dSmrg	return true;
919428d7b3dSmrg}
920428d7b3dSmrg
921428d7b3dSmrgstatic bool
922428d7b3dSmrgglyphs_slow(struct sna *sna,
923428d7b3dSmrg	    CARD8 op,
924428d7b3dSmrg	    PicturePtr src,
925428d7b3dSmrg	    PicturePtr dst,
926428d7b3dSmrg	    INT16 src_x, INT16 src_y,
927428d7b3dSmrg	    int nlist, GlyphListPtr list, GlyphPtr *glyphs)
928428d7b3dSmrg{
929428d7b3dSmrg	struct sna_composite_op tmp;
930428d7b3dSmrg	ScreenPtr screen = dst->pDrawable->pScreen;
931428d7b3dSmrg	int16_t x, y;
932428d7b3dSmrg
933428d7b3dSmrg	if (NO_GLYPHS_SLOW)
934428d7b3dSmrg		return false;
935428d7b3dSmrg
936428d7b3dSmrg	DBG(("%s(op=%d, src=(%d, %d), nlist=%d,  dst=(%d, %d)+(%d, %d))\n",
937428d7b3dSmrg	     __FUNCTION__, op, src_x, src_y, nlist,
938428d7b3dSmrg	     list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y));
939428d7b3dSmrg
940428d7b3dSmrg	x = dst->pDrawable->x;
941428d7b3dSmrg	y = dst->pDrawable->y;
942428d7b3dSmrg	src_x -= list->xOff + x;
943428d7b3dSmrg	src_y -= list->yOff + y;
944428d7b3dSmrg
945428d7b3dSmrg	while (nlist--) {
946428d7b3dSmrg		int n = list->len;
947428d7b3dSmrg		x += list->xOff;
948428d7b3dSmrg		y += list->yOff;
949428d7b3dSmrg		while (n--) {
950428d7b3dSmrg			GlyphPtr glyph = *glyphs++;
951428d7b3dSmrg			struct sna_glyph *p;
952428d7b3dSmrg			const BoxRec *rects;
953428d7b3dSmrg			BoxRec box;
954428d7b3dSmrg			int nrect;
955428d7b3dSmrg
956428d7b3dSmrg			box.x1 = x - glyph->info.x;
957428d7b3dSmrg			box.y1 = y - glyph->info.y;
958428d7b3dSmrg			box.x2 = bound(box.x1, glyph->info.width);
959428d7b3dSmrg			box.y2 = bound(box.y1, glyph->info.height);
960428d7b3dSmrg
961428d7b3dSmrg			if (!box_intersect(&box,
962428d7b3dSmrg					   &dst->pCompositeClip->extents))
963428d7b3dSmrg				goto next_glyph;
964428d7b3dSmrg
965428d7b3dSmrg			p = sna_glyph(glyph);
966428d7b3dSmrg			if (unlikely(p->atlas == NULL)) {
967428d7b3dSmrg				if (unlikely(!glyph_valid(glyph)))
968428d7b3dSmrg					goto next_glyph;
969428d7b3dSmrg
970428d7b3dSmrg				if (!glyph_cache(screen, &sna->render, glyph))
971428d7b3dSmrg					goto next_glyph;
972428d7b3dSmrg			}
973428d7b3dSmrg
974428d7b3dSmrg			DBG(("%s: glyph=(%d, %d)x(%d, %d), src=(%d, %d), mask=(%d, %d)\n",
975428d7b3dSmrg			     __FUNCTION__,
976428d7b3dSmrg			     x - glyph->info.x,
977428d7b3dSmrg			     y - glyph->info.y,
978428d7b3dSmrg			     glyph->info.width,
979428d7b3dSmrg			     glyph->info.height,
980428d7b3dSmrg			     src_x + x - glyph->info.x,
981428d7b3dSmrg			     src_y + y - glyph->info.y,
982428d7b3dSmrg			     p->coordinate.x, p->coordinate.y));
983428d7b3dSmrg
984428d7b3dSmrg			if (!sna->render.composite(sna,
985428d7b3dSmrg						   op, src, p->atlas, dst,
986428d7b3dSmrg						   src_x + x - glyph->info.x,
987428d7b3dSmrg						   src_y + y - glyph->info.y,
988428d7b3dSmrg						   p->coordinate.x, p->coordinate.y,
989428d7b3dSmrg						   x - glyph->info.x,
990428d7b3dSmrg						   y - glyph->info.y,
991428d7b3dSmrg						   glyph->info.width,
992428d7b3dSmrg						   glyph->info.height,
993428d7b3dSmrg						   COMPOSITE_PARTIAL, memset(&tmp, 0, sizeof(tmp))))
994428d7b3dSmrg				return false;
995428d7b3dSmrg
996428d7b3dSmrg			rects = region_rects(dst->pCompositeClip);
997428d7b3dSmrg			nrect = region_num_rects(dst->pCompositeClip);
998428d7b3dSmrg			do {
999428d7b3dSmrg				struct sna_composite_rectangles r;
1000428d7b3dSmrg				int16_t x2, y2;
1001428d7b3dSmrg
1002428d7b3dSmrg				r.dst.x = x - glyph->info.x;
1003428d7b3dSmrg				r.dst.y = y - glyph->info.y;
1004428d7b3dSmrg				x2 = r.dst.x + glyph->info.width;
1005428d7b3dSmrg				y2 = r.dst.y + glyph->info.height;
1006428d7b3dSmrg
1007428d7b3dSmrg				DBG(("%s: glyph=(%d, %d), (%d, %d), clip=(%d, %d), (%d, %d)\n",
1008428d7b3dSmrg				     __FUNCTION__,
1009428d7b3dSmrg				     r.dst.x, r.dst.y, x2, y2,
1010428d7b3dSmrg				     rects->x1, rects->y1,
1011428d7b3dSmrg				     rects->x2, rects->y2));
1012428d7b3dSmrg				if (rects->y1 >= y2)
1013428d7b3dSmrg					break;
1014428d7b3dSmrg
1015428d7b3dSmrg				if (r.dst.x < rects->x1)
1016428d7b3dSmrg					r.dst.x = rects->x1;
1017428d7b3dSmrg				if (x2 > rects->x2)
1018428d7b3dSmrg					x2 = rects->x2;
1019428d7b3dSmrg
1020428d7b3dSmrg				if (r.dst.y < rects->y1)
1021428d7b3dSmrg					r.dst.y = rects->y1;
1022428d7b3dSmrg				if (y2 > rects->y2)
1023428d7b3dSmrg					y2 = rects->y2;
1024428d7b3dSmrg
1025428d7b3dSmrg				if (r.dst.x < x2 && r.dst.y < y2) {
1026428d7b3dSmrg					DBG(("%s: blt=(%d, %d), (%d, %d)\n",
1027428d7b3dSmrg					     __FUNCTION__, r.dst.x, r.dst.y, x2, y2));
1028428d7b3dSmrg					r.width  = x2 - r.dst.x;
1029428d7b3dSmrg					r.height = y2 - r.dst.y;
1030428d7b3dSmrg					r.src = r.mask = r .dst;
1031428d7b3dSmrg					tmp.blt(sna, &tmp, &r);
1032428d7b3dSmrg					apply_damage(&tmp, &r);
1033428d7b3dSmrg				}
1034428d7b3dSmrg				rects++;
1035428d7b3dSmrg			} while (--nrect);
1036428d7b3dSmrg			tmp.done(sna, &tmp);
1037428d7b3dSmrg
1038428d7b3dSmrgnext_glyph:
1039428d7b3dSmrg			x += glyph->info.xOff;
1040428d7b3dSmrg			y += glyph->info.yOff;
1041428d7b3dSmrg		}
1042428d7b3dSmrg		list++;
1043428d7b3dSmrg	}
1044428d7b3dSmrg
1045428d7b3dSmrg	return true;
1046428d7b3dSmrg}
1047428d7b3dSmrg
1048428d7b3dSmrgstatic bool
1049428d7b3dSmrgclear_pixmap(struct sna *sna, PixmapPtr pixmap)
1050428d7b3dSmrg{
1051428d7b3dSmrg	struct sna_pixmap *priv = sna_pixmap(pixmap);
1052428d7b3dSmrg	return sna->render.clear(sna, pixmap, priv->gpu_bo);
1053428d7b3dSmrg}
1054428d7b3dSmrg
1055428d7b3dSmrgstatic bool
1056428d7b3dSmrgtoo_large(struct sna *sna, int width, int height)
1057428d7b3dSmrg{
1058428d7b3dSmrg	return (width > sna->render.max_3d_size ||
1059428d7b3dSmrg		height > sna->render.max_3d_size);
1060428d7b3dSmrg}
1061428d7b3dSmrg
1062428d7b3dSmrgstatic pixman_image_t *
1063428d7b3dSmrg__sna_glyph_get_image(GlyphPtr g, ScreenPtr s)
1064428d7b3dSmrg{
1065428d7b3dSmrg	pixman_image_t *image;
1066428d7b3dSmrg	PicturePtr p;
1067428d7b3dSmrg	int dx, dy;
1068428d7b3dSmrg
1069428d7b3dSmrg	DBG(("%s: creating image cache for glyph %p (on screen %d)\n", __FUNCTION__, g, s->myNum));
1070428d7b3dSmrg
1071428d7b3dSmrg	p = GetGlyphPicture(g, s);
1072428d7b3dSmrg	if (unlikely(p == NULL))
1073428d7b3dSmrg		return NULL;
1074428d7b3dSmrg
1075428d7b3dSmrg	image = image_from_pict(p, FALSE, &dx, &dy);
1076428d7b3dSmrg	if (!image)
1077428d7b3dSmrg		return NULL;
1078428d7b3dSmrg
1079428d7b3dSmrg	assert(dx == 0 && dy == 0);
1080428d7b3dSmrg	return sna_glyph(g)->image = image;
1081428d7b3dSmrg}
1082428d7b3dSmrg
1083428d7b3dSmrgstatic inline pixman_image_t *
1084428d7b3dSmrgsna_glyph_get_image(GlyphPtr g, ScreenPtr s)
1085428d7b3dSmrg{
1086428d7b3dSmrg	pixman_image_t *image;
1087428d7b3dSmrg
1088428d7b3dSmrg	image = sna_glyph(g)->image;
1089428d7b3dSmrg	if (image == NULL)
1090428d7b3dSmrg		image = __sna_glyph_get_image(g, s);
1091428d7b3dSmrg
1092428d7b3dSmrg	return image;
1093428d7b3dSmrg}
1094428d7b3dSmrg
1095428d7b3dSmrgstatic inline bool use_small_mask(struct sna *sna, int16_t width, int16_t height, int depth)
1096428d7b3dSmrg{
1097428d7b3dSmrg	if (FORCE_SMALL_MASK)
1098428d7b3dSmrg		return FORCE_SMALL_MASK > 0;
1099428d7b3dSmrg
1100428d7b3dSmrg	if (depth * width * height < 8 * 4096)
1101428d7b3dSmrg		return true;
1102428d7b3dSmrg
1103428d7b3dSmrg	return too_large(sna, width, height);
1104428d7b3dSmrg}
1105428d7b3dSmrg
1106428d7b3dSmrgflatten static bool
1107428d7b3dSmrgglyphs_via_mask(struct sna *sna,
1108428d7b3dSmrg		CARD8 op,
1109428d7b3dSmrg		PicturePtr src,
1110428d7b3dSmrg		PicturePtr dst,
1111428d7b3dSmrg		PictFormatPtr format,
1112428d7b3dSmrg		INT16 src_x, INT16 src_y,
1113428d7b3dSmrg		int nlist, GlyphListPtr list, GlyphPtr *glyphs)
1114428d7b3dSmrg{
1115428d7b3dSmrg	ScreenPtr screen = dst->pDrawable->pScreen;
1116428d7b3dSmrg	CARD32 component_alpha;
1117428d7b3dSmrg	PixmapPtr pixmap;
1118428d7b3dSmrg	PicturePtr mask;
1119428d7b3dSmrg	int16_t x, y, width, height;
1120428d7b3dSmrg	int error;
1121428d7b3dSmrg	bool ret = false;
1122428d7b3dSmrg	BoxRec box;
1123428d7b3dSmrg
1124428d7b3dSmrg	if (NO_GLYPHS_VIA_MASK)
1125428d7b3dSmrg		return false;
1126428d7b3dSmrg
1127428d7b3dSmrg	DBG(("%s(op=%d, src=(%d, %d), nlist=%d,  dst=(%d, %d)+(%d, %d))\n",
1128428d7b3dSmrg	     __FUNCTION__, op, src_x, src_y, nlist,
1129428d7b3dSmrg	     list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y));
1130428d7b3dSmrg
1131428d7b3dSmrg	glyph_extents(nlist, list, glyphs, &box);
1132428d7b3dSmrg	if (box.x2 <= box.x1 || box.y2 <= box.y1)
1133428d7b3dSmrg		return true;
1134428d7b3dSmrg
1135428d7b3dSmrg	DBG(("%s: nlist=%d, count=%d, bounds=((%d, %d), (%d, %d))\n", __FUNCTION__,
1136428d7b3dSmrg	     nlist, glyph_count(nlist, list), box.x1, box.y1, box.x2, box.y2));
1137428d7b3dSmrg
1138428d7b3dSmrg	if (!sna_compute_composite_extents(&box,
1139428d7b3dSmrg					   src, NULL, dst,
1140428d7b3dSmrg					   src_x, src_y,
1141428d7b3dSmrg					   0, 0,
1142428d7b3dSmrg					   box.x1, box.y1,
1143428d7b3dSmrg					   box.x2 - box.x1,
1144428d7b3dSmrg					   box.y2 - box.y1))
1145428d7b3dSmrg		return true;
1146428d7b3dSmrg
1147428d7b3dSmrg	DBG(("%s: extents=((%d, %d), (%d, %d))\n", __FUNCTION__,
1148428d7b3dSmrg	     box.x1, box.y1, box.x2, box.y2));
1149428d7b3dSmrg
1150428d7b3dSmrg	width  = box.x2 - box.x1;
1151428d7b3dSmrg	height = box.y2 - box.y1;
1152428d7b3dSmrg	box.x1 -= dst->pDrawable->x;
1153428d7b3dSmrg	box.y1 -= dst->pDrawable->y;
1154428d7b3dSmrg	x = -box.x1;
1155428d7b3dSmrg	y = -box.y1;
1156428d7b3dSmrg	src_x += box.x1 - list->xOff;
1157428d7b3dSmrg	src_y += box.y1 - list->yOff;
1158428d7b3dSmrg
1159428d7b3dSmrg	if (format->depth < 8) {
1160428d7b3dSmrg		format = PictureMatchFormat(screen, 8, PICT_a8);
1161428d7b3dSmrg		if (!format)
1162428d7b3dSmrg			return false;
1163428d7b3dSmrg	}
1164428d7b3dSmrg
1165428d7b3dSmrg	component_alpha = NeedsComponent(format->format);
1166428d7b3dSmrg	if (use_small_mask(sna, width, height, format->depth)) {
1167428d7b3dSmrg		pixman_image_t *mask_image;
1168428d7b3dSmrg
1169428d7b3dSmrguse_small_mask:
1170428d7b3dSmrg		DBG(("%s: small mask [format=%lx, depth=%d, size=%d], rendering glyphs to upload buffer\n",
1171428d7b3dSmrg		     __FUNCTION__, (unsigned long)format->format,
1172428d7b3dSmrg		     format->depth, (uint32_t)width*height*format->depth));
1173428d7b3dSmrg
1174428d7b3dSmrg		pixmap = sna_pixmap_create_upload(screen,
1175428d7b3dSmrg						  width, height,
1176428d7b3dSmrg						  format->depth,
1177428d7b3dSmrg						  KGEM_BUFFER_WRITE);
1178428d7b3dSmrg		if (!pixmap)
1179428d7b3dSmrg			return false;
1180428d7b3dSmrg
1181428d7b3dSmrg		mask_image =
1182428d7b3dSmrg			pixman_image_create_bits(format->depth << 24 | format->format,
1183428d7b3dSmrg						 width, height,
1184428d7b3dSmrg						 pixmap->devPrivate.ptr,
1185428d7b3dSmrg						 pixmap->devKind);
1186428d7b3dSmrg		if (mask_image == NULL)
1187428d7b3dSmrg			goto err_pixmap;
1188428d7b3dSmrg
1189428d7b3dSmrg		if (sigtrap_get()) {
1190428d7b3dSmrg			pixman_image_unref(mask_image);
1191428d7b3dSmrg			goto err_pixmap;
1192428d7b3dSmrg		}
1193428d7b3dSmrg
1194428d7b3dSmrg		memset(pixmap->devPrivate.ptr, 0, pixmap->devKind*height);
1195428d7b3dSmrg#if HAS_PIXMAN_GLYPHS
1196428d7b3dSmrg		if (__global_glyph_cache) {
1197428d7b3dSmrg			pixman_glyph_t stack_glyphs[N_STACK_GLYPHS];
1198428d7b3dSmrg			pixman_glyph_t *pglyphs = stack_glyphs;
1199428d7b3dSmrg			int count, n;
1200428d7b3dSmrg
1201428d7b3dSmrg			count = 0;
1202428d7b3dSmrg			for (n = 0; n < nlist; ++n)
1203428d7b3dSmrg				count += list[n].len;
1204428d7b3dSmrg			if (count > N_STACK_GLYPHS) {
1205428d7b3dSmrg				pglyphs = malloc (count * sizeof(pixman_glyph_t));
1206428d7b3dSmrg				if (pglyphs == NULL)
1207428d7b3dSmrg					goto err_pixmap;
1208428d7b3dSmrg			}
1209428d7b3dSmrg
1210428d7b3dSmrg			pixman_glyph_cache_freeze(__global_glyph_cache);
1211428d7b3dSmrg			count = 0;
1212428d7b3dSmrg			do {
1213428d7b3dSmrg				n = list->len;
1214428d7b3dSmrg				x += list->xOff;
1215428d7b3dSmrg				y += list->yOff;
1216428d7b3dSmrg				while (n--) {
1217428d7b3dSmrg					GlyphPtr g = *glyphs++;
1218428d7b3dSmrg					const void *ptr;
1219428d7b3dSmrg
1220428d7b3dSmrg					if (!glyph_valid(g))
1221428d7b3dSmrg						goto next_pglyph;
1222428d7b3dSmrg
1223428d7b3dSmrg					ptr = pixman_glyph_cache_lookup(__global_glyph_cache, g, NULL);
1224428d7b3dSmrg					if (ptr == NULL) {
1225428d7b3dSmrg						pixman_image_t *glyph_image;
1226428d7b3dSmrg
1227428d7b3dSmrg						glyph_image = sna_glyph_get_image(g, screen);
1228428d7b3dSmrg						if (glyph_image == NULL)
1229428d7b3dSmrg							goto next_pglyph;
1230428d7b3dSmrg
1231428d7b3dSmrg						DBG(("%s: inserting glyph %p into pixman cache\n", __FUNCTION__, g));
1232428d7b3dSmrg						ptr = pixman_glyph_cache_insert(__global_glyph_cache, g, NULL,
1233428d7b3dSmrg										g->info.x,
1234428d7b3dSmrg										g->info.y,
1235428d7b3dSmrg										glyph_image);
1236428d7b3dSmrg						if (ptr == NULL)
1237428d7b3dSmrg							goto next_pglyph;
1238428d7b3dSmrg					}
1239428d7b3dSmrg
1240428d7b3dSmrg					assert(sna_glyph_get_image(g, screen) != NULL);
1241428d7b3dSmrg
1242428d7b3dSmrg					pglyphs[count].x = x;
1243428d7b3dSmrg					pglyphs[count].y = y;
1244428d7b3dSmrg					pglyphs[count].glyph = ptr;
1245428d7b3dSmrg					count++;
1246428d7b3dSmrg
1247428d7b3dSmrgnext_pglyph:
1248428d7b3dSmrg					x += g->info.xOff;
1249428d7b3dSmrg					y += g->info.yOff;
1250428d7b3dSmrg				}
1251428d7b3dSmrg				list++;
1252428d7b3dSmrg			} while (--nlist);
1253428d7b3dSmrg
1254428d7b3dSmrg			pixman_composite_glyphs_no_mask(PIXMAN_OP_ADD,
1255428d7b3dSmrg							sna->render.white_image,
1256428d7b3dSmrg							mask_image,
1257428d7b3dSmrg							0, 0,
1258428d7b3dSmrg							0, 0,
1259428d7b3dSmrg							__global_glyph_cache, count, pglyphs);
1260428d7b3dSmrg			pixman_glyph_cache_thaw(__global_glyph_cache);
1261428d7b3dSmrg			if (pglyphs != stack_glyphs)
1262428d7b3dSmrg				free(pglyphs);
1263428d7b3dSmrg		} else
1264428d7b3dSmrg#endif
1265428d7b3dSmrg		do {
1266428d7b3dSmrg			int n = list->len;
1267428d7b3dSmrg			x += list->xOff;
1268428d7b3dSmrg			y += list->yOff;
1269428d7b3dSmrg			while (n--) {
1270428d7b3dSmrg				GlyphPtr g = *glyphs++;
1271428d7b3dSmrg				pixman_image_t *glyph_image;
1272428d7b3dSmrg				int16_t xi, yi;
1273428d7b3dSmrg
1274428d7b3dSmrg				if (!glyph_valid(g))
1275428d7b3dSmrg					goto next_image;
1276428d7b3dSmrg
1277428d7b3dSmrg				/* If the mask has been cropped, it is likely
1278428d7b3dSmrg				 * that some of the glyphs fall outside.
1279428d7b3dSmrg				 */
1280428d7b3dSmrg				xi = x - g->info.x;
1281428d7b3dSmrg				yi = y - g->info.y;
1282428d7b3dSmrg				if (xi >= width || yi >= height)
1283428d7b3dSmrg					goto next_image;
1284428d7b3dSmrg				if (xi + g->info.width  <= 0 ||
1285428d7b3dSmrg				    yi + g->info.height <= 0)
1286428d7b3dSmrg					goto next_image;
1287428d7b3dSmrg
1288428d7b3dSmrg				glyph_image =
1289428d7b3dSmrg					sna_glyph_get_image(g, dst->pDrawable->pScreen);
1290428d7b3dSmrg				if (glyph_image == NULL)
1291428d7b3dSmrg					goto next_image;
1292428d7b3dSmrg
1293428d7b3dSmrg				DBG(("%s: glyph to mask (%d, %d)x(%d, %d)\n",
1294428d7b3dSmrg				     __FUNCTION__,
1295428d7b3dSmrg				     xi, yi,
1296428d7b3dSmrg				     g->info.width,
1297428d7b3dSmrg				     g->info.height));
1298428d7b3dSmrg
1299428d7b3dSmrg				if (list->format == format) {
1300428d7b3dSmrg					assert(pixman_image_get_format(glyph_image) == pixman_image_get_format(mask_image));
1301428d7b3dSmrg					pixman_image_composite(PictOpAdd,
1302428d7b3dSmrg							       glyph_image,
1303428d7b3dSmrg							       NULL,
1304428d7b3dSmrg							       mask_image,
1305428d7b3dSmrg							       0, 0,
1306428d7b3dSmrg							       0, 0,
1307428d7b3dSmrg							       xi, yi,
1308428d7b3dSmrg							       g->info.width,
1309428d7b3dSmrg							       g->info.height);
1310428d7b3dSmrg				} else {
1311428d7b3dSmrg					pixman_image_composite(PictOpAdd,
1312428d7b3dSmrg							       sna->render.white_image,
1313428d7b3dSmrg							       glyph_image,
1314428d7b3dSmrg							       mask_image,
1315428d7b3dSmrg							       0, 0,
1316428d7b3dSmrg							       0, 0,
1317428d7b3dSmrg							       xi, yi,
1318428d7b3dSmrg							       g->info.width,
1319428d7b3dSmrg							       g->info.height);
1320428d7b3dSmrg				}
1321428d7b3dSmrg
1322428d7b3dSmrgnext_image:
1323428d7b3dSmrg				x += g->info.xOff;
1324428d7b3dSmrg				y += g->info.yOff;
1325428d7b3dSmrg			}
1326428d7b3dSmrg			list++;
1327428d7b3dSmrg		} while (--nlist);
1328428d7b3dSmrg		pixman_image_unref(mask_image);
1329428d7b3dSmrg
1330428d7b3dSmrg		sigtrap_put();
1331428d7b3dSmrg
1332428d7b3dSmrg		mask = CreatePicture(0, &pixmap->drawable,
1333428d7b3dSmrg				     format, CPComponentAlpha,
1334428d7b3dSmrg				     &component_alpha, serverClient, &error);
1335428d7b3dSmrg		if (!mask)
1336428d7b3dSmrg			goto err_pixmap;
1337428d7b3dSmrg
1338428d7b3dSmrg		ValidatePicture(mask);
1339428d7b3dSmrg	} else {
1340428d7b3dSmrg		struct sna_composite_op tmp;
1341428d7b3dSmrg		PicturePtr glyph_atlas = NO_ATLAS;
1342428d7b3dSmrg
1343428d7b3dSmrg		pixmap = screen->CreatePixmap(screen,
1344428d7b3dSmrg					      width, height, format->depth,
1345428d7b3dSmrg					      SNA_CREATE_SCRATCH);
1346428d7b3dSmrg		if (!pixmap)
1347428d7b3dSmrg			goto use_small_mask;
1348428d7b3dSmrg
1349428d7b3dSmrg		assert(__sna_pixmap_get_bo(pixmap));
1350428d7b3dSmrg
1351428d7b3dSmrg		mask = CreatePicture(0, &pixmap->drawable,
1352428d7b3dSmrg				     format, CPComponentAlpha,
1353428d7b3dSmrg				     &component_alpha, serverClient, &error);
1354428d7b3dSmrg		if (!mask)
1355428d7b3dSmrg			goto err_pixmap;
1356428d7b3dSmrg
1357428d7b3dSmrg		ValidatePicture(mask);
1358428d7b3dSmrg		if (!clear_pixmap(sna, pixmap))
1359428d7b3dSmrg			goto err_mask;
1360428d7b3dSmrg
1361428d7b3dSmrg		do {
1362428d7b3dSmrg			int n = list->len;
1363428d7b3dSmrg			x += list->xOff;
1364428d7b3dSmrg			y += list->yOff;
1365428d7b3dSmrg			while (n--) {
1366428d7b3dSmrg				GlyphPtr glyph = *glyphs++;
1367428d7b3dSmrg				struct sna_glyph *p = sna_glyph(glyph);
1368428d7b3dSmrg				struct sna_composite_rectangles r;
1369428d7b3dSmrg
1370428d7b3dSmrg				if (unlikely(p->atlas != glyph_atlas)) {
1371428d7b3dSmrg					bool ok;
1372428d7b3dSmrg
1373428d7b3dSmrg					if (unlikely(!glyph_valid(glyph)))
1374428d7b3dSmrg						goto next_glyph;
1375428d7b3dSmrg
1376428d7b3dSmrg					if (glyph_atlas != NO_ATLAS) {
1377428d7b3dSmrg						tmp.done(sna, &tmp);
1378428d7b3dSmrg						glyph_atlas = NO_ATLAS;
1379428d7b3dSmrg					}
1380428d7b3dSmrg
1381428d7b3dSmrg					if (unlikely(p->atlas == NULL)) {
1382428d7b3dSmrg						if (!glyph_cache(screen, &sna->render, glyph))
1383428d7b3dSmrg							goto next_glyph;
1384428d7b3dSmrg					}
1385428d7b3dSmrg
1386428d7b3dSmrg					DBG(("%s: atlas format=%08x, mask format=%08x\n",
1387428d7b3dSmrg					     __FUNCTION__,
1388428d7b3dSmrg					     (int)p->atlas->format,
1389428d7b3dSmrg					     (int)(format->depth << 24 | format->format)));
1390428d7b3dSmrg
1391428d7b3dSmrg					memset(&tmp, 0, sizeof(tmp));
1392428d7b3dSmrg					if (p->atlas->format == (format->depth << 24 | format->format)) {
1393428d7b3dSmrg						ok = sna->render.composite(sna, PictOpAdd,
1394428d7b3dSmrg									   p->atlas, NULL, mask,
1395428d7b3dSmrg									   0, 0, 0, 0, 0, 0,
1396428d7b3dSmrg									   0, 0,
1397428d7b3dSmrg									   COMPOSITE_PARTIAL, &tmp);
1398428d7b3dSmrg					} else {
1399428d7b3dSmrg						ok = sna->render.composite(sna, PictOpAdd,
1400428d7b3dSmrg									   sna->render.white_picture, p->atlas, mask,
1401428d7b3dSmrg									   0, 0, 0, 0, 0, 0,
1402428d7b3dSmrg									   0, 0,
1403428d7b3dSmrg									   COMPOSITE_PARTIAL, &tmp);
1404428d7b3dSmrg					}
1405428d7b3dSmrg					if (!ok) {
1406428d7b3dSmrg						DBG(("%s: fallback -- can not handle PictOpAdd of glyph onto mask!\n",
1407428d7b3dSmrg						     __FUNCTION__));
1408428d7b3dSmrg						goto err_mask;
1409428d7b3dSmrg					}
1410428d7b3dSmrg
1411428d7b3dSmrg					glyph_atlas = p->atlas;
1412428d7b3dSmrg				}
1413428d7b3dSmrg
1414428d7b3dSmrg				DBG(("%s: blt glyph origin (%d, %d), offset (%d, %d), src (%d, %d), size (%d, %d)\n",
1415428d7b3dSmrg				     __FUNCTION__,
1416428d7b3dSmrg				     x, y,
1417428d7b3dSmrg				     glyph->info.x, glyph->info.y,
1418428d7b3dSmrg				     p->coordinate.x, p->coordinate.y,
1419428d7b3dSmrg				     glyph->info.width, glyph->info.height));
1420428d7b3dSmrg
1421428d7b3dSmrg				r.mask = r.src = p->coordinate;
1422428d7b3dSmrg				r.dst.x = x - glyph->info.x;
1423428d7b3dSmrg				r.dst.y = y - glyph->info.y;
1424428d7b3dSmrg				glyph_copy_size(&r, glyph);
1425428d7b3dSmrg				tmp.blt(sna, &tmp, &r);
1426428d7b3dSmrg
1427428d7b3dSmrgnext_glyph:
1428428d7b3dSmrg				x += glyph->info.xOff;
1429428d7b3dSmrg				y += glyph->info.yOff;
1430428d7b3dSmrg			}
1431428d7b3dSmrg			list++;
1432428d7b3dSmrg		} while (--nlist);
1433428d7b3dSmrg		if (glyph_atlas != NO_ATLAS)
1434428d7b3dSmrg			tmp.done(sna, &tmp);
1435428d7b3dSmrg	}
1436428d7b3dSmrg
1437428d7b3dSmrg	sna_composite(op,
1438428d7b3dSmrg		      src, mask, dst,
1439428d7b3dSmrg		      src_x, src_y,
1440428d7b3dSmrg		      0, 0,
1441428d7b3dSmrg		      box.x1, box.y1,
1442428d7b3dSmrg		      width, height);
1443428d7b3dSmrg	ret = true;
1444428d7b3dSmrgerr_mask:
1445428d7b3dSmrg	FreePicture(mask, 0);
1446428d7b3dSmrgerr_pixmap:
1447428d7b3dSmrg	sna_pixmap_destroy(pixmap);
1448428d7b3dSmrg	return ret;
1449428d7b3dSmrg}
1450428d7b3dSmrg
1451428d7b3dSmrgstatic PictFormatPtr
1452428d7b3dSmrgglyphs_format(int nlist, GlyphListPtr list, GlyphPtr * glyphs)
1453428d7b3dSmrg{
1454428d7b3dSmrg	PictFormatPtr format = list[0].format;
1455428d7b3dSmrg	int16_t x1, x2, y1, y2;
1456428d7b3dSmrg	int16_t x, y;
1457428d7b3dSmrg	BoxRec stack_extents[64], *list_extents = stack_extents;
1458428d7b3dSmrg	int i, j;
1459428d7b3dSmrg
1460428d7b3dSmrg	if (nlist > ARRAY_SIZE(stack_extents)) {
1461428d7b3dSmrg		list_extents = malloc(sizeof(BoxRec) * nlist);
1462428d7b3dSmrg		if (list_extents == NULL)
1463428d7b3dSmrg			return NULL;
1464428d7b3dSmrg	}
1465428d7b3dSmrg
1466428d7b3dSmrg	x = y = 0; i = 0;
1467428d7b3dSmrg	while (nlist--) {
1468428d7b3dSmrg		BoxRec extents;
1469428d7b3dSmrg		bool first = true;
1470428d7b3dSmrg		int n = list->len;
1471428d7b3dSmrg
1472428d7b3dSmrg		/* Check the intersection of each glyph within the list and
1473428d7b3dSmrg		 * then each list against the previous lists.
1474428d7b3dSmrg		 *
1475428d7b3dSmrg		 * If we overlap then we cannot substitute a mask as the
1476428d7b3dSmrg		 * rendering will be altered.
1477428d7b3dSmrg		 */
1478428d7b3dSmrg		if (format->format != list->format->format) {
1479428d7b3dSmrg			DBG(("%s: switching formats from %x to %x\n",
1480428d7b3dSmrg			     __FUNCTION__,
1481428d7b3dSmrg			     (unsigned)format->format,
1482428d7b3dSmrg			     (unsigned)list->format->format));
1483428d7b3dSmrg			format = NULL;
1484428d7b3dSmrg			goto out;
1485428d7b3dSmrg		}
1486428d7b3dSmrg
1487428d7b3dSmrg		x += list->xOff;
1488428d7b3dSmrg		y += list->yOff;
1489428d7b3dSmrg		list++;
1490428d7b3dSmrg		while (n--) {
1491428d7b3dSmrg			GlyphPtr glyph = *glyphs++;
1492428d7b3dSmrg
1493428d7b3dSmrg			if (!glyph_valid(glyph))
1494428d7b3dSmrg				goto skip_glyph;
1495428d7b3dSmrg
1496428d7b3dSmrg			x1 = x - glyph->info.x;
1497428d7b3dSmrg			y1 = y - glyph->info.y;
1498428d7b3dSmrg			x2 = x1 + glyph->info.width;
1499428d7b3dSmrg			y2 = y1 + glyph->info.height;
1500428d7b3dSmrg
1501428d7b3dSmrg			if (first) {
1502428d7b3dSmrg				extents.x1 = x1;
1503428d7b3dSmrg				extents.y1 = y1;
1504428d7b3dSmrg				extents.x2 = x2;
1505428d7b3dSmrg				extents.y2 = y2;
1506428d7b3dSmrg				first = false;
1507428d7b3dSmrg			} else {
1508428d7b3dSmrg				/* Potential overlap?
1509428d7b3dSmrg				 * We cheat and ignore the boundary pixels, as
1510428d7b3dSmrg				 * the likelihood of an actual overlap of
1511428d7b3dSmrg				 * inkedk pixels being noticeable in the
1512428d7b3dSmrg				 * boundary is small, yet glyphs frequently
1513428d7b3dSmrg				 * overlap on the boundaries.
1514428d7b3dSmrg				 */
1515428d7b3dSmrg				if (x1 < extents.x2-GLYPH_TOLERANCE &&
1516428d7b3dSmrg				    x2 > extents.x1+GLYPH_TOLERANCE &&
1517428d7b3dSmrg				    y1 < extents.y2-GLYPH_TOLERANCE &&
1518428d7b3dSmrg				    y2 > extents.y1+GLYPH_TOLERANCE) {
1519428d7b3dSmrg					DBG(("%s: overlapping glyph inside line, current bbox (%d, %d), (%d, %d), glyph (%d, %d), (%d, %d)\n",
1520428d7b3dSmrg					     __FUNCTION__,
1521428d7b3dSmrg					     extents.x1, extents.y1, extents.x2, extents.y2,
1522428d7b3dSmrg					     x1, y1, x2, y2));
1523428d7b3dSmrg					format = NULL;
1524428d7b3dSmrg					goto out;
1525428d7b3dSmrg				}
1526428d7b3dSmrg
1527428d7b3dSmrg				if (x1 < extents.x1)
1528428d7b3dSmrg					extents.x1 = x1;
1529428d7b3dSmrg				if (x2 > extents.x2)
1530428d7b3dSmrg					extents.x2 = x2;
1531428d7b3dSmrg				if (y1 < extents.y1)
1532428d7b3dSmrg					extents.y1 = y1;
1533428d7b3dSmrg				if (y2 > extents.y2)
1534428d7b3dSmrg					extents.y2 = y2;
1535428d7b3dSmrg			}
1536428d7b3dSmrgskip_glyph:
1537428d7b3dSmrg			x += glyph->info.xOff;
1538428d7b3dSmrg			y += glyph->info.yOff;
1539428d7b3dSmrg		}
1540428d7b3dSmrg
1541428d7b3dSmrg		/* Incrementally building a region is expensive. We expect
1542428d7b3dSmrg		 * the number of lists to be small, so just keep a list
1543428d7b3dSmrg		 * of the previous boxes and walk those.
1544428d7b3dSmrg		 */
1545428d7b3dSmrg		if (!first) {
1546428d7b3dSmrg			for (j = 0; j < i; j++) {
1547428d7b3dSmrg				if (extents.x1 < list_extents[j].x2-GLYPH_TOLERANCE &&
1548428d7b3dSmrg				    extents.x2 > list_extents[j].x1+GLYPH_TOLERANCE &&
1549428d7b3dSmrg				    extents.y1 < list_extents[j].y2-GLYPH_TOLERANCE &&
1550428d7b3dSmrg				    extents.y2 > list_extents[j].y1+GLYPH_TOLERANCE) {
1551428d7b3dSmrg					DBG(("%s: overlapping lines, current bbox (%d, %d), (%d, %d), previous line (%d, %d), (%d, %d)\n",
1552428d7b3dSmrg					     __FUNCTION__,
1553428d7b3dSmrg					     extents.x1, extents.y1, extents.x2, extents.y2,
1554428d7b3dSmrg					     list_extents[j].x1, list_extents[j].y1,
1555428d7b3dSmrg					     list_extents[j].x2, list_extents[j].y2));
1556428d7b3dSmrg					format = NULL;
1557428d7b3dSmrg					goto out;
1558428d7b3dSmrg				}
1559428d7b3dSmrg			}
1560428d7b3dSmrg			list_extents[i++] = extents;
1561428d7b3dSmrg		}
1562428d7b3dSmrg	}
1563428d7b3dSmrg
1564428d7b3dSmrgout:
1565428d7b3dSmrg	if (list_extents != stack_extents)
1566428d7b3dSmrg		free(list_extents);
1567428d7b3dSmrg	return format;
1568428d7b3dSmrg}
1569428d7b3dSmrg
1570428d7b3dSmrgstatic bool can_discard_mask(uint8_t op, PicturePtr src, PictFormatPtr mask,
1571428d7b3dSmrg			     int nlist, GlyphListPtr list, GlyphPtr *glyphs)
1572428d7b3dSmrg{
1573428d7b3dSmrg	PictFormatPtr g;
1574428d7b3dSmrg	uint32_t color;
1575428d7b3dSmrg
1576428d7b3dSmrg	if (NO_DISCARD_MASK)
1577428d7b3dSmrg		return false;
1578428d7b3dSmrg
1579428d7b3dSmrg	DBG(("%s: nlist=%d, mask=%08x, depth %d, op=%d (bounded? %d)\n",
1580428d7b3dSmrg	     __FUNCTION__, nlist,
1581428d7b3dSmrg	     mask ? (unsigned)mask->format : 0, mask ? mask->depth : 0,
1582428d7b3dSmrg	     op, op_is_bounded(op)));
1583428d7b3dSmrg
1584428d7b3dSmrg	if (nlist == 1 && list->len == 1)
1585428d7b3dSmrg		return true;
1586428d7b3dSmrg
1587428d7b3dSmrg	if (!op_is_bounded(op))
1588428d7b3dSmrg		return false;
1589428d7b3dSmrg
1590428d7b3dSmrg	/* No glyphs overlap and we are not performing a mask conversion. */
1591428d7b3dSmrg	g = glyphs_format(nlist, list, glyphs);
1592428d7b3dSmrg	if (mask == g)
1593428d7b3dSmrg		return true;
1594428d7b3dSmrg
1595428d7b3dSmrg	DBG(("%s: preferred mask format %08x, depth %d\n",
1596428d7b3dSmrg	     __FUNCTION__, g ? (unsigned)g->format : 0,  g ? g->depth : 0));
1597428d7b3dSmrg
1598428d7b3dSmrg	/* Otherwise if the glyphs are all bitmaps and we have an
1599428d7b3dSmrg	 * opaque source we can also render directly to the dst.
1600428d7b3dSmrg	 */
1601428d7b3dSmrg	if (g == NULL) {
1602428d7b3dSmrg		while (nlist--) {
1603428d7b3dSmrg			if (list->format->depth != 1)
1604428d7b3dSmrg				return false;
1605428d7b3dSmrg
1606428d7b3dSmrg			list++;
1607428d7b3dSmrg		}
1608428d7b3dSmrg	} else {
1609428d7b3dSmrg		if (PICT_FORMAT_A(mask->format) >= PICT_FORMAT_A(g->format))
1610428d7b3dSmrg			return true;
1611428d7b3dSmrg
1612428d7b3dSmrg		if (g->depth != 1)
1613428d7b3dSmrg			return false;
1614428d7b3dSmrg	}
1615428d7b3dSmrg
1616428d7b3dSmrg	if (!sna_picture_is_solid(src, &color))
1617428d7b3dSmrg		return false;
1618428d7b3dSmrg
1619428d7b3dSmrg	return color >> 24 == 0xff;
1620428d7b3dSmrg}
1621428d7b3dSmrg
1622428d7b3dSmrgstatic void
1623428d7b3dSmrgglyphs_fallback(CARD8 op,
1624428d7b3dSmrg		PicturePtr src,
1625428d7b3dSmrg		PicturePtr dst,
1626428d7b3dSmrg		PictFormatPtr mask_format,
1627428d7b3dSmrg		int src_x, int src_y,
1628428d7b3dSmrg		int nlist, GlyphListPtr list, GlyphPtr *glyphs)
1629428d7b3dSmrg{
1630428d7b3dSmrg	struct sna *sna = to_sna_from_drawable(dst->pDrawable);
1631428d7b3dSmrg	pixman_image_t *src_image, *dst_image;
1632428d7b3dSmrg	int src_dx, src_dy;
1633428d7b3dSmrg	ScreenPtr screen = dst->pDrawable->pScreen;
1634428d7b3dSmrg	RegionRec region;
1635428d7b3dSmrg	int x, y, n;
1636428d7b3dSmrg
1637428d7b3dSmrg	glyph_extents(nlist, list, glyphs, &region.extents);
1638428d7b3dSmrg	DBG(("%s: nlist=%d, count=%d, extents (%d, %d), (%d, %d)\n", __FUNCTION__,
1639428d7b3dSmrg	     nlist, glyph_count(nlist, list),
1640428d7b3dSmrg	     region.extents.x1, region.extents.y1,
1641428d7b3dSmrg	     region.extents.x2, region.extents.y2));
1642428d7b3dSmrg
1643428d7b3dSmrg	if (region.extents.x2 <= region.extents.x1 ||
1644428d7b3dSmrg	    region.extents.y2 <= region.extents.y1)
1645428d7b3dSmrg		return;
1646428d7b3dSmrg
1647428d7b3dSmrg	region.data = NULL;
1648428d7b3dSmrg	RegionTranslate(&region, dst->pDrawable->x, dst->pDrawable->y);
1649428d7b3dSmrg	RegionIntersect(&region, &region, dst->pCompositeClip);
1650428d7b3dSmrg	DBG(("%s: clipped extents (%d, %d), (%d, %d)\n",
1651428d7b3dSmrg	     __FUNCTION__,
1652428d7b3dSmrg	     RegionExtents(&region)->x1, RegionExtents(&region)->y1,
1653428d7b3dSmrg	     RegionExtents(&region)->x2, RegionExtents(&region)->y2));
1654428d7b3dSmrg	if (RegionNil(&region))
1655428d7b3dSmrg		return;
1656428d7b3dSmrg
1657428d7b3dSmrg	if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &region,
1658428d7b3dSmrg					     MOVE_READ | MOVE_WRITE))
1659428d7b3dSmrg		return;
1660428d7b3dSmrg	if (dst->alphaMap &&
1661428d7b3dSmrg	    !sna_drawable_move_to_cpu(dst->alphaMap->pDrawable,
1662428d7b3dSmrg				      MOVE_READ | MOVE_WRITE))
1663428d7b3dSmrg		return;
1664428d7b3dSmrg
1665428d7b3dSmrg	if (src->pDrawable) {
1666428d7b3dSmrg		if (!sna_drawable_move_to_cpu(src->pDrawable,
1667428d7b3dSmrg					      MOVE_READ))
1668428d7b3dSmrg			return;
1669428d7b3dSmrg
1670428d7b3dSmrg		if (src->alphaMap &&
1671428d7b3dSmrg		    !sna_drawable_move_to_cpu(src->alphaMap->pDrawable,
1672428d7b3dSmrg					      MOVE_READ))
1673428d7b3dSmrg			return;
1674428d7b3dSmrg	}
1675428d7b3dSmrg	RegionTranslate(&region, -dst->pDrawable->x, -dst->pDrawable->y);
1676428d7b3dSmrg
1677428d7b3dSmrg	if (mask_format &&
1678428d7b3dSmrg	    can_discard_mask(op, src, mask_format, nlist, list, glyphs)) {
1679428d7b3dSmrg		DBG(("%s: discarding mask\n", __FUNCTION__));
1680428d7b3dSmrg		mask_format = NULL;
1681428d7b3dSmrg	}
1682428d7b3dSmrg
1683428d7b3dSmrg#if HAS_PIXMAN_GLYPHS
1684428d7b3dSmrg	if (__global_glyph_cache) {
1685428d7b3dSmrg		pixman_glyph_t stack_glyphs[N_STACK_GLYPHS];
1686428d7b3dSmrg		pixman_glyph_t *pglyphs = stack_glyphs;
1687428d7b3dSmrg		int dst_x = list->xOff, dst_y = list->yOff;
1688428d7b3dSmrg		int dst_dx, dst_dy, count;
1689428d7b3dSmrg
1690428d7b3dSmrg		pixman_glyph_cache_freeze(__global_glyph_cache);
1691428d7b3dSmrg
1692428d7b3dSmrg		count = 0;
1693428d7b3dSmrg		for (n = 0; n < nlist; ++n)
1694428d7b3dSmrg			count += list[n].len;
1695428d7b3dSmrg		if (count > N_STACK_GLYPHS) {
1696428d7b3dSmrg			pglyphs = malloc(count * sizeof(pixman_glyph_t));
1697428d7b3dSmrg			if (pglyphs == NULL)
1698428d7b3dSmrg				goto out;
1699428d7b3dSmrg		}
1700428d7b3dSmrg
1701428d7b3dSmrg		count = 0;
1702428d7b3dSmrg		x = y = 0;
1703428d7b3dSmrg		while (nlist--) {
1704428d7b3dSmrg			n = list->len;
1705428d7b3dSmrg			x += list->xOff;
1706428d7b3dSmrg			y += list->yOff;
1707428d7b3dSmrg			while (n--) {
1708428d7b3dSmrg				GlyphPtr g = *glyphs++;
1709428d7b3dSmrg				const void *ptr;
1710428d7b3dSmrg
1711428d7b3dSmrg				if (!glyph_valid(g))
1712428d7b3dSmrg					goto next;
1713428d7b3dSmrg
1714428d7b3dSmrg				ptr = pixman_glyph_cache_lookup(__global_glyph_cache, g, NULL);
1715428d7b3dSmrg				if (ptr == NULL) {
1716428d7b3dSmrg					pixman_image_t *glyph_image;
1717428d7b3dSmrg
1718428d7b3dSmrg					glyph_image = sna_glyph_get_image(g, screen);
1719428d7b3dSmrg					if (glyph_image == NULL)
1720428d7b3dSmrg						goto next;
1721428d7b3dSmrg
1722428d7b3dSmrg					DBG(("%s: inserting glyph %p into pixman cache\n", __FUNCTION__, g));
1723428d7b3dSmrg					ptr = pixman_glyph_cache_insert(__global_glyph_cache, g, NULL,
1724428d7b3dSmrg									g->info.x,
1725428d7b3dSmrg									g->info.y,
1726428d7b3dSmrg									glyph_image);
1727428d7b3dSmrg					if (ptr == NULL)
1728428d7b3dSmrg						goto next;
1729428d7b3dSmrg				}
1730428d7b3dSmrg
1731428d7b3dSmrg				assert(sna_glyph_get_image(g, screen) != NULL);
1732428d7b3dSmrg
1733428d7b3dSmrg				pglyphs[count].x = x;
1734428d7b3dSmrg				pglyphs[count].y = y;
1735428d7b3dSmrg				pglyphs[count].glyph = ptr;
1736428d7b3dSmrg				count++;
1737428d7b3dSmrg
1738428d7b3dSmrgnext:
1739428d7b3dSmrg				x += g->info.xOff;
1740428d7b3dSmrg				y += g->info.yOff;
1741428d7b3dSmrg			}
1742428d7b3dSmrg			list++;
1743428d7b3dSmrg		}
1744428d7b3dSmrg
1745428d7b3dSmrg		if (count == 0)
1746428d7b3dSmrg			goto out;
1747428d7b3dSmrg
1748428d7b3dSmrg		src_image = image_from_pict(src, FALSE, &src_dx, &src_dy);
1749428d7b3dSmrg		if (src_image == NULL)
1750428d7b3dSmrg			goto out;
1751428d7b3dSmrg
1752428d7b3dSmrg		dst_image = image_from_pict(dst, TRUE, &dst_dx, &dst_dy);
1753428d7b3dSmrg		if (dst_image == NULL)
1754428d7b3dSmrg			goto out_free_src;
1755428d7b3dSmrg
1756428d7b3dSmrg		if (sigtrap_get() == 0) {
1757428d7b3dSmrg			if (mask_format) {
1758428d7b3dSmrg				pixman_composite_glyphs(op, src_image, dst_image,
1759428d7b3dSmrg							mask_format->format | (mask_format->depth << 24),
1760428d7b3dSmrg							src_x + src_dx + region.extents.x1 - dst_x,
1761428d7b3dSmrg							src_y + src_dy + region.extents.y1 - dst_y,
1762428d7b3dSmrg							region.extents.x1, region.extents.y1,
1763428d7b3dSmrg							region.extents.x1 + dst_dx, region.extents.y1 + dst_dy,
1764428d7b3dSmrg							region.extents.x2 - region.extents.x1,
1765428d7b3dSmrg							region.extents.y2 - region.extents.y1,
1766428d7b3dSmrg							__global_glyph_cache, count, pglyphs);
1767428d7b3dSmrg			} else {
1768428d7b3dSmrg				pixman_composite_glyphs_no_mask(op, src_image, dst_image,
1769428d7b3dSmrg								src_x + src_dx - dst_x, src_y + src_dy - dst_y,
1770428d7b3dSmrg								dst_dx, dst_dy,
1771428d7b3dSmrg								__global_glyph_cache, count, pglyphs);
1772428d7b3dSmrg			}
1773428d7b3dSmrg			sigtrap_put();
1774428d7b3dSmrg		}
1775428d7b3dSmrg
1776428d7b3dSmrg		free_pixman_pict(dst, dst_image);
1777428d7b3dSmrg
1778428d7b3dSmrgout_free_src:
1779428d7b3dSmrg		free_pixman_pict(src, src_image);
1780428d7b3dSmrg
1781428d7b3dSmrgout:
1782428d7b3dSmrg		pixman_glyph_cache_thaw(__global_glyph_cache);
1783428d7b3dSmrg		if (pglyphs != stack_glyphs)
1784428d7b3dSmrg			free(pglyphs);
1785428d7b3dSmrg	} else
1786428d7b3dSmrg#endif
1787428d7b3dSmrg	{
1788428d7b3dSmrg		pixman_image_t *mask_image;
1789428d7b3dSmrg
1790428d7b3dSmrg		dst_image = image_from_pict(dst, TRUE, &x, &y);
1791428d7b3dSmrg		if (dst_image == NULL)
1792428d7b3dSmrg			goto cleanup_region;
1793428d7b3dSmrg		DBG(("%s: dst offset (%d, %d)\n", __FUNCTION__, x, y));
1794428d7b3dSmrg		if (x | y) {
1795428d7b3dSmrg			region.extents.x1 += x;
1796428d7b3dSmrg			region.extents.x2 += x;
1797428d7b3dSmrg			region.extents.y1 += y;
1798428d7b3dSmrg			region.extents.y2 += y;
1799428d7b3dSmrg		}
1800428d7b3dSmrg
1801428d7b3dSmrg		src_image = image_from_pict(src, FALSE, &src_dx, &src_dy);
1802428d7b3dSmrg		if (src_image == NULL)
1803428d7b3dSmrg			goto cleanup_dst;
1804428d7b3dSmrg		DBG(("%s: src offset (%d, %d)\n", __FUNCTION__, src_dx, src_dy));
1805428d7b3dSmrg		src_x += src_dx - list->xOff;
1806428d7b3dSmrg		src_y += src_dy - list->yOff;
1807428d7b3dSmrg
1808428d7b3dSmrg		if (mask_format) {
1809428d7b3dSmrg			DBG(("%s: create mask (%d, %d)x(%d,%d) + (%d,%d) + (%d,%d), depth=%d, format=%lx [%lx], ca? %d\n",
1810428d7b3dSmrg			     __FUNCTION__,
1811428d7b3dSmrg			     region.extents.x1, region.extents.y1,
1812428d7b3dSmrg			     region.extents.x2 - region.extents.x1,
1813428d7b3dSmrg			     region.extents.y2 - region.extents.y1,
1814428d7b3dSmrg			     dst->pDrawable->x, dst->pDrawable->y,
1815428d7b3dSmrg			     x, y,
1816428d7b3dSmrg			     mask_format->depth,
1817428d7b3dSmrg			     (long)mask_format->format,
1818428d7b3dSmrg			     (long)(mask_format->depth << 24 | mask_format->format),
1819428d7b3dSmrg			     NeedsComponent(mask_format->format)));
1820428d7b3dSmrg			mask_image =
1821428d7b3dSmrg				pixman_image_create_bits(mask_format->depth << 24 | mask_format->format,
1822428d7b3dSmrg							 region.extents.x2 - region.extents.x1,
1823428d7b3dSmrg							 region.extents.y2 - region.extents.y1,
1824428d7b3dSmrg							 NULL, 0);
1825428d7b3dSmrg			if (mask_image == NULL)
1826428d7b3dSmrg				goto cleanup_src;
1827428d7b3dSmrg			if (NeedsComponent(mask_format->format))
1828428d7b3dSmrg				pixman_image_set_component_alpha(mask_image, TRUE);
1829428d7b3dSmrg
1830428d7b3dSmrg			x -= region.extents.x1;
1831428d7b3dSmrg			y -= region.extents.y1;
1832428d7b3dSmrg		} else {
1833428d7b3dSmrg			mask_image = dst_image;
1834428d7b3dSmrg			src_x -= x - dst->pDrawable->x;
1835428d7b3dSmrg			src_y -= y - dst->pDrawable->y;
1836428d7b3dSmrg		}
1837428d7b3dSmrg
1838428d7b3dSmrg		if (sigtrap_get() == 0) {
1839428d7b3dSmrg			do {
1840428d7b3dSmrg				n = list->len;
1841428d7b3dSmrg				x += list->xOff;
1842428d7b3dSmrg				y += list->yOff;
1843428d7b3dSmrg				while (n--) {
1844428d7b3dSmrg					GlyphPtr g = *glyphs++;
1845428d7b3dSmrg					pixman_image_t *glyph_image;
1846428d7b3dSmrg
1847428d7b3dSmrg					if (!glyph_valid(g))
1848428d7b3dSmrg						goto next_glyph;
1849428d7b3dSmrg
1850428d7b3dSmrg					glyph_image = sna_glyph_get_image(g, screen);
1851428d7b3dSmrg					if (glyph_image == NULL)
1852428d7b3dSmrg						goto next_glyph;
1853428d7b3dSmrg
1854428d7b3dSmrg					if (mask_format) {
1855428d7b3dSmrg						DBG(("%s: glyph to mask (%d, %d)x(%d, %d)\n",
1856428d7b3dSmrg						     __FUNCTION__,
1857428d7b3dSmrg						     x - g->info.x,
1858428d7b3dSmrg						     y - g->info.y,
1859428d7b3dSmrg						     g->info.width,
1860428d7b3dSmrg						     g->info.height));
1861428d7b3dSmrg
1862428d7b3dSmrg						if (list->format == mask_format) {
1863428d7b3dSmrg							assert(pixman_image_get_format(glyph_image) == pixman_image_get_format(mask_image));
1864428d7b3dSmrg							pixman_image_composite(PictOpAdd,
1865428d7b3dSmrg									       glyph_image,
1866428d7b3dSmrg									       NULL,
1867428d7b3dSmrg									       mask_image,
1868428d7b3dSmrg									       0, 0,
1869428d7b3dSmrg									       0, 0,
1870428d7b3dSmrg									       x - g->info.x,
1871428d7b3dSmrg									       y - g->info.y,
1872428d7b3dSmrg									       g->info.width,
1873428d7b3dSmrg									       g->info.height);
1874428d7b3dSmrg						} else {
1875428d7b3dSmrg							pixman_image_composite(PictOpAdd,
1876428d7b3dSmrg									       sna->render.white_image,
1877428d7b3dSmrg									       glyph_image,
1878428d7b3dSmrg									       mask_image,
1879428d7b3dSmrg									       0, 0,
1880428d7b3dSmrg									       0, 0,
1881428d7b3dSmrg									       x - g->info.x,
1882428d7b3dSmrg									       y - g->info.y,
1883428d7b3dSmrg									       g->info.width,
1884428d7b3dSmrg									       g->info.height);
1885428d7b3dSmrg						}
1886428d7b3dSmrg					} else {
1887428d7b3dSmrg						int xi = x - g->info.x;
1888428d7b3dSmrg						int yi = y - g->info.y;
1889428d7b3dSmrg
1890428d7b3dSmrg						DBG(("%s: glyph to dst (%d, %d)x(%d, %d)/[(%d, %d)x(%d, %d)], src (%d, %d) [op=%d]\n",
1891428d7b3dSmrg						     __FUNCTION__,
1892428d7b3dSmrg						     xi, yi,
1893428d7b3dSmrg						     g->info.width, g->info.height,
1894428d7b3dSmrg						     dst->pDrawable->x,
1895428d7b3dSmrg						     dst->pDrawable->y,
1896428d7b3dSmrg						     dst->pDrawable->width,
1897428d7b3dSmrg						     dst->pDrawable->height,
1898428d7b3dSmrg						     src_x + xi,
1899428d7b3dSmrg						     src_y + yi,
1900428d7b3dSmrg						     op));
1901428d7b3dSmrg
1902428d7b3dSmrg						pixman_image_composite(op,
1903428d7b3dSmrg								       src_image,
1904428d7b3dSmrg								       glyph_image,
1905428d7b3dSmrg								       dst_image,
1906428d7b3dSmrg								       src_x + xi,
1907428d7b3dSmrg								       src_y + yi,
1908428d7b3dSmrg								       0, 0,
1909428d7b3dSmrg								       xi, yi,
1910428d7b3dSmrg								       g->info.width,
1911428d7b3dSmrg								       g->info.height);
1912428d7b3dSmrg					}
1913428d7b3dSmrgnext_glyph:
1914428d7b3dSmrg					x += g->info.xOff;
1915428d7b3dSmrg					y += g->info.yOff;
1916428d7b3dSmrg				}
1917428d7b3dSmrg				list++;
1918428d7b3dSmrg			} while (--nlist);
1919428d7b3dSmrg			sigtrap_put();
1920428d7b3dSmrg		}
1921428d7b3dSmrg
1922428d7b3dSmrg		if (mask_format) {
1923428d7b3dSmrg			DBG(("%s: glyph mask composite src=(%d+%d,%d+%d) dst=(%d, %d)x(%d, %d)\n",
1924428d7b3dSmrg			     __FUNCTION__,
1925428d7b3dSmrg			     src_x, region.extents.x1, src_y, region.extents.y1,
1926428d7b3dSmrg			     region.extents.x1, region.extents.y1,
1927428d7b3dSmrg			     region.extents.x2 - region.extents.x1,
1928428d7b3dSmrg			     region.extents.y2 - region.extents.y1));
1929428d7b3dSmrg			pixman_image_composite(op, src_image, mask_image, dst_image,
1930428d7b3dSmrg					       src_x, src_y,
1931428d7b3dSmrg					       0, 0,
1932428d7b3dSmrg					       region.extents.x1, region.extents.y1,
1933428d7b3dSmrg					       region.extents.x2 - region.extents.x1,
1934428d7b3dSmrg					       region.extents.y2 - region.extents.y1);
1935428d7b3dSmrg			pixman_image_unref(mask_image);
1936428d7b3dSmrg		}
1937428d7b3dSmrg
1938428d7b3dSmrgcleanup_src:
1939428d7b3dSmrg		free_pixman_pict(src, src_image);
1940428d7b3dSmrgcleanup_dst:
1941428d7b3dSmrg		free_pixman_pict(dst, dst_image);
1942428d7b3dSmrg	}
1943428d7b3dSmrg
1944428d7b3dSmrgcleanup_region:
1945428d7b3dSmrg	RegionUninit(&region);
1946428d7b3dSmrg}
1947428d7b3dSmrg
1948428d7b3dSmrgvoid
1949428d7b3dSmrgsna_glyphs(CARD8 op,
1950428d7b3dSmrg	   PicturePtr src,
1951428d7b3dSmrg	   PicturePtr dst,
1952428d7b3dSmrg	   PictFormatPtr mask,
1953428d7b3dSmrg	   INT16 src_x, INT16 src_y,
1954428d7b3dSmrg	   int nlist, GlyphListPtr list, GlyphPtr *glyphs)
1955428d7b3dSmrg{
1956428d7b3dSmrg	PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable);
1957428d7b3dSmrg	struct sna *sna = to_sna_from_pixmap(pixmap);
1958428d7b3dSmrg	struct sna_pixmap *priv;
1959428d7b3dSmrg
1960428d7b3dSmrg	DBG(("%s(op=%d, nlist=%d, src=(%d, %d))\n",
1961428d7b3dSmrg	     __FUNCTION__, op, nlist, src_x, src_y));
1962428d7b3dSmrg
1963428d7b3dSmrg	if (RegionNil(dst->pCompositeClip))
1964428d7b3dSmrg		return;
1965428d7b3dSmrg
1966428d7b3dSmrg	if (FALLBACK)
1967428d7b3dSmrg		goto fallback;
1968428d7b3dSmrg
1969428d7b3dSmrg	if (!can_render(sna)) {
1970428d7b3dSmrg		DBG(("%s: wedged\n", __FUNCTION__));
1971428d7b3dSmrg		goto fallback;
1972428d7b3dSmrg	}
1973428d7b3dSmrg
1974428d7b3dSmrg	if (!can_render_to_picture(dst)) {
1975428d7b3dSmrg		DBG(("%s: fallback -- dst incompatible picture\n", __FUNCTION__));
1976428d7b3dSmrg		goto fallback;
1977428d7b3dSmrg	}
1978428d7b3dSmrg
1979428d7b3dSmrg	priv = sna_pixmap(pixmap);
1980428d7b3dSmrg	if (priv == NULL) {
1981428d7b3dSmrg		DBG(("%s: fallback -- destination unattached\n", __FUNCTION__));
1982428d7b3dSmrg		goto fallback;
1983428d7b3dSmrg	}
1984428d7b3dSmrg
1985428d7b3dSmrg	if (!is_gpu_dst(priv) && !picture_is_gpu(sna, src, 0)) {
1986428d7b3dSmrg		DBG(("%s: fallback -- too small (%dx%d)\n",
1987428d7b3dSmrg		     __FUNCTION__, dst->pDrawable->width, dst->pDrawable->height));
1988428d7b3dSmrg		goto fallback;
1989428d7b3dSmrg	}
1990428d7b3dSmrg
1991428d7b3dSmrg	/* Try to discard the mask for non-overlapping glyphs */
1992428d7b3dSmrg	if (FORCE_GLYPHS_TO_DST ||
1993428d7b3dSmrg	    mask == NULL ||
1994428d7b3dSmrg	    (dst->pCompositeClip->data == NULL &&
1995428d7b3dSmrg	     can_discard_mask(op, src, mask, nlist, list, glyphs))) {
1996428d7b3dSmrg		DBG(("%s: discarding mask\n", __FUNCTION__));
1997428d7b3dSmrg		if (can_use_glyph0()) {
1998428d7b3dSmrg			if (glyphs0_to_dst(sna, op,
1999428d7b3dSmrg					   src, dst,
2000428d7b3dSmrg					   src_x, src_y,
2001428d7b3dSmrg					   nlist, list, glyphs))
2002428d7b3dSmrg				return;
2003428d7b3dSmrg		} else {
2004428d7b3dSmrg			if (glyphs_to_dst(sna, op,
2005428d7b3dSmrg					  src, dst,
2006428d7b3dSmrg					  src_x, src_y,
2007428d7b3dSmrg					  nlist, list, glyphs))
2008428d7b3dSmrg				return;
2009428d7b3dSmrg		}
2010428d7b3dSmrg	}
2011428d7b3dSmrg
2012428d7b3dSmrg	/* Otherwise see if we can substitute a mask */
2013428d7b3dSmrg	if (!mask) {
2014428d7b3dSmrg		mask = glyphs_format(nlist, list, glyphs);
2015428d7b3dSmrg		DBG(("%s: substituting mask? %d\n", __FUNCTION__, mask!=NULL));
2016428d7b3dSmrg	}
2017428d7b3dSmrg	if (mask) {
2018428d7b3dSmrg		if (glyphs_via_mask(sna, op,
2019428d7b3dSmrg				    src, dst, mask,
2020428d7b3dSmrg				    src_x, src_y,
2021428d7b3dSmrg				    nlist, list, glyphs))
2022428d7b3dSmrg			return;
2023428d7b3dSmrg	} else {
2024428d7b3dSmrg		if (glyphs_slow(sna, op,
2025428d7b3dSmrg				src, dst,
2026428d7b3dSmrg				src_x, src_y,
2027428d7b3dSmrg				nlist, list, glyphs))
2028428d7b3dSmrg			return;
2029428d7b3dSmrg	}
2030428d7b3dSmrg
2031428d7b3dSmrgfallback:
2032428d7b3dSmrg	glyphs_fallback(op, src, dst, mask, src_x, src_y, nlist, list, glyphs);
2033428d7b3dSmrg}
2034428d7b3dSmrg
2035428d7b3dSmrgstatic bool
2036428d7b3dSmrgglyphs_via_image(struct sna *sna,
2037428d7b3dSmrg		 CARD8 op,
2038428d7b3dSmrg		 PicturePtr src,
2039428d7b3dSmrg		 PicturePtr dst,
2040428d7b3dSmrg		 PictFormatPtr format,
2041428d7b3dSmrg		 INT16 src_x, INT16 src_y,
2042428d7b3dSmrg		 int nlist, GlyphListPtr list, GlyphPtr *glyphs)
2043428d7b3dSmrg{
2044428d7b3dSmrg	ScreenPtr screen = dst->pDrawable->pScreen;
2045428d7b3dSmrg	CARD32 component_alpha;
2046428d7b3dSmrg	PixmapPtr pixmap;
2047428d7b3dSmrg	PicturePtr mask;
2048428d7b3dSmrg	int16_t x, y, width, height;
2049428d7b3dSmrg	pixman_image_t *mask_image;
2050428d7b3dSmrg	int error;
2051428d7b3dSmrg	bool ret = false;
2052428d7b3dSmrg	BoxRec box;
2053428d7b3dSmrg
2054428d7b3dSmrg	if (NO_GLYPHS_VIA_MASK)
2055428d7b3dSmrg		return false;
2056428d7b3dSmrg
2057428d7b3dSmrg	DBG(("%s(op=%d, src=(%d, %d), nlist=%d,  dst=(%d, %d)+(%d, %d))\n",
2058428d7b3dSmrg	     __FUNCTION__, op, src_x, src_y, nlist,
2059428d7b3dSmrg	     list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y));
2060428d7b3dSmrg
2061428d7b3dSmrg	glyph_extents(nlist, list, glyphs, &box);
2062428d7b3dSmrg	if (box.x2 <= box.x1 || box.y2 <= box.y1)
2063428d7b3dSmrg		return true;
2064428d7b3dSmrg
2065428d7b3dSmrg	DBG(("%s: nlist=%d, count=%d, bounds=((%d, %d), (%d, %d))\n", __FUNCTION__,
2066428d7b3dSmrg	     nlist, glyph_count(nlist, list), box.x1, box.y1, box.x2, box.y2));
2067428d7b3dSmrg
2068428d7b3dSmrg	if (!sna_compute_composite_extents(&box,
2069428d7b3dSmrg					   src, NULL, dst,
2070428d7b3dSmrg					   src_x, src_y,
2071428d7b3dSmrg					   0, 0,
2072428d7b3dSmrg					   box.x1, box.y1,
2073428d7b3dSmrg					   box.x2 - box.x1,
2074428d7b3dSmrg					   box.y2 - box.y1))
2075428d7b3dSmrg		return true;
2076428d7b3dSmrg
2077428d7b3dSmrg	DBG(("%s: extents=((%d, %d), (%d, %d))\n", __FUNCTION__,
2078428d7b3dSmrg	     box.x1, box.y1, box.x2, box.y2));
2079428d7b3dSmrg
2080428d7b3dSmrg	width  = box.x2 - box.x1;
2081428d7b3dSmrg	height = box.y2 - box.y1;
2082428d7b3dSmrg	box.x1 -= dst->pDrawable->x;
2083428d7b3dSmrg	box.y1 -= dst->pDrawable->y;
2084428d7b3dSmrg	x = -box.x1;
2085428d7b3dSmrg	y = -box.y1;
2086428d7b3dSmrg	src_x += box.x1 - list->xOff;
2087428d7b3dSmrg	src_y += box.y1 - list->yOff;
2088428d7b3dSmrg
2089428d7b3dSmrg	if (format->depth < 8) {
2090428d7b3dSmrg		format = PictureMatchFormat(screen, 8, PICT_a8);
2091428d7b3dSmrg		if (!format)
2092428d7b3dSmrg			return false;
2093428d7b3dSmrg	}
2094428d7b3dSmrg
2095428d7b3dSmrg	DBG(("%s: small mask [format=%lx, depth=%d, size=%d], rendering glyphs to upload buffer\n",
2096428d7b3dSmrg	     __FUNCTION__, (unsigned long)format->format,
2097428d7b3dSmrg	     format->depth, (uint32_t)width*height*format->depth));
2098428d7b3dSmrg
2099428d7b3dSmrg	pixmap = sna_pixmap_create_upload(screen,
2100428d7b3dSmrg					  width, height,
2101428d7b3dSmrg					  format->depth,
2102428d7b3dSmrg					  KGEM_BUFFER_WRITE);
2103428d7b3dSmrg	if (!pixmap)
2104428d7b3dSmrg		return false;
2105428d7b3dSmrg
2106428d7b3dSmrg	mask_image =
2107428d7b3dSmrg		pixman_image_create_bits(format->depth << 24 | format->format,
2108428d7b3dSmrg					 width, height,
2109428d7b3dSmrg					 pixmap->devPrivate.ptr,
2110428d7b3dSmrg					 pixmap->devKind);
2111428d7b3dSmrg	if (mask_image == NULL)
2112428d7b3dSmrg		goto err_pixmap;
2113428d7b3dSmrg
2114428d7b3dSmrg	if (sigtrap_get()) {
2115428d7b3dSmrg		pixman_image_unref(mask_image);
2116428d7b3dSmrg		goto err_pixmap;
2117428d7b3dSmrg	}
2118428d7b3dSmrg
2119428d7b3dSmrg	memset(pixmap->devPrivate.ptr, 0, pixmap->devKind*height);
2120428d7b3dSmrg#if HAS_PIXMAN_GLYPHS
2121428d7b3dSmrg	if (__global_glyph_cache) {
2122428d7b3dSmrg		pixman_glyph_t stack_glyphs[N_STACK_GLYPHS];
2123428d7b3dSmrg		pixman_glyph_t *pglyphs = stack_glyphs;
2124428d7b3dSmrg		int count, n;
2125428d7b3dSmrg
2126428d7b3dSmrg		count = 0;
2127428d7b3dSmrg		for (n = 0; n < nlist; ++n)
2128428d7b3dSmrg			count += list[n].len;
2129428d7b3dSmrg		if (count > N_STACK_GLYPHS) {
2130428d7b3dSmrg			pglyphs = malloc(count * sizeof(pixman_glyph_t));
2131428d7b3dSmrg			if (pglyphs == NULL)
2132428d7b3dSmrg				goto err_pixmap;
2133428d7b3dSmrg		}
2134428d7b3dSmrg
2135428d7b3dSmrg		pixman_glyph_cache_freeze(__global_glyph_cache);
2136428d7b3dSmrg		count = 0;
2137428d7b3dSmrg		do {
2138428d7b3dSmrg			n = list->len;
2139428d7b3dSmrg			x += list->xOff;
2140428d7b3dSmrg			y += list->yOff;
2141428d7b3dSmrg			while (n--) {
2142428d7b3dSmrg				GlyphPtr g = *glyphs++;
2143428d7b3dSmrg				const void *ptr;
2144428d7b3dSmrg
2145428d7b3dSmrg				if (!glyph_valid(g))
2146428d7b3dSmrg					goto next_pglyph;
2147428d7b3dSmrg
2148428d7b3dSmrg				ptr = pixman_glyph_cache_lookup(__global_glyph_cache, g, NULL);
2149428d7b3dSmrg				if (ptr == NULL) {
2150428d7b3dSmrg					pixman_image_t *glyph_image;
2151428d7b3dSmrg
2152428d7b3dSmrg					glyph_image = sna_glyph_get_image(g, screen);
2153428d7b3dSmrg					if (glyph_image == NULL)
2154428d7b3dSmrg						goto next_pglyph;
2155428d7b3dSmrg
2156428d7b3dSmrg					DBG(("%s: inserting glyph %p into pixman cache\n", __FUNCTION__, g));
2157428d7b3dSmrg					ptr = pixman_glyph_cache_insert(__global_glyph_cache, g, NULL,
2158428d7b3dSmrg									g->info.x,
2159428d7b3dSmrg									g->info.y,
2160428d7b3dSmrg									glyph_image);
2161428d7b3dSmrg					if (ptr == NULL)
2162428d7b3dSmrg						goto next_pglyph;
2163428d7b3dSmrg				}
2164428d7b3dSmrg
2165428d7b3dSmrg				assert(sna_glyph_get_image(g, screen) != NULL);
2166428d7b3dSmrg
2167428d7b3dSmrg				pglyphs[count].x = x;
2168428d7b3dSmrg				pglyphs[count].y = y;
2169428d7b3dSmrg				pglyphs[count].glyph = ptr;
2170428d7b3dSmrg				count++;
2171428d7b3dSmrg
2172428d7b3dSmrgnext_pglyph:
2173428d7b3dSmrg				x += g->info.xOff;
2174428d7b3dSmrg				y += g->info.yOff;
2175428d7b3dSmrg			}
2176428d7b3dSmrg			list++;
2177428d7b3dSmrg		} while (--nlist);
2178428d7b3dSmrg
2179428d7b3dSmrg		pixman_composite_glyphs_no_mask(PIXMAN_OP_ADD,
2180428d7b3dSmrg						sna->render.white_image,
2181428d7b3dSmrg						mask_image,
2182428d7b3dSmrg						0, 0,
2183428d7b3dSmrg						0, 0,
2184428d7b3dSmrg						__global_glyph_cache, count, pglyphs);
2185428d7b3dSmrg		pixman_glyph_cache_thaw(__global_glyph_cache);
2186428d7b3dSmrg		if (pglyphs != stack_glyphs)
2187428d7b3dSmrg			free(pglyphs);
2188428d7b3dSmrg	} else
2189428d7b3dSmrg#endif
2190428d7b3dSmrg		do {
2191428d7b3dSmrg			int n = list->len;
2192428d7b3dSmrg			x += list->xOff;
2193428d7b3dSmrg			y += list->yOff;
2194428d7b3dSmrg			while (n--) {
2195428d7b3dSmrg				GlyphPtr g = *glyphs++;
2196428d7b3dSmrg				pixman_image_t *glyph_image;
2197428d7b3dSmrg				int16_t xi, yi;
2198428d7b3dSmrg
2199428d7b3dSmrg				if (!glyph_valid(g))
2200428d7b3dSmrg					goto next_image;
2201428d7b3dSmrg
2202428d7b3dSmrg				/* If the mask has been cropped, it is likely
2203428d7b3dSmrg				 * that some of the glyphs fall outside.
2204428d7b3dSmrg				 */
2205428d7b3dSmrg				xi = x - g->info.x;
2206428d7b3dSmrg				yi = y - g->info.y;
2207428d7b3dSmrg				if (xi >= width || yi >= height)
2208428d7b3dSmrg					goto next_image;
2209428d7b3dSmrg				if (xi + g->info.width  <= 0 ||
2210428d7b3dSmrg				    yi + g->info.height <= 0)
2211428d7b3dSmrg					goto next_image;
2212428d7b3dSmrg
2213428d7b3dSmrg				glyph_image = sna_glyph_get_image(g, screen);
2214428d7b3dSmrg				if (glyph_image == NULL)
2215428d7b3dSmrg					goto next_image;
2216428d7b3dSmrg
2217428d7b3dSmrg				DBG(("%s: glyph to mask (%d, %d)x(%d, %d)\n",
2218428d7b3dSmrg				     __FUNCTION__,
2219428d7b3dSmrg				     xi, yi,
2220428d7b3dSmrg				     g->info.width,
2221428d7b3dSmrg				     g->info.height));
2222428d7b3dSmrg
2223428d7b3dSmrg				if (list->format == format) {
2224428d7b3dSmrg					assert(pixman_image_get_format(glyph_image) == pixman_image_get_format(mask_image));
2225428d7b3dSmrg					pixman_image_composite(PictOpAdd,
2226428d7b3dSmrg							       glyph_image,
2227428d7b3dSmrg							       NULL,
2228428d7b3dSmrg							       mask_image,
2229428d7b3dSmrg							       0, 0,
2230428d7b3dSmrg							       0, 0,
2231428d7b3dSmrg							       xi, yi,
2232428d7b3dSmrg							       g->info.width,
2233428d7b3dSmrg							       g->info.height);
2234428d7b3dSmrg				} else {
2235428d7b3dSmrg					pixman_image_composite(PictOpAdd,
2236428d7b3dSmrg							       sna->render.white_image,
2237428d7b3dSmrg							       glyph_image,
2238428d7b3dSmrg							       mask_image,
2239428d7b3dSmrg							       0, 0,
2240428d7b3dSmrg							       0, 0,
2241428d7b3dSmrg							       xi, yi,
2242428d7b3dSmrg							       g->info.width,
2243428d7b3dSmrg							       g->info.height);
2244428d7b3dSmrg				}
2245428d7b3dSmrg
2246428d7b3dSmrgnext_image:
2247428d7b3dSmrg				x += g->info.xOff;
2248428d7b3dSmrg				y += g->info.yOff;
2249428d7b3dSmrg			}
2250428d7b3dSmrg			list++;
2251428d7b3dSmrg		} while (--nlist);
2252428d7b3dSmrg	pixman_image_unref(mask_image);
2253428d7b3dSmrg	sigtrap_put();
2254428d7b3dSmrg
2255428d7b3dSmrg	component_alpha = NeedsComponent(format->format);
2256428d7b3dSmrg
2257428d7b3dSmrg	mask = CreatePicture(0, &pixmap->drawable,
2258428d7b3dSmrg			     format, CPComponentAlpha,
2259428d7b3dSmrg			     &component_alpha, serverClient, &error);
2260428d7b3dSmrg	if (!mask)
2261428d7b3dSmrg		goto err_pixmap;
2262428d7b3dSmrg
2263428d7b3dSmrg	ValidatePicture(mask);
2264428d7b3dSmrg
2265428d7b3dSmrg	sna_composite(op,
2266428d7b3dSmrg		      src, mask, dst,
2267428d7b3dSmrg		      src_x, src_y,
2268428d7b3dSmrg		      0, 0,
2269428d7b3dSmrg		      box.x1, box.y1,
2270428d7b3dSmrg		      width, height);
2271428d7b3dSmrg	FreePicture(mask, 0);
2272428d7b3dSmrg	ret = true;
2273428d7b3dSmrgerr_pixmap:
2274428d7b3dSmrg	sna_pixmap_destroy(pixmap);
2275428d7b3dSmrg	return ret;
2276428d7b3dSmrg}
2277428d7b3dSmrg
2278428d7b3dSmrgvoid
2279428d7b3dSmrgsna_glyphs__shared(CARD8 op,
2280428d7b3dSmrg		   PicturePtr src,
2281428d7b3dSmrg		   PicturePtr dst,
2282428d7b3dSmrg		   PictFormatPtr mask,
2283428d7b3dSmrg		   INT16 src_x, INT16 src_y,
2284428d7b3dSmrg		   int nlist, GlyphListPtr list, GlyphPtr *glyphs)
2285428d7b3dSmrg{
2286428d7b3dSmrg	PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable);
2287428d7b3dSmrg	struct sna *sna = to_sna_from_pixmap(pixmap);
2288428d7b3dSmrg	struct sna_pixmap *priv;
2289428d7b3dSmrg
2290428d7b3dSmrg	DBG(("%s(op=%d, nlist=%d, src=(%d, %d))\n",
2291428d7b3dSmrg	     __FUNCTION__, op, nlist, src_x, src_y));
2292428d7b3dSmrg
2293428d7b3dSmrg	if (RegionNil(dst->pCompositeClip))
2294428d7b3dSmrg		return;
2295428d7b3dSmrg
2296428d7b3dSmrg	if (FALLBACK)
2297428d7b3dSmrg		goto fallback;
2298428d7b3dSmrg
2299428d7b3dSmrg	if (!can_render(sna)) {
2300428d7b3dSmrg		DBG(("%s: wedged\n", __FUNCTION__));
2301428d7b3dSmrg		goto fallback;
2302428d7b3dSmrg	}
2303428d7b3dSmrg
2304428d7b3dSmrg	if (!can_render_to_picture(dst)) {
2305428d7b3dSmrg		DBG(("%s: fallback -- incompatible picture\n", __FUNCTION__));
2306428d7b3dSmrg		goto fallback;
2307428d7b3dSmrg	}
2308428d7b3dSmrg
2309428d7b3dSmrg	priv = sna_pixmap(pixmap);
2310428d7b3dSmrg	if (priv == NULL) {
2311428d7b3dSmrg		DBG(("%s: fallback -- destination unattached\n", __FUNCTION__));
2312428d7b3dSmrg		goto fallback;
2313428d7b3dSmrg	}
2314428d7b3dSmrg
2315428d7b3dSmrg	if (!is_gpu_dst(priv) && !picture_is_gpu(sna, src, 0)) {
2316428d7b3dSmrg		DBG(("%s: fallback -- too small (%dx%d)\n",
2317428d7b3dSmrg		     __FUNCTION__, dst->pDrawable->width, dst->pDrawable->height));
2318428d7b3dSmrg		goto fallback;
2319428d7b3dSmrg	}
2320428d7b3dSmrg
2321428d7b3dSmrg	if (!mask) {
2322428d7b3dSmrg		mask = glyphs_format(nlist, list, glyphs);
2323428d7b3dSmrg		DBG(("%s: substituting mask? %d\n", __FUNCTION__, mask!=NULL));
2324428d7b3dSmrg	}
2325428d7b3dSmrg	if (mask) {
2326428d7b3dSmrg		if (glyphs_via_image(sna, op,
2327428d7b3dSmrg				     src, dst, mask,
2328428d7b3dSmrg				     src_x, src_y,
2329428d7b3dSmrg				     nlist, list, glyphs))
2330428d7b3dSmrg			return;
2331428d7b3dSmrg	}
2332428d7b3dSmrg
2333428d7b3dSmrgfallback:
2334428d7b3dSmrg	glyphs_fallback(op, src, dst, mask, src_x, src_y, nlist, list, glyphs);
2335428d7b3dSmrg}
2336428d7b3dSmrg
2337428d7b3dSmrgvoid
2338428d7b3dSmrgsna_glyph_unrealize(ScreenPtr screen, GlyphPtr glyph)
2339428d7b3dSmrg{
2340428d7b3dSmrg	struct sna_glyph *p = sna_glyph(glyph);
2341428d7b3dSmrg
2342428d7b3dSmrg	DBG(("%s: screen=%d, glyph=%p (image?=%d, atlas?=%d)\n",
2343428d7b3dSmrg	     __FUNCTION__, screen->myNum, glyph, !!p->image,
2344428d7b3dSmrg	     p->atlas && p->atlas != GetGlyphPicture(glyph, screen)));
2345428d7b3dSmrg
2346428d7b3dSmrg	if (p->image) {
2347428d7b3dSmrg#if HAS_PIXMAN_GLYPHS
2348428d7b3dSmrg		if (__global_glyph_cache) {
2349428d7b3dSmrg			DBG(("%s: removing glyph %p from pixman cache\n",
2350428d7b3dSmrg			     __FUNCTION__, glyph));
2351428d7b3dSmrg			pixman_glyph_cache_remove(__global_glyph_cache,
2352428d7b3dSmrg						  glyph, NULL);
2353428d7b3dSmrg		}
2354428d7b3dSmrg#endif
2355428d7b3dSmrg		pixman_image_unref(p->image);
2356428d7b3dSmrg		p->image = NULL;
2357428d7b3dSmrg	}
2358428d7b3dSmrg
2359428d7b3dSmrg	if (p->atlas && p->atlas != GetGlyphPicture(glyph, screen)) {
2360428d7b3dSmrg		struct sna *sna = to_sna_from_screen(screen);
2361428d7b3dSmrg		struct sna_glyph_cache *cache = &sna->render.glyph[p->pos&1];
2362428d7b3dSmrg		DBG(("%s: releasing glyph pos %d from cache %d\n",
2363428d7b3dSmrg		     __FUNCTION__, p->pos >> 1, p->pos & 1));
2364428d7b3dSmrg		assert(cache->glyphs[p->pos >> 1] == p);
2365428d7b3dSmrg		cache->glyphs[p->pos >> 1] = NULL;
2366428d7b3dSmrg		p->atlas = NULL;
2367428d7b3dSmrg	}
2368428d7b3dSmrg
2369428d7b3dSmrg#if HAS_PIXMAN_GLYPHS
2370428d7b3dSmrg	assert(__global_glyph_cache == NULL ||
2371428d7b3dSmrg	       pixman_glyph_cache_lookup(__global_glyph_cache, glyph, NULL) == NULL);
2372428d7b3dSmrg#endif
2373428d7b3dSmrg}
2374