103b705cfSriastradh/*
203b705cfSriastradh * Copyright © 2010 Intel Corporation
303b705cfSriastradh * Partly based on code Copyright © 2008 Red Hat, Inc.
403b705cfSriastradh * Partly based on code Copyright © 2000 SuSE, Inc.
503b705cfSriastradh *
603b705cfSriastradh * Permission to use, copy, modify, distribute, and sell this software and its
703b705cfSriastradh * documentation for any purpose is hereby granted without fee, provided that
803b705cfSriastradh * the above copyright notice appear in all copies and that both that
903b705cfSriastradh * copyright notice and this permission notice appear in supporting
1003b705cfSriastradh * documentation, and that the name of Intel not be used in advertising or
1103b705cfSriastradh * publicity pertaining to distribution of the software without specific,
1203b705cfSriastradh * written prior permission.  Intel makes no representations about the
1303b705cfSriastradh * suitability of this software for any purpose.  It is provided "as is"
1403b705cfSriastradh * without express or implied warranty.
1503b705cfSriastradh *
1603b705cfSriastradh * INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
1703b705cfSriastradh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INTEL
1803b705cfSriastradh * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1903b705cfSriastradh * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
2003b705cfSriastradh * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
2103b705cfSriastradh * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2203b705cfSriastradh *
2303b705cfSriastradh * Permission to use, copy, modify, distribute, and sell this software and its
2403b705cfSriastradh * documentation for any purpose is hereby granted without fee, provided that
2503b705cfSriastradh * the above copyright notice appear in all copies and that both that
2603b705cfSriastradh * copyright notice and this permission notice appear in supporting
2703b705cfSriastradh * documentation, and that the name of Red Hat not be used in advertising or
2803b705cfSriastradh * publicity pertaining to distribution of the software without specific,
2903b705cfSriastradh * written prior permission.  Red Hat makes no representations about the
3003b705cfSriastradh * suitability of this software for any purpose.  It is provided "as is"
3103b705cfSriastradh * without express or implied warranty.
3203b705cfSriastradh *
3303b705cfSriastradh * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
3403b705cfSriastradh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat
3503b705cfSriastradh * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
3603b705cfSriastradh * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
3703b705cfSriastradh * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
3803b705cfSriastradh * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
3903b705cfSriastradh *
4003b705cfSriastradh * Permission to use, copy, modify, distribute, and sell this software and its
4103b705cfSriastradh * documentation for any purpose is hereby granted without fee, provided that
4203b705cfSriastradh * the above copyright notice appear in all copies and that both that
4303b705cfSriastradh * copyright notice and this permission notice appear in supporting
4403b705cfSriastradh * documentation, and that the name of SuSE not be used in advertising or
4503b705cfSriastradh * publicity pertaining to distribution of the software without specific,
4603b705cfSriastradh * written prior permission.  SuSE makes no representations about the
4703b705cfSriastradh * suitability of this software for any purpose.  It is provided "as is"
4803b705cfSriastradh * without express or implied warranty.
4903b705cfSriastradh *
5003b705cfSriastradh * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
5103b705cfSriastradh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
5203b705cfSriastradh * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
5303b705cfSriastradh * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
5403b705cfSriastradh * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
5503b705cfSriastradh * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
5603b705cfSriastradh *
5703b705cfSriastradh * Author: Chris Wilson <chris@chris-wilson.co.uk>
5803b705cfSriastradh * Based on code by: Keith Packard <keithp@keithp.com> and Owen Taylor <otaylor@fishsoup.net>
5903b705cfSriastradh */
6003b705cfSriastradh
6103b705cfSriastradh#ifdef HAVE_CONFIG_H
6203b705cfSriastradh#include "config.h"
6303b705cfSriastradh#endif
6403b705cfSriastradh
6503b705cfSriastradh#include "sna.h"
6603b705cfSriastradh#include "sna_render.h"
6703b705cfSriastradh#include "sna_render_inline.h"
6803b705cfSriastradh#include "fb/fbpict.h"
6903b705cfSriastradh
7003b705cfSriastradh#define FALLBACK 0
7103b705cfSriastradh#define NO_GLYPH_CACHE 0
7203b705cfSriastradh#define NO_GLYPHS_TO_DST 0
7342542f5fSchristos#define FORCE_GLYPHS_TO_DST 0
7403b705cfSriastradh#define NO_GLYPHS_VIA_MASK 0
7542542f5fSchristos#define FORCE_SMALL_MASK 0 /* -1 = never, 1 = always */
7603b705cfSriastradh#define NO_GLYPHS_SLOW 0
77fe8aea9eSmrg#define DISCARD_MASK 0 /* -1 = never, 1 = always */
7803b705cfSriastradh
7903b705cfSriastradh#define CACHE_PICTURE_SIZE 1024
8003b705cfSriastradh#define GLYPH_MIN_SIZE 8
8103b705cfSriastradh#define GLYPH_MAX_SIZE 64
8203b705cfSriastradh#define GLYPH_CACHE_SIZE (CACHE_PICTURE_SIZE * CACHE_PICTURE_SIZE / (GLYPH_MIN_SIZE * GLYPH_MIN_SIZE))
8303b705cfSriastradh
8403b705cfSriastradh#define N_STACK_GLYPHS 512
8542542f5fSchristos#define NO_ATLAS ((PicturePtr)-1)
8642542f5fSchristos#define GLYPH_TOLERANCE 3
8703b705cfSriastradh
8803b705cfSriastradh#define glyph_valid(g) *((uint32_t *)&(g)->info.width)
8903b705cfSriastradh#define glyph_copy_size(r, g) *(uint32_t *)&(r)->width = *(uint32_t *)&g->info.width
9003b705cfSriastradh
9142542f5fSchristos#if HAS_PIXMAN_GLYPHS
9242542f5fSchristosstatic  pixman_glyph_cache_t *__global_glyph_cache;
9342542f5fSchristos#endif
9442542f5fSchristos
9503b705cfSriastradh#if HAS_DEBUG_FULL
9603b705cfSriastradhstatic void _assert_pixmap_contains_box(PixmapPtr pixmap, BoxPtr box, const char *function)
9703b705cfSriastradh{
9803b705cfSriastradh	if (box->x1 < 0 || box->y1 < 0 ||
9903b705cfSriastradh	    box->x2 > pixmap->drawable.width ||
10003b705cfSriastradh	    box->y2 > pixmap->drawable.height)
10103b705cfSriastradh	{
10242542f5fSchristos		FatalError("%s: damage box is beyond the pixmap: box=(%d, %d), (%d, %d), pixmap=(%d, %d)\n",
10342542f5fSchristos			   function,
10442542f5fSchristos			   box->x1, box->y1, box->x2, box->y2,
10542542f5fSchristos			   pixmap->drawable.width,
10642542f5fSchristos			   pixmap->drawable.height);
10703b705cfSriastradh	}
10803b705cfSriastradh}
10903b705cfSriastradh#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__)
11003b705cfSriastradh#else
11103b705cfSriastradh#define assert_pixmap_contains_box(p, b)
11203b705cfSriastradh#endif
11303b705cfSriastradh
11403b705cfSriastradhextern DevPrivateKeyRec sna_glyph_key;
11503b705cfSriastradh
11603b705cfSriastradhstatic inline struct sna_glyph *sna_glyph(GlyphPtr glyph)
11703b705cfSriastradh{
11803b705cfSriastradh	return __get_private(glyph, sna_glyph_key);
11903b705cfSriastradh}
12003b705cfSriastradh
12103b705cfSriastradhstatic inline struct sna_glyph *sna_glyph0(GlyphPtr glyph)
12203b705cfSriastradh{
12303b705cfSriastradh	return (struct sna_glyph *)glyph->devPrivates;
12403b705cfSriastradh}
12503b705cfSriastradh
12603b705cfSriastradhstatic inline bool can_use_glyph0(void)
12703b705cfSriastradh{
12803b705cfSriastradh#if HAS_DEVPRIVATEKEYREC
12903b705cfSriastradh	return sna_glyph_key.offset == 0;
13003b705cfSriastradh#else
13103b705cfSriastradh	return 0;
13203b705cfSriastradh#endif
13303b705cfSriastradh}
13403b705cfSriastradh
13503b705cfSriastradh#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
13603b705cfSriastradh
13703b705cfSriastradhstatic bool op_is_bounded(uint8_t op)
13803b705cfSriastradh{
13903b705cfSriastradh	switch (op) {
14003b705cfSriastradh	case PictOpOver:
14103b705cfSriastradh	case PictOpOutReverse:
14203b705cfSriastradh	case PictOpAdd:
14303b705cfSriastradh	case PictOpXor:
14403b705cfSriastradh		return true;
14503b705cfSriastradh	default:
14603b705cfSriastradh		return false;
14703b705cfSriastradh	}
14803b705cfSriastradh}
14903b705cfSriastradh
15003b705cfSriastradhvoid sna_glyphs_close(struct sna *sna)
15103b705cfSriastradh{
15203b705cfSriastradh	struct sna_render *render = &sna->render;
15303b705cfSriastradh	unsigned int i;
15403b705cfSriastradh
15503b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
15603b705cfSriastradh
15703b705cfSriastradh	for (i = 0; i < ARRAY_SIZE(render->glyph); i++) {
15803b705cfSriastradh		struct sna_glyph_cache *cache = &render->glyph[i];
15903b705cfSriastradh
16003b705cfSriastradh		if (cache->picture)
16103b705cfSriastradh			FreePicture(cache->picture, 0);
16203b705cfSriastradh
16303b705cfSriastradh		free(cache->glyphs);
16403b705cfSriastradh	}
16503b705cfSriastradh	memset(render->glyph, 0, sizeof(render->glyph));
16603b705cfSriastradh
16703b705cfSriastradh	if (render->white_image) {
16803b705cfSriastradh		pixman_image_unref(render->white_image);
16903b705cfSriastradh		render->white_image = NULL;
17003b705cfSriastradh	}
17103b705cfSriastradh	if (render->white_picture) {
17203b705cfSriastradh		FreePicture(render->white_picture, 0);
17303b705cfSriastradh		render->white_picture = NULL;
17403b705cfSriastradh	}
17503b705cfSriastradh}
17603b705cfSriastradh
17703b705cfSriastradh/* All caches for a single format share a single pixmap for glyph storage,
17803b705cfSriastradh * allowing mixing glyphs of different sizes without paying a penalty
17903b705cfSriastradh * for switching between source pixmaps. (Note that for a size of font
18003b705cfSriastradh * right at the border between two sizes, we might be switching for almost
18103b705cfSriastradh * every glyph.)
18203b705cfSriastradh *
18303b705cfSriastradh * This function allocates the storage pixmap, and then fills in the
18403b705cfSriastradh * rest of the allocated structures for all caches with the given format.
18503b705cfSriastradh */
18603b705cfSriastradhbool sna_glyphs_create(struct sna *sna)
18703b705cfSriastradh{
188fe8aea9eSmrg	ScreenPtr screen = to_screen_from_sna(sna);
18903b705cfSriastradh	pixman_color_t white = { 0xffff, 0xffff, 0xffff, 0xffff };
19003b705cfSriastradh	unsigned int formats[] = {
19103b705cfSriastradh		PIXMAN_a8,
19203b705cfSriastradh		PIXMAN_a8r8g8b8,
19303b705cfSriastradh	};
19403b705cfSriastradh	unsigned int i;
19503b705cfSriastradh	int error;
19603b705cfSriastradh
19703b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
19803b705cfSriastradh
19903b705cfSriastradh#if HAS_PIXMAN_GLYPHS
20042542f5fSchristos	if (__global_glyph_cache == NULL) {
20142542f5fSchristos		__global_glyph_cache = pixman_glyph_cache_create();
20242542f5fSchristos		if (__global_glyph_cache == NULL)
20342542f5fSchristos			goto bail;
20442542f5fSchristos	}
20503b705cfSriastradh#endif
20603b705cfSriastradh
20703b705cfSriastradh	sna->render.white_image = pixman_image_create_solid_fill(&white);
20803b705cfSriastradh	if (sna->render.white_image == NULL)
20903b705cfSriastradh		goto bail;
21003b705cfSriastradh
21103b705cfSriastradh	if (!can_render(sna)) {
21203b705cfSriastradh		DBG(("%s: no render acceleration, no render glyph caches\n",
21303b705cfSriastradh		     __FUNCTION__));
21403b705cfSriastradh		return true;
21503b705cfSriastradh	}
21603b705cfSriastradh
21703b705cfSriastradh	if (xf86IsEntityShared(sna->scrn->entityList[0])) {
21803b705cfSriastradh		DBG(("%s: shared GlyphPictures, no render glyph caches\n",
21903b705cfSriastradh		     __FUNCTION__));
22003b705cfSriastradh		return true;
22103b705cfSriastradh	}
22203b705cfSriastradh
22303b705cfSriastradh	for (i = 0; i < ARRAY_SIZE(formats); i++) {
22403b705cfSriastradh		struct sna_glyph_cache *cache = &sna->render.glyph[i];
22503b705cfSriastradh		struct sna_pixmap *priv;
22603b705cfSriastradh		PixmapPtr pixmap;
22703b705cfSriastradh		PicturePtr picture = NULL;
22803b705cfSriastradh		PictFormatPtr pPictFormat;
22903b705cfSriastradh		CARD32 component_alpha;
23003b705cfSriastradh		int depth = PIXMAN_FORMAT_DEPTH(formats[i]);
23103b705cfSriastradh
23203b705cfSriastradh		pPictFormat = PictureMatchFormat(screen, depth, formats[i]);
23303b705cfSriastradh		if (!pPictFormat)
23403b705cfSriastradh			goto bail;
23503b705cfSriastradh
23603b705cfSriastradh		/* Now allocate the pixmap and picture */
23703b705cfSriastradh		pixmap = screen->CreatePixmap(screen,
23803b705cfSriastradh					      CACHE_PICTURE_SIZE,
23903b705cfSriastradh					      CACHE_PICTURE_SIZE,
24003b705cfSriastradh					      depth,
24142542f5fSchristos					      SNA_CREATE_SCRATCH);
24203b705cfSriastradh		if (!pixmap) {
24303b705cfSriastradh			DBG(("%s: failed to allocate pixmap for Glyph cache\n",
24403b705cfSriastradh			     __FUNCTION__));
24503b705cfSriastradh			goto bail;
24603b705cfSriastradh		}
24703b705cfSriastradh
24803b705cfSriastradh		priv = sna_pixmap(pixmap);
24903b705cfSriastradh		if (priv != NULL) {
25003b705cfSriastradh			/* Prevent the cache from ever being paged out */
25142542f5fSchristos			assert(priv->gpu_bo);
25203b705cfSriastradh			priv->pinned = PIN_SCANOUT;
25303b705cfSriastradh
25403b705cfSriastradh			component_alpha = NeedsComponent(pPictFormat->format);
25503b705cfSriastradh			picture = CreatePicture(0, &pixmap->drawable, pPictFormat,
25603b705cfSriastradh						CPComponentAlpha, &component_alpha,
25703b705cfSriastradh						serverClient, &error);
25803b705cfSriastradh		}
25903b705cfSriastradh
26003b705cfSriastradh		screen->DestroyPixmap(pixmap);
26103b705cfSriastradh		if (!picture)
26203b705cfSriastradh			goto bail;
26303b705cfSriastradh
26403b705cfSriastradh		ValidatePicture(picture);
26503b705cfSriastradh		assert(picture->pDrawable == &pixmap->drawable);
26603b705cfSriastradh
26703b705cfSriastradh		cache->count = cache->evict = 0;
26803b705cfSriastradh		cache->picture = picture;
26903b705cfSriastradh		cache->glyphs = calloc(sizeof(struct sna_glyph *),
27003b705cfSriastradh				       GLYPH_CACHE_SIZE);
27103b705cfSriastradh		if (!cache->glyphs)
27203b705cfSriastradh			goto bail;
27303b705cfSriastradh
27403b705cfSriastradh		cache->evict = rand() % GLYPH_CACHE_SIZE;
27503b705cfSriastradh	}
27603b705cfSriastradh
27703b705cfSriastradh	sna->render.white_picture =
27803b705cfSriastradh		CreateSolidPicture(0, (xRenderColor *)&white, &error);
27903b705cfSriastradh	if (sna->render.white_picture == NULL)
28003b705cfSriastradh		goto bail;
28103b705cfSriastradh
28203b705cfSriastradh	return true;
28303b705cfSriastradh
28403b705cfSriastradhbail:
28503b705cfSriastradh	sna_glyphs_close(sna);
28603b705cfSriastradh	return false;
28703b705cfSriastradh}
28803b705cfSriastradh
28903b705cfSriastradhstatic void
29003b705cfSriastradhglyph_cache_upload(struct sna_glyph_cache *cache,
29103b705cfSriastradh		   GlyphPtr glyph, PicturePtr glyph_picture,
29203b705cfSriastradh		   int16_t x, int16_t y)
29303b705cfSriastradh{
29403b705cfSriastradh	DBG(("%s: upload glyph %p to cache (%d, %d)x(%d, %d)\n",
29503b705cfSriastradh	     __FUNCTION__,
29603b705cfSriastradh	     glyph, x, y,
29703b705cfSriastradh	     glyph_picture->pDrawable->width,
29803b705cfSriastradh	     glyph_picture->pDrawable->height));
29903b705cfSriastradh	sna_composite(PictOpSrc,
30003b705cfSriastradh		      glyph_picture, 0, cache->picture,
30103b705cfSriastradh		      0, 0,
30203b705cfSriastradh		      0, 0,
30303b705cfSriastradh		      x, y,
30403b705cfSriastradh		      glyph_picture->pDrawable->width,
30503b705cfSriastradh		      glyph_picture->pDrawable->height);
30603b705cfSriastradh}
30703b705cfSriastradh
30803b705cfSriastradhstatic void
30903b705cfSriastradhglyph_extents(int nlist,
31003b705cfSriastradh	      GlyphListPtr list,
31103b705cfSriastradh	      GlyphPtr *glyphs,
31203b705cfSriastradh	      BoxPtr extents)
31303b705cfSriastradh{
31442542f5fSchristos	int x1, x2, y1, y2;
31542542f5fSchristos	int x, y;
31603b705cfSriastradh
31703b705cfSriastradh	x1 = y1 = MAXSHORT;
31803b705cfSriastradh	x2 = y2 = MINSHORT;
31903b705cfSriastradh	x = y = 0;
32003b705cfSriastradh	while (nlist--) {
32103b705cfSriastradh		int n = list->len;
32203b705cfSriastradh		x += list->xOff;
32303b705cfSriastradh		y += list->yOff;
32403b705cfSriastradh		list++;
32503b705cfSriastradh		while (n--) {
32603b705cfSriastradh			GlyphPtr glyph = *glyphs++;
32703b705cfSriastradh
32803b705cfSriastradh			if (glyph_valid(glyph)) {
32903b705cfSriastradh				int v;
33003b705cfSriastradh
33103b705cfSriastradh				v = x - glyph->info.x;
33203b705cfSriastradh				if (v < x1)
33303b705cfSriastradh					x1 = v;
33403b705cfSriastradh				v += glyph->info.width;
33503b705cfSriastradh				if (v > x2)
33603b705cfSriastradh					x2 = v;
33703b705cfSriastradh
33803b705cfSriastradh				v = y - glyph->info.y;
33903b705cfSriastradh				if (v < y1)
34003b705cfSriastradh					y1 = v;
34103b705cfSriastradh				v += glyph->info.height;
34203b705cfSriastradh				if (v > y2)
34303b705cfSriastradh					y2 = v;
34403b705cfSriastradh			}
34503b705cfSriastradh
34603b705cfSriastradh			x += glyph->info.xOff;
34703b705cfSriastradh			y += glyph->info.yOff;
34803b705cfSriastradh		}
34903b705cfSriastradh	}
35003b705cfSriastradh
35142542f5fSchristos	extents->x1 = x1 > MINSHORT ? x1 : MINSHORT;
35242542f5fSchristos	extents->y1 = y1 > MINSHORT ? y1 : MINSHORT;
35342542f5fSchristos	extents->x2 = x2 < MAXSHORT ? x2 : MAXSHORT;
35442542f5fSchristos	extents->y2 = y2 < MAXSHORT ? y2 : MAXSHORT;
35542542f5fSchristos}
35642542f5fSchristos
35742542f5fSchristos#if HAS_DEBUG_FULL
35842542f5fSchristosstatic int
35942542f5fSchristosglyph_count(int nlist,
36042542f5fSchristos	    GlyphListPtr list)
36142542f5fSchristos{
36242542f5fSchristos	int count = 0;
36342542f5fSchristos	while (nlist--) {
36442542f5fSchristos		count += list->len;
36542542f5fSchristos		list++;
36642542f5fSchristos	}
36742542f5fSchristos	return count;
36803b705cfSriastradh}
36942542f5fSchristos#endif
37003b705cfSriastradh
37103b705cfSriastradhstatic inline unsigned int
37203b705cfSriastradhglyph_size_to_count(int size)
37303b705cfSriastradh{
37403b705cfSriastradh	size /= GLYPH_MIN_SIZE;
37503b705cfSriastradh	return size * size;
37603b705cfSriastradh}
37703b705cfSriastradh
37803b705cfSriastradhstatic inline unsigned int
37903b705cfSriastradhglyph_count_to_mask(int count)
38003b705cfSriastradh{
38103b705cfSriastradh	return ~(count - 1);
38203b705cfSriastradh}
38303b705cfSriastradh
38403b705cfSriastradhstatic inline unsigned int
38503b705cfSriastradhglyph_size_to_mask(int size)
38603b705cfSriastradh{
38703b705cfSriastradh	return glyph_count_to_mask(glyph_size_to_count(size));
38803b705cfSriastradh}
38903b705cfSriastradh
39003b705cfSriastradhstatic int
39103b705cfSriastradhglyph_cache(ScreenPtr screen,
39203b705cfSriastradh	    struct sna_render *render,
39303b705cfSriastradh	    GlyphPtr glyph)
39403b705cfSriastradh{
39503b705cfSriastradh	PicturePtr glyph_picture;
39603b705cfSriastradh	struct sna_glyph_cache *cache;
39703b705cfSriastradh	struct sna_glyph *p;
39803b705cfSriastradh	int size, mask, pos, s;
39903b705cfSriastradh
40042542f5fSchristos	assert(glyph_valid(glyph));
40103b705cfSriastradh
40203b705cfSriastradh	glyph_picture = GetGlyphPicture(glyph, screen);
40303b705cfSriastradh	if (unlikely(glyph_picture == NULL)) {
40403b705cfSriastradh		glyph->info.width = glyph->info.height = 0;
40503b705cfSriastradh		return false;
40603b705cfSriastradh	}
40703b705cfSriastradh
40842542f5fSchristos	if (NO_GLYPH_CACHE ||
40942542f5fSchristos	    glyph->info.width > GLYPH_MAX_SIZE ||
41003b705cfSriastradh	    glyph->info.height > GLYPH_MAX_SIZE) {
41103b705cfSriastradh		PixmapPtr pixmap = (PixmapPtr)glyph_picture->pDrawable;
41203b705cfSriastradh		assert(glyph_picture->pDrawable->type == DRAWABLE_PIXMAP);
41303b705cfSriastradh		if (pixmap->drawable.depth >= 8) {
41403b705cfSriastradh			pixmap->usage_hint = 0;
41503b705cfSriastradh			sna_pixmap_force_to_gpu(pixmap, MOVE_READ);
41603b705cfSriastradh		}
41742542f5fSchristos
41842542f5fSchristos		/* no cache for this glyph */
41942542f5fSchristos		p = sna_glyph(glyph);
42042542f5fSchristos		p->atlas = glyph_picture;
42142542f5fSchristos		p->coordinate.x = p->coordinate.y = 0;
42242542f5fSchristos		return true;
42303b705cfSriastradh	}
42403b705cfSriastradh
42503b705cfSriastradh	for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2)
42603b705cfSriastradh		if (glyph->info.width <= size && glyph->info.height <= size)
42703b705cfSriastradh			break;
42803b705cfSriastradh
42903b705cfSriastradh	cache = &render->glyph[PICT_FORMAT_RGB(glyph_picture->format) != 0];
43003b705cfSriastradh	s = glyph_size_to_count(size);
43103b705cfSriastradh	mask = glyph_count_to_mask(s);
43203b705cfSriastradh	pos = (cache->count + s - 1) & mask;
43303b705cfSriastradh	if (pos < GLYPH_CACHE_SIZE) {
43403b705cfSriastradh		cache->count = pos + s;
43503b705cfSriastradh	} else {
43603b705cfSriastradh		p = NULL;
43703b705cfSriastradh		for (s = size; s <= GLYPH_MAX_SIZE; s *= 2) {
43803b705cfSriastradh			int i = cache->evict & glyph_size_to_mask(s);
43903b705cfSriastradh			p = cache->glyphs[i];
44003b705cfSriastradh			if (p == NULL)
44103b705cfSriastradh				continue;
44203b705cfSriastradh
44303b705cfSriastradh			if (p->size >= s) {
44403b705cfSriastradh				cache->glyphs[i] = NULL;
44503b705cfSriastradh				p->atlas = NULL;
44603b705cfSriastradh				pos = i;
44703b705cfSriastradh			} else
44803b705cfSriastradh				p = NULL;
44903b705cfSriastradh			break;
45003b705cfSriastradh		}
45103b705cfSriastradh		if (p == NULL) {
45203b705cfSriastradh			int count = glyph_size_to_count(size);
45303b705cfSriastradh			pos = cache->evict & glyph_count_to_mask(count);
45403b705cfSriastradh			for (s = 0; s < count; s++) {
45503b705cfSriastradh				p = cache->glyphs[pos + s];
45603b705cfSriastradh				if (p != NULL) {
45703b705cfSriastradh					p->atlas =NULL;
45803b705cfSriastradh					cache->glyphs[pos + s] = NULL;
45903b705cfSriastradh				}
46003b705cfSriastradh			}
46103b705cfSriastradh		}
46203b705cfSriastradh
46303b705cfSriastradh		/* And pick a new eviction position */
46403b705cfSriastradh		cache->evict = rand() % GLYPH_CACHE_SIZE;
46503b705cfSriastradh	}
46603b705cfSriastradh	assert(cache->glyphs[pos] == NULL);
46703b705cfSriastradh
46803b705cfSriastradh	p = sna_glyph(glyph);
46903b705cfSriastradh	DBG(("%s(%d): adding glyph to cache %d, pos %d\n",
47003b705cfSriastradh	     __FUNCTION__, screen->myNum,
47103b705cfSriastradh	     PICT_FORMAT_RGB(glyph_picture->format) != 0, pos));
47203b705cfSriastradh	cache->glyphs[pos] = p;
47303b705cfSriastradh	p->atlas = cache->picture;
47403b705cfSriastradh	p->size = size;
47503b705cfSriastradh	p->pos = pos << 1 | (PICT_FORMAT_RGB(glyph_picture->format) != 0);
47603b705cfSriastradh	s = pos / ((GLYPH_MAX_SIZE / GLYPH_MIN_SIZE) * (GLYPH_MAX_SIZE / GLYPH_MIN_SIZE));
47703b705cfSriastradh	p->coordinate.x = s % (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE) * GLYPH_MAX_SIZE;
47803b705cfSriastradh	p->coordinate.y = (s / (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE)) * GLYPH_MAX_SIZE;
47903b705cfSriastradh	for (s = GLYPH_MIN_SIZE; s < GLYPH_MAX_SIZE; s *= 2) {
48003b705cfSriastradh		if (pos & 1)
48103b705cfSriastradh			p->coordinate.x += s;
48203b705cfSriastradh		if (pos & 2)
48303b705cfSriastradh			p->coordinate.y += s;
48403b705cfSriastradh		pos >>= 2;
48503b705cfSriastradh	}
48603b705cfSriastradh
48703b705cfSriastradh	glyph_cache_upload(cache, glyph, glyph_picture,
48803b705cfSriastradh			   p->coordinate.x, p->coordinate.y);
48903b705cfSriastradh
49003b705cfSriastradh	return true;
49103b705cfSriastradh}
49203b705cfSriastradh
49303b705cfSriastradhstatic void apply_damage(struct sna_composite_op *op,
49403b705cfSriastradh			 const struct sna_composite_rectangles *r)
49503b705cfSriastradh{
49603b705cfSriastradh	BoxRec box;
49703b705cfSriastradh
49803b705cfSriastradh	if (op->damage == NULL)
49903b705cfSriastradh		return;
50003b705cfSriastradh
50103b705cfSriastradh	box.x1 = r->dst.x + op->dst.x;
50203b705cfSriastradh	box.y1 = r->dst.y + op->dst.y;
50303b705cfSriastradh	box.x2 = box.x1 + r->width;
50403b705cfSriastradh	box.y2 = box.y1 + r->height;
50503b705cfSriastradh
50603b705cfSriastradh	assert_pixmap_contains_box(op->dst.pixmap, &box);
50703b705cfSriastradh	sna_damage_add_box(op->damage, &box);
50803b705cfSriastradh}
50903b705cfSriastradh
51003b705cfSriastradhstatic void apply_damage_clipped_to_dst(struct sna_composite_op *op,
51103b705cfSriastradh					const struct sna_composite_rectangles *r,
51203b705cfSriastradh					DrawablePtr dst)
51303b705cfSriastradh{
51403b705cfSriastradh	BoxRec box;
51503b705cfSriastradh
51603b705cfSriastradh	if (op->damage == NULL)
51703b705cfSriastradh		return;
51803b705cfSriastradh
51903b705cfSriastradh	box.x1 = r->dst.x + op->dst.x;
52003b705cfSriastradh	box.y1 = r->dst.y + op->dst.y;
52103b705cfSriastradh	box.x2 = box.x1 + r->width;
52203b705cfSriastradh	box.y2 = box.y1 + r->height;
52303b705cfSriastradh
52403b705cfSriastradh	if (box.x1 < dst->x)
52503b705cfSriastradh		box.x1 = dst->x;
52603b705cfSriastradh
52703b705cfSriastradh	if (box.x2 > op->dst.width)
52803b705cfSriastradh		box.x2 = op->dst.width;
52903b705cfSriastradh
53003b705cfSriastradh	if (box.y1 < dst->y)
53103b705cfSriastradh		box.y1 = dst->y;
53203b705cfSriastradh
53303b705cfSriastradh	if (box.y2 > op->dst.height)
53403b705cfSriastradh		box.y2 = op->dst.height;
53503b705cfSriastradh
53603b705cfSriastradh	assert_pixmap_contains_box(op->dst.pixmap, &box);
53703b705cfSriastradh	sna_damage_add_box(op->damage, &box);
53803b705cfSriastradh}
53903b705cfSriastradh
54042542f5fSchristosstatic inline bool region_matches_pixmap(const RegionRec *r, PixmapPtr pixmap)
54142542f5fSchristos{
54242542f5fSchristos	return (r->extents.x2 - r->extents.x1 >= pixmap->drawable.width &&
54342542f5fSchristos		r->extents.y2 - r->extents.y1 >= pixmap->drawable.height);
54442542f5fSchristos}
54542542f5fSchristos
54642542f5fSchristosstatic inline bool clipped_glyphs(PicturePtr dst, int nlist, GlyphListPtr list, GlyphPtr *glyphs)
54742542f5fSchristos{
54842542f5fSchristos	BoxRec box;
54942542f5fSchristos
55042542f5fSchristos	if (dst->pCompositeClip->data == NULL &&
55142542f5fSchristos	    region_matches_pixmap(dst->pCompositeClip,
55242542f5fSchristos				  get_drawable_pixmap(dst->pDrawable))) {
55342542f5fSchristos		DBG(("%s: no, clip region (%d, %d), (%d, %d) matches drawable pixmap=%ld size=%dx%d\n",
55442542f5fSchristos		     __FUNCTION__,
55542542f5fSchristos		     dst->pCompositeClip->extents.x1,
55642542f5fSchristos		     dst->pCompositeClip->extents.y1,
55742542f5fSchristos		     dst->pCompositeClip->extents.x2,
55842542f5fSchristos		     dst->pCompositeClip->extents.y2,
55942542f5fSchristos		     get_drawable_pixmap(dst->pDrawable),
56042542f5fSchristos		     get_drawable_pixmap(dst->pDrawable)->drawable.width,
56142542f5fSchristos		     get_drawable_pixmap(dst->pDrawable)->drawable.height));
56242542f5fSchristos		return false;
56342542f5fSchristos	}
56442542f5fSchristos
56542542f5fSchristos	glyph_extents(nlist, list, glyphs, &box);
56642542f5fSchristos
56742542f5fSchristos	box.x1 += dst->pDrawable->x;
56842542f5fSchristos	box.x2 += dst->pDrawable->x;
56942542f5fSchristos	box.y1 += dst->pDrawable->y;
57042542f5fSchristos	box.y2 += dst->pDrawable->y;
57142542f5fSchristos
57242542f5fSchristos	DBG(("%s? %d glyph in %d lists extents (%d, %d), (%d, %d), region (%d, %d), (%d, %d): %s\n",
57342542f5fSchristos	     __FUNCTION__, glyph_count(nlist, list), nlist, box.x1, box.y1, box.x2, box.y2,
57442542f5fSchristos	     dst->pCompositeClip->extents.x1, dst->pCompositeClip->extents.y1,
57542542f5fSchristos	     dst->pCompositeClip->extents.x2, dst->pCompositeClip->extents.y2,
57642542f5fSchristos	     pixman_region_contains_rectangle(dst->pCompositeClip,
57742542f5fSchristos					      &box) != PIXMAN_REGION_IN ?  "yes" : "no"));
57842542f5fSchristos
57942542f5fSchristos	return pixman_region_contains_rectangle(dst->pCompositeClip,
58042542f5fSchristos						&box) != PIXMAN_REGION_IN;
58142542f5fSchristos}
58242542f5fSchristos
58303b705cfSriastradhflatten static bool
58403b705cfSriastradhglyphs_to_dst(struct sna *sna,
58503b705cfSriastradh	      CARD8 op,
58603b705cfSriastradh	      PicturePtr src,
58703b705cfSriastradh	      PicturePtr dst,
58803b705cfSriastradh	      INT16 src_x, INT16 src_y,
58903b705cfSriastradh	      int nlist, GlyphListPtr list, GlyphPtr *glyphs)
59003b705cfSriastradh{
59103b705cfSriastradh	struct sna_composite_op tmp;
59203b705cfSriastradh	ScreenPtr screen = dst->pDrawable->pScreen;
59303b705cfSriastradh	PicturePtr glyph_atlas;
59442542f5fSchristos	const BoxRec *rects;
59503b705cfSriastradh	int nrect;
59603b705cfSriastradh	int16_t x, y;
59703b705cfSriastradh
59803b705cfSriastradh	if (NO_GLYPHS_TO_DST)
59903b705cfSriastradh		return false;
60003b705cfSriastradh
60103b705cfSriastradh	memset(&tmp, 0, sizeof(tmp));
60203b705cfSriastradh
60303b705cfSriastradh	DBG(("%s(op=%d, src=(%d, %d), nlist=%d,  dst=(%d, %d)+(%d, %d))\n",
60403b705cfSriastradh	     __FUNCTION__, op, src_x, src_y, nlist,
60503b705cfSriastradh	     list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y));
60603b705cfSriastradh
60742542f5fSchristos	if (clipped_glyphs(dst, nlist, list, glyphs)) {
60842542f5fSchristos		rects = region_rects(dst->pCompositeClip);
60942542f5fSchristos		nrect = region_num_rects(dst->pCompositeClip);
61003b705cfSriastradh	} else
61103b705cfSriastradh		nrect = 0;
61203b705cfSriastradh
61303b705cfSriastradh	x = dst->pDrawable->x;
61403b705cfSriastradh	y = dst->pDrawable->y;
61503b705cfSriastradh	src_x -= list->xOff + x;
61603b705cfSriastradh	src_y -= list->yOff + y;
61703b705cfSriastradh
61842542f5fSchristos	glyph_atlas = NO_ATLAS;
61903b705cfSriastradh	while (nlist--) {
62003b705cfSriastradh		int n = list->len;
62103b705cfSriastradh		x += list->xOff;
62203b705cfSriastradh		y += list->yOff;
62303b705cfSriastradh		while (n--) {
62403b705cfSriastradh			GlyphPtr glyph = *glyphs++;
62503b705cfSriastradh			struct sna_glyph *p;
62603b705cfSriastradh			int i;
62703b705cfSriastradh
62803b705cfSriastradh			p = sna_glyph(glyph);
62942542f5fSchristos			if (unlikely(p->atlas != glyph_atlas)) {
63003b705cfSriastradh				if (unlikely(!glyph_valid(glyph)))
63103b705cfSriastradh					goto next_glyph;
63203b705cfSriastradh
63342542f5fSchristos				if (glyph_atlas != NO_ATLAS) {
63403b705cfSriastradh					tmp.done(sna, &tmp);
63542542f5fSchristos					glyph_atlas = NO_ATLAS;
63603b705cfSriastradh				}
63703b705cfSriastradh
63842542f5fSchristos				if (p->atlas == NULL &&
63942542f5fSchristos				    !glyph_cache(screen, &sna->render, glyph))
64042542f5fSchristos					goto next_glyph;
64103b705cfSriastradh
64203b705cfSriastradh				if (!sna->render.composite(sna,
64303b705cfSriastradh							   op, src, p->atlas, dst,
64403b705cfSriastradh							   0, 0, 0, 0, 0, 0,
64503b705cfSriastradh							   0, 0,
64642542f5fSchristos							   COMPOSITE_PARTIAL, &tmp))
64703b705cfSriastradh					return false;
64803b705cfSriastradh
64903b705cfSriastradh				glyph_atlas = p->atlas;
65003b705cfSriastradh			}
65103b705cfSriastradh
65203b705cfSriastradh			if (nrect) {
65342542f5fSchristos				int xi = x - glyph->info.x;
65442542f5fSchristos				int yi = y - glyph->info.y;
65542542f5fSchristos
65642542f5fSchristos				if (xi < dst->pCompositeClip->extents.x2 &&
65742542f5fSchristos				    yi < dst->pCompositeClip->extents.y2 &&
65842542f5fSchristos				    xi + glyph->info.width  > dst->pCompositeClip->extents.x1 &&
65942542f5fSchristos				    yi + glyph->info.height > dst->pCompositeClip->extents.y1) {
66042542f5fSchristos					for (i = 0; i < nrect; i++) {
66142542f5fSchristos						struct sna_composite_rectangles r;
66242542f5fSchristos						int16_t dx, dy;
66342542f5fSchristos						int16_t x2, y2;
66442542f5fSchristos
66542542f5fSchristos						r.dst.x = xi;
66642542f5fSchristos						r.dst.y = yi;
66742542f5fSchristos						x2 = xi + glyph->info.width;
66842542f5fSchristos						y2 = yi + glyph->info.height;
66942542f5fSchristos						dx = dy = 0;
67042542f5fSchristos
67142542f5fSchristos						DBG(("%s: glyph=(%d, %d), (%d, %d), clip=(%d, %d), (%d, %d)\n",
67242542f5fSchristos						     __FUNCTION__,
67342542f5fSchristos						     r.dst.x, r.dst.y, x2, y2,
67442542f5fSchristos						     rects[i].x1, rects[i].y1,
67542542f5fSchristos						     rects[i].x2, rects[i].y2));
67642542f5fSchristos						if (rects[i].y1 >= y2)
67742542f5fSchristos							break;
67842542f5fSchristos
67942542f5fSchristos						if (r.dst.x < rects[i].x1)
68042542f5fSchristos							dx = rects[i].x1 - r.dst.x, r.dst.x = rects[i].x1;
68142542f5fSchristos						if (x2 > rects[i].x2)
68242542f5fSchristos							x2 = rects[i].x2;
68342542f5fSchristos						if (r.dst.y < rects[i].y1)
68442542f5fSchristos							dy = rects[i].y1 - r.dst.y, r.dst.y = rects[i].y1;
68542542f5fSchristos						if (y2 > rects[i].y2)
68642542f5fSchristos							y2 = rects[i].y2;
68742542f5fSchristos
68842542f5fSchristos						assert(dx >= 0 && dy >= 0);
68942542f5fSchristos
69042542f5fSchristos						if (r.dst.x < x2 && r.dst.y < y2) {
69142542f5fSchristos							DBG(("%s: blt=(%d, %d), (%d, %d)\n",
69242542f5fSchristos							     __FUNCTION__, r.dst.x, r.dst.y, x2, y2));
69342542f5fSchristos
69442542f5fSchristos							r.src.x = r.dst.x + src_x;
69542542f5fSchristos							r.src.y = r.dst.y + src_y;
69642542f5fSchristos							r.mask.x = dx + p->coordinate.x;
69742542f5fSchristos							r.mask.y = dy + p->coordinate.y;
69842542f5fSchristos							r.width  = x2 - r.dst.x;
69942542f5fSchristos							r.height = y2 - r.dst.y;
70042542f5fSchristos							tmp.blt(sna, &tmp, &r);
70142542f5fSchristos							apply_damage(&tmp, &r);
70242542f5fSchristos						}
70303b705cfSriastradh					}
70403b705cfSriastradh				}
70503b705cfSriastradh			} else {
70603b705cfSriastradh				struct sna_composite_rectangles r;
70703b705cfSriastradh
70803b705cfSriastradh				r.dst.x = x - glyph->info.x;
70903b705cfSriastradh				r.dst.y = y - glyph->info.y;
71003b705cfSriastradh				r.src.x = r.dst.x + src_x;
71103b705cfSriastradh				r.src.y = r.dst.y + src_y;
71203b705cfSriastradh				r.mask = p->coordinate;
71303b705cfSriastradh				glyph_copy_size(&r, glyph);
71403b705cfSriastradh
71503b705cfSriastradh				DBG(("%s: glyph=(%d, %d)x(%d, %d), unclipped\n",
71603b705cfSriastradh				     __FUNCTION__,
71703b705cfSriastradh				     r.dst.x, r.dst.y,
71803b705cfSriastradh				     r.width, r.height));
71903b705cfSriastradh
72003b705cfSriastradh				tmp.blt(sna, &tmp, &r);
72103b705cfSriastradh				apply_damage_clipped_to_dst(&tmp, &r, dst->pDrawable);
72203b705cfSriastradh			}
72303b705cfSriastradh
72403b705cfSriastradhnext_glyph:
72503b705cfSriastradh			x += glyph->info.xOff;
72603b705cfSriastradh			y += glyph->info.yOff;
72703b705cfSriastradh		}
72803b705cfSriastradh		list++;
72903b705cfSriastradh	}
73013496ba1Ssnj	if (glyph_atlas != NO_ATLAS)
73103b705cfSriastradh		tmp.done(sna, &tmp);
73203b705cfSriastradh
73303b705cfSriastradh	return true;
73403b705cfSriastradh}
73503b705cfSriastradh
73603b705cfSriastradhflatten static bool
73703b705cfSriastradhglyphs0_to_dst(struct sna *sna,
73803b705cfSriastradh	       CARD8 op,
73903b705cfSriastradh	       PicturePtr src,
74003b705cfSriastradh	       PicturePtr dst,
74103b705cfSriastradh	       INT16 src_x, INT16 src_y,
74203b705cfSriastradh	       int nlist, GlyphListPtr list, GlyphPtr *glyphs)
74303b705cfSriastradh{
74403b705cfSriastradh	struct sna_composite_op tmp;
74503b705cfSriastradh	ScreenPtr screen = dst->pDrawable->pScreen;
74642542f5fSchristos	PicturePtr glyph_atlas = NO_ATLAS;
74742542f5fSchristos	int x, y;
74803b705cfSriastradh
74903b705cfSriastradh	if (NO_GLYPHS_TO_DST)
75003b705cfSriastradh		return false;
75103b705cfSriastradh
75203b705cfSriastradh	memset(&tmp, 0, sizeof(tmp));
75303b705cfSriastradh
75403b705cfSriastradh	DBG(("%s(op=%d, src=(%d, %d), nlist=%d,  dst=(%d, %d)+(%d, %d))\n",
75503b705cfSriastradh	     __FUNCTION__, op, src_x, src_y, nlist,
75603b705cfSriastradh	     list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y));
75703b705cfSriastradh
75803b705cfSriastradh	x = dst->pDrawable->x;
75903b705cfSriastradh	y = dst->pDrawable->y;
76003b705cfSriastradh	src_x -= list->xOff + x;
76103b705cfSriastradh	src_y -= list->yOff + y;
76203b705cfSriastradh
76342542f5fSchristos	if (clipped_glyphs(dst, nlist, list, glyphs)) {
76442542f5fSchristos		const BoxRec *rects = region_rects(dst->pCompositeClip);
76542542f5fSchristos		int nrect = region_num_rects(dst->pCompositeClip);
76642542f5fSchristos		if (nrect == 0)
76742542f5fSchristos			return true;
76842542f5fSchristos
76942542f5fSchristos		while (nlist--) {
77042542f5fSchristos			int n = list->len;
77142542f5fSchristos			x += list->xOff;
77242542f5fSchristos			y += list->yOff;
77342542f5fSchristos			while (n--) {
77442542f5fSchristos				GlyphPtr glyph = *glyphs++;
77542542f5fSchristos				struct sna_glyph *p = sna_glyph0(glyph);
77642542f5fSchristos				int i, xi, yi;
77742542f5fSchristos
77842542f5fSchristos				if (unlikely(p->atlas != glyph_atlas)) {
77942542f5fSchristos					if (unlikely(!glyph_valid(glyph)))
78042542f5fSchristos						goto next_glyph_N;
78142542f5fSchristos
78242542f5fSchristos					if (glyph_atlas != NO_ATLAS) {
78342542f5fSchristos						tmp.done(sna, &tmp);
78442542f5fSchristos						glyph_atlas = NO_ATLAS;
78542542f5fSchristos					}
78642542f5fSchristos
78742542f5fSchristos					if (unlikely(p->atlas == NULL)) {
78842542f5fSchristos						if (!glyph_cache(screen, &sna->render, glyph))
78942542f5fSchristos							goto next_glyph_N;
79042542f5fSchristos					}
79142542f5fSchristos
79242542f5fSchristos					if (!sna->render.composite(sna,
79342542f5fSchristos								   op, src, p->atlas, dst,
79442542f5fSchristos								   0, 0, 0, 0, 0, 0,
79542542f5fSchristos								   0, 0,
79642542f5fSchristos								   COMPOSITE_PARTIAL, &tmp))
79742542f5fSchristos						return false;
79842542f5fSchristos
79942542f5fSchristos					glyph_atlas = p->atlas;
80042542f5fSchristos				}
80142542f5fSchristos
80242542f5fSchristos				xi = x - glyph->info.x;
80342542f5fSchristos				yi = y - glyph->info.y;
80442542f5fSchristos
80542542f5fSchristos				if (xi < dst->pCompositeClip->extents.x2 &&
80642542f5fSchristos				    yi < dst->pCompositeClip->extents.y2 &&
80742542f5fSchristos				    xi + glyph->info.width  > dst->pCompositeClip->extents.x1 &&
80842542f5fSchristos				    yi + glyph->info.height > dst->pCompositeClip->extents.y1) {
80942542f5fSchristos					for (i = 0; i < nrect; i++) {
81042542f5fSchristos						struct sna_composite_rectangles r;
81142542f5fSchristos						int16_t dx, dy;
81242542f5fSchristos						int16_t x2, y2;
81342542f5fSchristos
81442542f5fSchristos						r.dst.x = xi;
81542542f5fSchristos						r.dst.y = yi;
81642542f5fSchristos						x2 = xi + glyph->info.width;
81742542f5fSchristos						y2 = yi + glyph->info.height;
81842542f5fSchristos						dx = dy = 0;
81942542f5fSchristos
82042542f5fSchristos						DBG(("%s: glyph=(%d, %d), (%d, %d), clip=(%d, %d), (%d, %d)\n",
82142542f5fSchristos						     __FUNCTION__,
82242542f5fSchristos						     r.dst.x, r.dst.y, x2, y2,
82342542f5fSchristos						     rects[i].x1, rects[i].y1,
82442542f5fSchristos						     rects[i].x2, rects[i].y2));
82542542f5fSchristos						if (rects[i].y1 >= y2)
82642542f5fSchristos							break;
82742542f5fSchristos
82842542f5fSchristos						if (r.dst.x < rects[i].x1)
82942542f5fSchristos							dx = rects[i].x1 - r.dst.x, r.dst.x = rects[i].x1;
83042542f5fSchristos						if (x2 > rects[i].x2)
83142542f5fSchristos							x2 = rects[i].x2;
83242542f5fSchristos						if (r.dst.y < rects[i].y1)
83342542f5fSchristos							dy = rects[i].y1 - r.dst.y, r.dst.y = rects[i].y1;
83442542f5fSchristos						if (y2 > rects[i].y2)
83542542f5fSchristos							y2 = rects[i].y2;
83642542f5fSchristos
83742542f5fSchristos						assert(dx >= 0 && dy >= 0);
83842542f5fSchristos
83942542f5fSchristos						if (r.dst.x < x2 && r.dst.y < y2) {
84042542f5fSchristos							DBG(("%s: blt=(%d, %d), (%d, %d)\n",
84142542f5fSchristos							     __FUNCTION__, r.dst.x, r.dst.y, x2, y2));
84242542f5fSchristos
84342542f5fSchristos							r.src.x = r.dst.x + src_x;
84442542f5fSchristos							r.src.y = r.dst.y + src_y;
84542542f5fSchristos							r.mask.x = dx + p->coordinate.x;
84642542f5fSchristos							r.mask.y = dy + p->coordinate.y;
84742542f5fSchristos							r.width  = x2 - r.dst.x;
84842542f5fSchristos							r.height = y2 - r.dst.y;
84942542f5fSchristos							tmp.blt(sna, &tmp, &r);
85042542f5fSchristos							apply_damage(&tmp, &r);
85142542f5fSchristos						}
85242542f5fSchristos					}
85342542f5fSchristos				}
85442542f5fSchristos
85542542f5fSchristosnext_glyph_N:
85642542f5fSchristos				x += glyph->info.xOff;
85742542f5fSchristos				y += glyph->info.yOff;
85842542f5fSchristos			}
85942542f5fSchristos			list++;
86042542f5fSchristos		}
86142542f5fSchristos	} else while (nlist--) {
86203b705cfSriastradh		int n = list->len;
86303b705cfSriastradh		x += list->xOff;
86403b705cfSriastradh		y += list->yOff;
86503b705cfSriastradh		while (n--) {
86603b705cfSriastradh			GlyphPtr glyph = *glyphs++;
86742542f5fSchristos			struct sna_glyph *p = sna_glyph0(glyph);
86842542f5fSchristos			struct sna_composite_rectangles r;
86903b705cfSriastradh
87042542f5fSchristos			if (unlikely(p->atlas != glyph_atlas)) {
87103b705cfSriastradh				if (unlikely(!glyph_valid(glyph)))
87242542f5fSchristos					goto next_glyph_0;
87303b705cfSriastradh
87442542f5fSchristos				if (glyph_atlas != NO_ATLAS) {
87503b705cfSriastradh					tmp.done(sna, &tmp);
87642542f5fSchristos					glyph_atlas = NO_ATLAS;
87703b705cfSriastradh				}
87803b705cfSriastradh
87942542f5fSchristos				if (unlikely(p->atlas == NULL)) {
88042542f5fSchristos					if (!glyph_cache(screen, &sna->render, glyph))
88142542f5fSchristos						goto next_glyph_0;
88242542f5fSchristos				}
88303b705cfSriastradh
88403b705cfSriastradh				if (!sna->render.composite(sna,
88503b705cfSriastradh							   op, src, p->atlas, dst,
88603b705cfSriastradh							   0, 0, 0, 0, 0, 0,
88703b705cfSriastradh							   0, 0,
88842542f5fSchristos							   COMPOSITE_PARTIAL, &tmp))
88903b705cfSriastradh					return false;
89003b705cfSriastradh
89103b705cfSriastradh				glyph_atlas = p->atlas;
89203b705cfSriastradh			}
89303b705cfSriastradh
89442542f5fSchristos			r.dst.x = x - glyph->info.x;
89542542f5fSchristos			r.dst.y = y - glyph->info.y;
89642542f5fSchristos			r.src.x = r.dst.x + src_x;
89742542f5fSchristos			r.src.y = r.dst.y + src_y;
89842542f5fSchristos			r.mask = p->coordinate;
89942542f5fSchristos			glyph_copy_size(&r, glyph);
90003b705cfSriastradh
90142542f5fSchristos			DBG(("%s: glyph=(%d, %d)x(%d, %d), unclipped\n",
90242542f5fSchristos			     __FUNCTION__,
90342542f5fSchristos			     r.dst.x, r.dst.y,
90442542f5fSchristos			     r.width, r.height));
90503b705cfSriastradh
90642542f5fSchristos			tmp.blt(sna, &tmp, &r);
90742542f5fSchristos			apply_damage_clipped_to_dst(&tmp, &r, dst->pDrawable);
90803b705cfSriastradh
90942542f5fSchristosnext_glyph_0:
91003b705cfSriastradh			x += glyph->info.xOff;
91103b705cfSriastradh			y += glyph->info.yOff;
91203b705cfSriastradh		}
91303b705cfSriastradh		list++;
91403b705cfSriastradh	}
91542542f5fSchristos	if (glyph_atlas != NO_ATLAS)
91603b705cfSriastradh		tmp.done(sna, &tmp);
91703b705cfSriastradh
91803b705cfSriastradh	return true;
91903b705cfSriastradh}
92003b705cfSriastradh
92103b705cfSriastradhstatic bool
92203b705cfSriastradhglyphs_slow(struct sna *sna,
92303b705cfSriastradh	    CARD8 op,
92403b705cfSriastradh	    PicturePtr src,
92503b705cfSriastradh	    PicturePtr dst,
92603b705cfSriastradh	    INT16 src_x, INT16 src_y,
92703b705cfSriastradh	    int nlist, GlyphListPtr list, GlyphPtr *glyphs)
92803b705cfSriastradh{
92903b705cfSriastradh	struct sna_composite_op tmp;
93003b705cfSriastradh	ScreenPtr screen = dst->pDrawable->pScreen;
93103b705cfSriastradh	int16_t x, y;
93203b705cfSriastradh
93303b705cfSriastradh	if (NO_GLYPHS_SLOW)
93403b705cfSriastradh		return false;
93503b705cfSriastradh
93603b705cfSriastradh	DBG(("%s(op=%d, src=(%d, %d), nlist=%d,  dst=(%d, %d)+(%d, %d))\n",
93703b705cfSriastradh	     __FUNCTION__, op, src_x, src_y, nlist,
93803b705cfSriastradh	     list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y));
93903b705cfSriastradh
94003b705cfSriastradh	x = dst->pDrawable->x;
94103b705cfSriastradh	y = dst->pDrawable->y;
94203b705cfSriastradh	src_x -= list->xOff + x;
94303b705cfSriastradh	src_y -= list->yOff + y;
94403b705cfSriastradh
94503b705cfSriastradh	while (nlist--) {
94603b705cfSriastradh		int n = list->len;
94703b705cfSriastradh		x += list->xOff;
94803b705cfSriastradh		y += list->yOff;
94903b705cfSriastradh		while (n--) {
95003b705cfSriastradh			GlyphPtr glyph = *glyphs++;
95103b705cfSriastradh			struct sna_glyph *p;
95242542f5fSchristos			const BoxRec *rects;
95303b705cfSriastradh			BoxRec box;
95403b705cfSriastradh			int nrect;
95503b705cfSriastradh
95603b705cfSriastradh			box.x1 = x - glyph->info.x;
95703b705cfSriastradh			box.y1 = y - glyph->info.y;
95803b705cfSriastradh			box.x2 = bound(box.x1, glyph->info.width);
95903b705cfSriastradh			box.y2 = bound(box.y1, glyph->info.height);
96003b705cfSriastradh
96103b705cfSriastradh			if (!box_intersect(&box,
96203b705cfSriastradh					   &dst->pCompositeClip->extents))
96303b705cfSriastradh				goto next_glyph;
96403b705cfSriastradh
96503b705cfSriastradh			p = sna_glyph(glyph);
96603b705cfSriastradh			if (unlikely(p->atlas == NULL)) {
96703b705cfSriastradh				if (unlikely(!glyph_valid(glyph)))
96803b705cfSriastradh					goto next_glyph;
96903b705cfSriastradh
97042542f5fSchristos				if (!glyph_cache(screen, &sna->render, glyph))
97142542f5fSchristos					goto next_glyph;
97203b705cfSriastradh			}
97303b705cfSriastradh
97403b705cfSriastradh			DBG(("%s: glyph=(%d, %d)x(%d, %d), src=(%d, %d), mask=(%d, %d)\n",
97503b705cfSriastradh			     __FUNCTION__,
97603b705cfSriastradh			     x - glyph->info.x,
97703b705cfSriastradh			     y - glyph->info.y,
97803b705cfSriastradh			     glyph->info.width,
97903b705cfSriastradh			     glyph->info.height,
98003b705cfSriastradh			     src_x + x - glyph->info.x,
98103b705cfSriastradh			     src_y + y - glyph->info.y,
98203b705cfSriastradh			     p->coordinate.x, p->coordinate.y));
98303b705cfSriastradh
98403b705cfSriastradh			if (!sna->render.composite(sna,
98503b705cfSriastradh						   op, src, p->atlas, dst,
98603b705cfSriastradh						   src_x + x - glyph->info.x,
98703b705cfSriastradh						   src_y + y - glyph->info.y,
98803b705cfSriastradh						   p->coordinate.x, p->coordinate.y,
98903b705cfSriastradh						   x - glyph->info.x,
99003b705cfSriastradh						   y - glyph->info.y,
99103b705cfSriastradh						   glyph->info.width,
99203b705cfSriastradh						   glyph->info.height,
99342542f5fSchristos						   COMPOSITE_PARTIAL, memset(&tmp, 0, sizeof(tmp))))
99403b705cfSriastradh				return false;
99503b705cfSriastradh
99642542f5fSchristos			rects = region_rects(dst->pCompositeClip);
99742542f5fSchristos			nrect = region_num_rects(dst->pCompositeClip);
99803b705cfSriastradh			do {
99903b705cfSriastradh				struct sna_composite_rectangles r;
100003b705cfSriastradh				int16_t x2, y2;
100103b705cfSriastradh
100203b705cfSriastradh				r.dst.x = x - glyph->info.x;
100303b705cfSriastradh				r.dst.y = y - glyph->info.y;
100403b705cfSriastradh				x2 = r.dst.x + glyph->info.width;
100503b705cfSriastradh				y2 = r.dst.y + glyph->info.height;
100603b705cfSriastradh
100703b705cfSriastradh				DBG(("%s: glyph=(%d, %d), (%d, %d), clip=(%d, %d), (%d, %d)\n",
100803b705cfSriastradh				     __FUNCTION__,
100903b705cfSriastradh				     r.dst.x, r.dst.y, x2, y2,
101003b705cfSriastradh				     rects->x1, rects->y1,
101103b705cfSriastradh				     rects->x2, rects->y2));
101203b705cfSriastradh				if (rects->y1 >= y2)
101303b705cfSriastradh					break;
101403b705cfSriastradh
101503b705cfSriastradh				if (r.dst.x < rects->x1)
101603b705cfSriastradh					r.dst.x = rects->x1;
101703b705cfSriastradh				if (x2 > rects->x2)
101803b705cfSriastradh					x2 = rects->x2;
101903b705cfSriastradh
102003b705cfSriastradh				if (r.dst.y < rects->y1)
102103b705cfSriastradh					r.dst.y = rects->y1;
102203b705cfSriastradh				if (y2 > rects->y2)
102303b705cfSriastradh					y2 = rects->y2;
102403b705cfSriastradh
102503b705cfSriastradh				if (r.dst.x < x2 && r.dst.y < y2) {
102603b705cfSriastradh					DBG(("%s: blt=(%d, %d), (%d, %d)\n",
102703b705cfSriastradh					     __FUNCTION__, r.dst.x, r.dst.y, x2, y2));
102803b705cfSriastradh					r.width  = x2 - r.dst.x;
102903b705cfSriastradh					r.height = y2 - r.dst.y;
103003b705cfSriastradh					r.src = r.mask = r .dst;
103103b705cfSriastradh					tmp.blt(sna, &tmp, &r);
103203b705cfSriastradh					apply_damage(&tmp, &r);
103303b705cfSriastradh				}
103403b705cfSriastradh				rects++;
103503b705cfSriastradh			} while (--nrect);
103603b705cfSriastradh			tmp.done(sna, &tmp);
103703b705cfSriastradh
103803b705cfSriastradhnext_glyph:
103903b705cfSriastradh			x += glyph->info.xOff;
104003b705cfSriastradh			y += glyph->info.yOff;
104103b705cfSriastradh		}
104203b705cfSriastradh		list++;
104303b705cfSriastradh	}
104403b705cfSriastradh
104503b705cfSriastradh	return true;
104603b705cfSriastradh}
104703b705cfSriastradh
104803b705cfSriastradhstatic bool
104903b705cfSriastradhclear_pixmap(struct sna *sna, PixmapPtr pixmap)
105003b705cfSriastradh{
105103b705cfSriastradh	struct sna_pixmap *priv = sna_pixmap(pixmap);
105203b705cfSriastradh	return sna->render.clear(sna, pixmap, priv->gpu_bo);
105303b705cfSriastradh}
105403b705cfSriastradh
105503b705cfSriastradhstatic bool
105603b705cfSriastradhtoo_large(struct sna *sna, int width, int height)
105703b705cfSriastradh{
105803b705cfSriastradh	return (width > sna->render.max_3d_size ||
105903b705cfSriastradh		height > sna->render.max_3d_size);
106003b705cfSriastradh}
106103b705cfSriastradh
106203b705cfSriastradhstatic pixman_image_t *
106303b705cfSriastradh__sna_glyph_get_image(GlyphPtr g, ScreenPtr s)
106403b705cfSriastradh{
106503b705cfSriastradh	pixman_image_t *image;
106603b705cfSriastradh	PicturePtr p;
106703b705cfSriastradh	int dx, dy;
106803b705cfSriastradh
106942542f5fSchristos	DBG(("%s: creating image cache for glyph %p (on screen %d)\n", __FUNCTION__, g, s->myNum));
107042542f5fSchristos
107103b705cfSriastradh	p = GetGlyphPicture(g, s);
107203b705cfSriastradh	if (unlikely(p == NULL))
107303b705cfSriastradh		return NULL;
107403b705cfSriastradh
107503b705cfSriastradh	image = image_from_pict(p, FALSE, &dx, &dy);
107603b705cfSriastradh	if (!image)
107703b705cfSriastradh		return NULL;
107803b705cfSriastradh
107903b705cfSriastradh	assert(dx == 0 && dy == 0);
108003b705cfSriastradh	return sna_glyph(g)->image = image;
108103b705cfSriastradh}
108203b705cfSriastradh
108303b705cfSriastradhstatic inline pixman_image_t *
108403b705cfSriastradhsna_glyph_get_image(GlyphPtr g, ScreenPtr s)
108503b705cfSriastradh{
108603b705cfSriastradh	pixman_image_t *image;
108703b705cfSriastradh
108803b705cfSriastradh	image = sna_glyph(g)->image;
108903b705cfSriastradh	if (image == NULL)
109003b705cfSriastradh		image = __sna_glyph_get_image(g, s);
109103b705cfSriastradh
109203b705cfSriastradh	return image;
109303b705cfSriastradh}
109403b705cfSriastradh
109542542f5fSchristosstatic inline bool use_small_mask(struct sna *sna, int16_t width, int16_t height, int depth)
109642542f5fSchristos{
1097fe8aea9eSmrg	if (depth < 8)
1098fe8aea9eSmrg		return true;
1099fe8aea9eSmrg
110042542f5fSchristos	if (FORCE_SMALL_MASK)
110142542f5fSchristos		return FORCE_SMALL_MASK > 0;
110242542f5fSchristos
110342542f5fSchristos	if (depth * width * height < 8 * 4096)
110442542f5fSchristos		return true;
110542542f5fSchristos
110642542f5fSchristos	return too_large(sna, width, height);
110742542f5fSchristos}
110842542f5fSchristos
110903b705cfSriastradhflatten static bool
111003b705cfSriastradhglyphs_via_mask(struct sna *sna,
111103b705cfSriastradh		CARD8 op,
111203b705cfSriastradh		PicturePtr src,
111303b705cfSriastradh		PicturePtr dst,
111403b705cfSriastradh		PictFormatPtr format,
111503b705cfSriastradh		INT16 src_x, INT16 src_y,
111603b705cfSriastradh		int nlist, GlyphListPtr list, GlyphPtr *glyphs)
111703b705cfSriastradh{
111803b705cfSriastradh	ScreenPtr screen = dst->pDrawable->pScreen;
111903b705cfSriastradh	CARD32 component_alpha;
112003b705cfSriastradh	PixmapPtr pixmap;
112142542f5fSchristos	PicturePtr mask;
112203b705cfSriastradh	int16_t x, y, width, height;
112303b705cfSriastradh	int error;
112403b705cfSriastradh	bool ret = false;
112503b705cfSriastradh	BoxRec box;
112603b705cfSriastradh
112703b705cfSriastradh	if (NO_GLYPHS_VIA_MASK)
112803b705cfSriastradh		return false;
112903b705cfSriastradh
113003b705cfSriastradh	DBG(("%s(op=%d, src=(%d, %d), nlist=%d,  dst=(%d, %d)+(%d, %d))\n",
113103b705cfSriastradh	     __FUNCTION__, op, src_x, src_y, nlist,
113203b705cfSriastradh	     list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y));
113303b705cfSriastradh
113403b705cfSriastradh	glyph_extents(nlist, list, glyphs, &box);
113503b705cfSriastradh	if (box.x2 <= box.x1 || box.y2 <= box.y1)
113603b705cfSriastradh		return true;
113703b705cfSriastradh
113842542f5fSchristos	DBG(("%s: nlist=%d, count=%d, bounds=((%d, %d), (%d, %d))\n", __FUNCTION__,
113942542f5fSchristos	     nlist, glyph_count(nlist, list), box.x1, box.y1, box.x2, box.y2));
114003b705cfSriastradh
114103b705cfSriastradh	if (!sna_compute_composite_extents(&box,
114203b705cfSriastradh					   src, NULL, dst,
114303b705cfSriastradh					   src_x, src_y,
114403b705cfSriastradh					   0, 0,
114503b705cfSriastradh					   box.x1, box.y1,
114603b705cfSriastradh					   box.x2 - box.x1,
114703b705cfSriastradh					   box.y2 - box.y1))
114803b705cfSriastradh		return true;
114903b705cfSriastradh
115003b705cfSriastradh	DBG(("%s: extents=((%d, %d), (%d, %d))\n", __FUNCTION__,
115103b705cfSriastradh	     box.x1, box.y1, box.x2, box.y2));
115203b705cfSriastradh
115303b705cfSriastradh	width  = box.x2 - box.x1;
115403b705cfSriastradh	height = box.y2 - box.y1;
115503b705cfSriastradh	box.x1 -= dst->pDrawable->x;
115603b705cfSriastradh	box.y1 -= dst->pDrawable->y;
115703b705cfSriastradh	x = -box.x1;
115803b705cfSriastradh	y = -box.y1;
115903b705cfSriastradh	src_x += box.x1 - list->xOff;
116003b705cfSriastradh	src_y += box.y1 - list->yOff;
116103b705cfSriastradh
116203b705cfSriastradh	component_alpha = NeedsComponent(format->format);
116342542f5fSchristos	if (use_small_mask(sna, width, height, format->depth)) {
116403b705cfSriastradh		pixman_image_t *mask_image;
116503b705cfSriastradh
116642542f5fSchristosuse_small_mask:
116703b705cfSriastradh		DBG(("%s: small mask [format=%lx, depth=%d, size=%d], rendering glyphs to upload buffer\n",
116803b705cfSriastradh		     __FUNCTION__, (unsigned long)format->format,
116903b705cfSriastradh		     format->depth, (uint32_t)width*height*format->depth));
117003b705cfSriastradh
117103b705cfSriastradh		pixmap = sna_pixmap_create_upload(screen,
117203b705cfSriastradh						  width, height,
117303b705cfSriastradh						  format->depth,
117403b705cfSriastradh						  KGEM_BUFFER_WRITE);
117503b705cfSriastradh		if (!pixmap)
117603b705cfSriastradh			return false;
117703b705cfSriastradh
117803b705cfSriastradh		mask_image =
1179fe8aea9eSmrg			pixman_image_create_bits(pixmap->drawable.bitsPerPixel << 24 | format->format,
118003b705cfSriastradh						 width, height,
118103b705cfSriastradh						 pixmap->devPrivate.ptr,
118203b705cfSriastradh						 pixmap->devKind);
118303b705cfSriastradh		if (mask_image == NULL)
118403b705cfSriastradh			goto err_pixmap;
118503b705cfSriastradh
118642542f5fSchristos		if (sigtrap_get()) {
118742542f5fSchristos			pixman_image_unref(mask_image);
118842542f5fSchristos			goto err_pixmap;
118942542f5fSchristos		}
119042542f5fSchristos
119103b705cfSriastradh		memset(pixmap->devPrivate.ptr, 0, pixmap->devKind*height);
119203b705cfSriastradh#if HAS_PIXMAN_GLYPHS
119342542f5fSchristos		if (__global_glyph_cache) {
119403b705cfSriastradh			pixman_glyph_t stack_glyphs[N_STACK_GLYPHS];
119503b705cfSriastradh			pixman_glyph_t *pglyphs = stack_glyphs;
119603b705cfSriastradh			int count, n;
119703b705cfSriastradh
119803b705cfSriastradh			count = 0;
119903b705cfSriastradh			for (n = 0; n < nlist; ++n)
120003b705cfSriastradh				count += list[n].len;
120103b705cfSriastradh			if (count > N_STACK_GLYPHS) {
120203b705cfSriastradh				pglyphs = malloc (count * sizeof(pixman_glyph_t));
120303b705cfSriastradh				if (pglyphs == NULL)
120403b705cfSriastradh					goto err_pixmap;
120503b705cfSriastradh			}
120603b705cfSriastradh
120742542f5fSchristos			pixman_glyph_cache_freeze(__global_glyph_cache);
120803b705cfSriastradh			count = 0;
120903b705cfSriastradh			do {
121003b705cfSriastradh				n = list->len;
121103b705cfSriastradh				x += list->xOff;
121203b705cfSriastradh				y += list->yOff;
121303b705cfSriastradh				while (n--) {
121403b705cfSriastradh					GlyphPtr g = *glyphs++;
121503b705cfSriastradh					const void *ptr;
121603b705cfSriastradh
121703b705cfSriastradh					if (!glyph_valid(g))
121803b705cfSriastradh						goto next_pglyph;
121903b705cfSriastradh
122042542f5fSchristos					ptr = pixman_glyph_cache_lookup(__global_glyph_cache, g, NULL);
122103b705cfSriastradh					if (ptr == NULL) {
122203b705cfSriastradh						pixman_image_t *glyph_image;
122303b705cfSriastradh
122403b705cfSriastradh						glyph_image = sna_glyph_get_image(g, screen);
122503b705cfSriastradh						if (glyph_image == NULL)
122603b705cfSriastradh							goto next_pglyph;
122703b705cfSriastradh
122842542f5fSchristos						DBG(("%s: inserting glyph %p into pixman cache\n", __FUNCTION__, g));
122942542f5fSchristos						ptr = pixman_glyph_cache_insert(__global_glyph_cache, g, NULL,
123003b705cfSriastradh										g->info.x,
123103b705cfSriastradh										g->info.y,
123203b705cfSriastradh										glyph_image);
123303b705cfSriastradh						if (ptr == NULL)
123403b705cfSriastradh							goto next_pglyph;
123503b705cfSriastradh					}
123603b705cfSriastradh
123742542f5fSchristos					assert(sna_glyph_get_image(g, screen) != NULL);
123842542f5fSchristos
123903b705cfSriastradh					pglyphs[count].x = x;
124003b705cfSriastradh					pglyphs[count].y = y;
124103b705cfSriastradh					pglyphs[count].glyph = ptr;
124203b705cfSriastradh					count++;
124303b705cfSriastradh
124403b705cfSriastradhnext_pglyph:
124503b705cfSriastradh					x += g->info.xOff;
124603b705cfSriastradh					y += g->info.yOff;
124703b705cfSriastradh				}
124803b705cfSriastradh				list++;
124903b705cfSriastradh			} while (--nlist);
125003b705cfSriastradh
125103b705cfSriastradh			pixman_composite_glyphs_no_mask(PIXMAN_OP_ADD,
125203b705cfSriastradh							sna->render.white_image,
125303b705cfSriastradh							mask_image,
125403b705cfSriastradh							0, 0,
125503b705cfSriastradh							0, 0,
125642542f5fSchristos							__global_glyph_cache, count, pglyphs);
125742542f5fSchristos			pixman_glyph_cache_thaw(__global_glyph_cache);
125803b705cfSriastradh			if (pglyphs != stack_glyphs)
125903b705cfSriastradh				free(pglyphs);
126003b705cfSriastradh		} else
126103b705cfSriastradh#endif
126203b705cfSriastradh		do {
126303b705cfSriastradh			int n = list->len;
126403b705cfSriastradh			x += list->xOff;
126503b705cfSriastradh			y += list->yOff;
126603b705cfSriastradh			while (n--) {
126703b705cfSriastradh				GlyphPtr g = *glyphs++;
126803b705cfSriastradh				pixman_image_t *glyph_image;
126903b705cfSriastradh				int16_t xi, yi;
127003b705cfSriastradh
127103b705cfSriastradh				if (!glyph_valid(g))
127203b705cfSriastradh					goto next_image;
127303b705cfSriastradh
127403b705cfSriastradh				/* If the mask has been cropped, it is likely
127503b705cfSriastradh				 * that some of the glyphs fall outside.
127603b705cfSriastradh				 */
127703b705cfSriastradh				xi = x - g->info.x;
127803b705cfSriastradh				yi = y - g->info.y;
127903b705cfSriastradh				if (xi >= width || yi >= height)
128003b705cfSriastradh					goto next_image;
128103b705cfSriastradh				if (xi + g->info.width  <= 0 ||
128203b705cfSriastradh				    yi + g->info.height <= 0)
128303b705cfSriastradh					goto next_image;
128403b705cfSriastradh
128503b705cfSriastradh				glyph_image =
128603b705cfSriastradh					sna_glyph_get_image(g, dst->pDrawable->pScreen);
128703b705cfSriastradh				if (glyph_image == NULL)
128803b705cfSriastradh					goto next_image;
128903b705cfSriastradh
129003b705cfSriastradh				DBG(("%s: glyph to mask (%d, %d)x(%d, %d)\n",
129103b705cfSriastradh				     __FUNCTION__,
129203b705cfSriastradh				     xi, yi,
129303b705cfSriastradh				     g->info.width,
129403b705cfSriastradh				     g->info.height));
129503b705cfSriastradh
129603b705cfSriastradh				if (list->format == format) {
129703b705cfSriastradh					assert(pixman_image_get_format(glyph_image) == pixman_image_get_format(mask_image));
129803b705cfSriastradh					pixman_image_composite(PictOpAdd,
129903b705cfSriastradh							       glyph_image,
130003b705cfSriastradh							       NULL,
130103b705cfSriastradh							       mask_image,
130203b705cfSriastradh							       0, 0,
130303b705cfSriastradh							       0, 0,
130403b705cfSriastradh							       xi, yi,
130503b705cfSriastradh							       g->info.width,
130603b705cfSriastradh							       g->info.height);
130703b705cfSriastradh				} else {
130803b705cfSriastradh					pixman_image_composite(PictOpAdd,
130903b705cfSriastradh							       sna->render.white_image,
131003b705cfSriastradh							       glyph_image,
131103b705cfSriastradh							       mask_image,
131203b705cfSriastradh							       0, 0,
131303b705cfSriastradh							       0, 0,
131403b705cfSriastradh							       xi, yi,
131503b705cfSriastradh							       g->info.width,
131603b705cfSriastradh							       g->info.height);
131703b705cfSriastradh				}
131803b705cfSriastradh
131903b705cfSriastradhnext_image:
132003b705cfSriastradh				x += g->info.xOff;
132103b705cfSriastradh				y += g->info.yOff;
132203b705cfSriastradh			}
132303b705cfSriastradh			list++;
132403b705cfSriastradh		} while (--nlist);
132503b705cfSriastradh		pixman_image_unref(mask_image);
132603b705cfSriastradh
132742542f5fSchristos		sigtrap_put();
132842542f5fSchristos
132903b705cfSriastradh		mask = CreatePicture(0, &pixmap->drawable,
133003b705cfSriastradh				     format, CPComponentAlpha,
133103b705cfSriastradh				     &component_alpha, serverClient, &error);
133203b705cfSriastradh		if (!mask)
133303b705cfSriastradh			goto err_pixmap;
133403b705cfSriastradh
133503b705cfSriastradh		ValidatePicture(mask);
133603b705cfSriastradh	} else {
133742542f5fSchristos		struct sna_composite_op tmp;
133842542f5fSchristos		PicturePtr glyph_atlas = NO_ATLAS;
133942542f5fSchristos
134003b705cfSriastradh		pixmap = screen->CreatePixmap(screen,
134103b705cfSriastradh					      width, height, format->depth,
134203b705cfSriastradh					      SNA_CREATE_SCRATCH);
134303b705cfSriastradh		if (!pixmap)
134442542f5fSchristos			goto use_small_mask;
134542542f5fSchristos
134642542f5fSchristos		assert(__sna_pixmap_get_bo(pixmap));
134703b705cfSriastradh
134803b705cfSriastradh		mask = CreatePicture(0, &pixmap->drawable,
134903b705cfSriastradh				     format, CPComponentAlpha,
135003b705cfSriastradh				     &component_alpha, serverClient, &error);
135103b705cfSriastradh		if (!mask)
135203b705cfSriastradh			goto err_pixmap;
135303b705cfSriastradh
135403b705cfSriastradh		ValidatePicture(mask);
135503b705cfSriastradh		if (!clear_pixmap(sna, pixmap))
135603b705cfSriastradh			goto err_mask;
135703b705cfSriastradh
135803b705cfSriastradh		do {
135903b705cfSriastradh			int n = list->len;
136003b705cfSriastradh			x += list->xOff;
136103b705cfSriastradh			y += list->yOff;
136203b705cfSriastradh			while (n--) {
136303b705cfSriastradh				GlyphPtr glyph = *glyphs++;
136442542f5fSchristos				struct sna_glyph *p = sna_glyph(glyph);
136503b705cfSriastradh				struct sna_composite_rectangles r;
136603b705cfSriastradh
136742542f5fSchristos				if (unlikely(p->atlas != glyph_atlas)) {
136842542f5fSchristos					bool ok;
136942542f5fSchristos
137003b705cfSriastradh					if (unlikely(!glyph_valid(glyph)))
137103b705cfSriastradh						goto next_glyph;
137203b705cfSriastradh
137342542f5fSchristos					if (glyph_atlas != NO_ATLAS) {
137403b705cfSriastradh						tmp.done(sna, &tmp);
137542542f5fSchristos						glyph_atlas = NO_ATLAS;
137603b705cfSriastradh					}
137742542f5fSchristos
137842542f5fSchristos					if (unlikely(p->atlas == NULL)) {
137942542f5fSchristos						if (!glyph_cache(screen, &sna->render, glyph))
138003b705cfSriastradh							goto next_glyph;
138103b705cfSriastradh					}
138203b705cfSriastradh
138303b705cfSriastradh					DBG(("%s: atlas format=%08x, mask format=%08x\n",
138403b705cfSriastradh					     __FUNCTION__,
138503b705cfSriastradh					     (int)p->atlas->format,
1386fe8aea9eSmrg					     (int)mask->format));
138742542f5fSchristos
138842542f5fSchristos					memset(&tmp, 0, sizeof(tmp));
1389fe8aea9eSmrg					if (p->atlas->format == mask->format ||
1390fe8aea9eSmrg					    alphaless(p->atlas->format) == mask->format) {
139103b705cfSriastradh						ok = sna->render.composite(sna, PictOpAdd,
139203b705cfSriastradh									   p->atlas, NULL, mask,
139303b705cfSriastradh									   0, 0, 0, 0, 0, 0,
139403b705cfSriastradh									   0, 0,
139542542f5fSchristos									   COMPOSITE_PARTIAL, &tmp);
139603b705cfSriastradh					} else {
139703b705cfSriastradh						ok = sna->render.composite(sna, PictOpAdd,
139803b705cfSriastradh									   sna->render.white_picture, p->atlas, mask,
139903b705cfSriastradh									   0, 0, 0, 0, 0, 0,
140003b705cfSriastradh									   0, 0,
140142542f5fSchristos									   COMPOSITE_PARTIAL, &tmp);
140203b705cfSriastradh					}
140303b705cfSriastradh					if (!ok) {
140403b705cfSriastradh						DBG(("%s: fallback -- can not handle PictOpAdd of glyph onto mask!\n",
140503b705cfSriastradh						     __FUNCTION__));
140603b705cfSriastradh						goto err_mask;
140703b705cfSriastradh					}
140803b705cfSriastradh
140903b705cfSriastradh					glyph_atlas = p->atlas;
141003b705cfSriastradh				}
141103b705cfSriastradh
141203b705cfSriastradh				DBG(("%s: blt glyph origin (%d, %d), offset (%d, %d), src (%d, %d), size (%d, %d)\n",
141303b705cfSriastradh				     __FUNCTION__,
141403b705cfSriastradh				     x, y,
141503b705cfSriastradh				     glyph->info.x, glyph->info.y,
141603b705cfSriastradh				     p->coordinate.x, p->coordinate.y,
141703b705cfSriastradh				     glyph->info.width, glyph->info.height));
141803b705cfSriastradh
141903b705cfSriastradh				r.mask = r.src = p->coordinate;
142003b705cfSriastradh				r.dst.x = x - glyph->info.x;
142103b705cfSriastradh				r.dst.y = y - glyph->info.y;
142203b705cfSriastradh				glyph_copy_size(&r, glyph);
142303b705cfSriastradh				tmp.blt(sna, &tmp, &r);
142403b705cfSriastradh
142503b705cfSriastradhnext_glyph:
142603b705cfSriastradh				x += glyph->info.xOff;
142703b705cfSriastradh				y += glyph->info.yOff;
142803b705cfSriastradh			}
142903b705cfSriastradh			list++;
143003b705cfSriastradh		} while (--nlist);
143142542f5fSchristos		if (glyph_atlas != NO_ATLAS)
143203b705cfSriastradh			tmp.done(sna, &tmp);
143303b705cfSriastradh	}
143403b705cfSriastradh
143503b705cfSriastradh	sna_composite(op,
143603b705cfSriastradh		      src, mask, dst,
143703b705cfSriastradh		      src_x, src_y,
143803b705cfSriastradh		      0, 0,
143903b705cfSriastradh		      box.x1, box.y1,
144003b705cfSriastradh		      width, height);
144103b705cfSriastradh	ret = true;
144203b705cfSriastradherr_mask:
144303b705cfSriastradh	FreePicture(mask, 0);
144403b705cfSriastradherr_pixmap:
144503b705cfSriastradh	sna_pixmap_destroy(pixmap);
144603b705cfSriastradh	return ret;
144703b705cfSriastradh}
144803b705cfSriastradh
144903b705cfSriastradhstatic PictFormatPtr
145003b705cfSriastradhglyphs_format(int nlist, GlyphListPtr list, GlyphPtr * glyphs)
145103b705cfSriastradh{
145203b705cfSriastradh	PictFormatPtr format = list[0].format;
145303b705cfSriastradh	int16_t x1, x2, y1, y2;
145403b705cfSriastradh	int16_t x, y;
145503b705cfSriastradh	BoxRec stack_extents[64], *list_extents = stack_extents;
145603b705cfSriastradh	int i, j;
145703b705cfSriastradh
145803b705cfSriastradh	if (nlist > ARRAY_SIZE(stack_extents)) {
145903b705cfSriastradh		list_extents = malloc(sizeof(BoxRec) * nlist);
146003b705cfSriastradh		if (list_extents == NULL)
146103b705cfSriastradh			return NULL;
146203b705cfSriastradh	}
146303b705cfSriastradh
146442542f5fSchristos	x = y = 0; i = 0;
146542542f5fSchristos	while (nlist--) {
146603b705cfSriastradh		BoxRec extents;
146703b705cfSriastradh		bool first = true;
146803b705cfSriastradh		int n = list->len;
146903b705cfSriastradh
147003b705cfSriastradh		/* Check the intersection of each glyph within the list and
147103b705cfSriastradh		 * then each list against the previous lists.
147203b705cfSriastradh		 *
147303b705cfSriastradh		 * If we overlap then we cannot substitute a mask as the
147403b705cfSriastradh		 * rendering will be altered.
147503b705cfSriastradh		 */
147603b705cfSriastradh		if (format->format != list->format->format) {
147742542f5fSchristos			DBG(("%s: switching formats from %x to %x\n",
147842542f5fSchristos			     __FUNCTION__,
147942542f5fSchristos			     (unsigned)format->format,
148042542f5fSchristos			     (unsigned)list->format->format));
148103b705cfSriastradh			format = NULL;
148203b705cfSriastradh			goto out;
148303b705cfSriastradh		}
148403b705cfSriastradh
148503b705cfSriastradh		x += list->xOff;
148603b705cfSriastradh		y += list->yOff;
148703b705cfSriastradh		list++;
148803b705cfSriastradh		while (n--) {
148903b705cfSriastradh			GlyphPtr glyph = *glyphs++;
149003b705cfSriastradh
149103b705cfSriastradh			if (!glyph_valid(glyph))
149203b705cfSriastradh				goto skip_glyph;
149303b705cfSriastradh
149403b705cfSriastradh			x1 = x - glyph->info.x;
149503b705cfSriastradh			y1 = y - glyph->info.y;
149603b705cfSriastradh			x2 = x1 + glyph->info.width;
149703b705cfSriastradh			y2 = y1 + glyph->info.height;
149803b705cfSriastradh
149903b705cfSriastradh			if (first) {
150003b705cfSriastradh				extents.x1 = x1;
150103b705cfSriastradh				extents.y1 = y1;
150203b705cfSriastradh				extents.x2 = x2;
150303b705cfSriastradh				extents.y2 = y2;
150403b705cfSriastradh				first = false;
150503b705cfSriastradh			} else {
150603b705cfSriastradh				/* Potential overlap?
150703b705cfSriastradh				 * We cheat and ignore the boundary pixels, as
150803b705cfSriastradh				 * the likelihood of an actual overlap of
150903b705cfSriastradh				 * inkedk pixels being noticeable in the
151003b705cfSriastradh				 * boundary is small, yet glyphs frequently
151103b705cfSriastradh				 * overlap on the boundaries.
151203b705cfSriastradh				 */
151342542f5fSchristos				if (x1 < extents.x2-GLYPH_TOLERANCE &&
151442542f5fSchristos				    x2 > extents.x1+GLYPH_TOLERANCE &&
151542542f5fSchristos				    y1 < extents.y2-GLYPH_TOLERANCE &&
151642542f5fSchristos				    y2 > extents.y1+GLYPH_TOLERANCE) {
151742542f5fSchristos					DBG(("%s: overlapping glyph inside line, current bbox (%d, %d), (%d, %d), glyph (%d, %d), (%d, %d)\n",
151842542f5fSchristos					     __FUNCTION__,
151942542f5fSchristos					     extents.x1, extents.y1, extents.x2, extents.y2,
152042542f5fSchristos					     x1, y1, x2, y2));
152103b705cfSriastradh					format = NULL;
152203b705cfSriastradh					goto out;
152303b705cfSriastradh				}
152403b705cfSriastradh
152503b705cfSriastradh				if (x1 < extents.x1)
152603b705cfSriastradh					extents.x1 = x1;
152703b705cfSriastradh				if (x2 > extents.x2)
152803b705cfSriastradh					extents.x2 = x2;
152903b705cfSriastradh				if (y1 < extents.y1)
153003b705cfSriastradh					extents.y1 = y1;
153103b705cfSriastradh				if (y2 > extents.y2)
153203b705cfSriastradh					extents.y2 = y2;
153303b705cfSriastradh			}
153403b705cfSriastradhskip_glyph:
153503b705cfSriastradh			x += glyph->info.xOff;
153603b705cfSriastradh			y += glyph->info.yOff;
153703b705cfSriastradh		}
153803b705cfSriastradh
153903b705cfSriastradh		/* Incrementally building a region is expensive. We expect
154003b705cfSriastradh		 * the number of lists to be small, so just keep a list
154103b705cfSriastradh		 * of the previous boxes and walk those.
154203b705cfSriastradh		 */
154342542f5fSchristos		if (!first) {
154442542f5fSchristos			for (j = 0; j < i; j++) {
154542542f5fSchristos				if (extents.x1 < list_extents[j].x2-GLYPH_TOLERANCE &&
154642542f5fSchristos				    extents.x2 > list_extents[j].x1+GLYPH_TOLERANCE &&
154742542f5fSchristos				    extents.y1 < list_extents[j].y2-GLYPH_TOLERANCE &&
154842542f5fSchristos				    extents.y2 > list_extents[j].y1+GLYPH_TOLERANCE) {
154942542f5fSchristos					DBG(("%s: overlapping lines, current bbox (%d, %d), (%d, %d), previous line (%d, %d), (%d, %d)\n",
155042542f5fSchristos					     __FUNCTION__,
155142542f5fSchristos					     extents.x1, extents.y1, extents.x2, extents.y2,
155242542f5fSchristos					     list_extents[j].x1, list_extents[j].y1,
155342542f5fSchristos					     list_extents[j].x2, list_extents[j].y2));
155442542f5fSchristos					format = NULL;
155542542f5fSchristos					goto out;
155642542f5fSchristos				}
155703b705cfSriastradh			}
155842542f5fSchristos			list_extents[i++] = extents;
155903b705cfSriastradh		}
156003b705cfSriastradh	}
156103b705cfSriastradh
1562fe8aea9eSmrg	assert(format);
1563fe8aea9eSmrg	DBG(("%s: format=%08d, depth=%d\n",
1564fe8aea9eSmrg	     __FUNCTION__, format->format, format->depth));
156503b705cfSriastradhout:
156603b705cfSriastradh	if (list_extents != stack_extents)
156703b705cfSriastradh		free(list_extents);
156803b705cfSriastradh	return format;
156903b705cfSriastradh}
157003b705cfSriastradh
157103b705cfSriastradhstatic bool can_discard_mask(uint8_t op, PicturePtr src, PictFormatPtr mask,
157203b705cfSriastradh			     int nlist, GlyphListPtr list, GlyphPtr *glyphs)
157303b705cfSriastradh{
157403b705cfSriastradh	PictFormatPtr g;
157503b705cfSriastradh	uint32_t color;
157603b705cfSriastradh
1577fe8aea9eSmrg	if (DISCARD_MASK)
1578fe8aea9eSmrg		return DISCARD_MASK > 0;
157903b705cfSriastradh
158042542f5fSchristos	DBG(("%s: nlist=%d, mask=%08x, depth %d, op=%d (bounded? %d)\n",
158142542f5fSchristos	     __FUNCTION__, nlist,
158242542f5fSchristos	     mask ? (unsigned)mask->format : 0, mask ? mask->depth : 0,
158342542f5fSchristos	     op, op_is_bounded(op)));
158442542f5fSchristos
1585fe8aea9eSmrg	if (nlist == 1 && list->len == 1) {
1586fe8aea9eSmrg		if (mask == list->format)
1587fe8aea9eSmrg			return true;
1588fe8aea9eSmrg
1589fe8aea9eSmrg		g = list->format;
1590fe8aea9eSmrg		goto skip;
1591fe8aea9eSmrg	}
159203b705cfSriastradh
1593fe8aea9eSmrg	if (!op_is_bounded(op)) {
1594fe8aea9eSmrg		DBG(("%s: unbounded op, not discarding\n", __FUNCTION__));
159503b705cfSriastradh		return false;
1596fe8aea9eSmrg	}
159703b705cfSriastradh
159803b705cfSriastradh	/* No glyphs overlap and we are not performing a mask conversion. */
159903b705cfSriastradh	g = glyphs_format(nlist, list, glyphs);
1600fe8aea9eSmrg	if (mask == g) {
1601fe8aea9eSmrg		DBG(("%s: mask matches glyphs format, no conversion, so discard mask\n",
1602fe8aea9eSmrg		     __FUNCTION__));
160303b705cfSriastradh		return true;
1604fe8aea9eSmrg	}
160503b705cfSriastradh
160642542f5fSchristos	DBG(("%s: preferred mask format %08x, depth %d\n",
160742542f5fSchristos	     __FUNCTION__, g ? (unsigned)g->format : 0,  g ? g->depth : 0));
160842542f5fSchristos
160903b705cfSriastradh	/* Otherwise if the glyphs are all bitmaps and we have an
161003b705cfSriastradh	 * opaque source we can also render directly to the dst.
161103b705cfSriastradh	 */
161203b705cfSriastradh	if (g == NULL) {
161303b705cfSriastradh		while (nlist--) {
161403b705cfSriastradh			if (list->format->depth != 1)
161503b705cfSriastradh				return false;
161603b705cfSriastradh
161703b705cfSriastradh			list++;
161803b705cfSriastradh		}
1619fe8aea9eSmrg
1620fe8aea9eSmrg		if (!sna_picture_is_solid(src, &color))
1621fe8aea9eSmrg			return false;
1622fe8aea9eSmrg
1623fe8aea9eSmrg		return color >> 24 == 0xff;
162403b705cfSriastradh	} else {
1625fe8aea9eSmrgskip:
1626fe8aea9eSmrg		if (mask->format == g->format)
162703b705cfSriastradh			return true;
162803b705cfSriastradh
1629fe8aea9eSmrg		if (mask->format == alphaless(g->format))
1630fe8aea9eSmrg			return true;
1631fe8aea9eSmrg
1632fe8aea9eSmrg		if (PICT_FORMAT_TYPE(g->format) == PICT_TYPE_A &&
1633fe8aea9eSmrg		    PICT_FORMAT_TYPE(mask->format) != PICT_TYPE_A)
1634fe8aea9eSmrg			return true;
163503b705cfSriastradh
163603b705cfSriastradh		return false;
1637fe8aea9eSmrg	}
1638fe8aea9eSmrg}
163903b705cfSriastradh
1640fe8aea9eSmrgstatic uint32_t pixman_format(PictFormatPtr short_format)
1641fe8aea9eSmrg{
1642fe8aea9eSmrg	uint32_t bpp;
1643fe8aea9eSmrg
1644fe8aea9eSmrg	bpp = short_format->depth;
1645fe8aea9eSmrg	if (bpp <= 1)
1646fe8aea9eSmrg		bpp = 1;
1647fe8aea9eSmrg	else if (bpp <= 8)
1648fe8aea9eSmrg		bpp = 8;
1649fe8aea9eSmrg	else if (bpp <= 16)
1650fe8aea9eSmrg		bpp = 16;
1651fe8aea9eSmrg	else
1652fe8aea9eSmrg		bpp = 32;
1653fe8aea9eSmrg	return bpp << 24 | short_format->format;
165403b705cfSriastradh}
165503b705cfSriastradh
165603b705cfSriastradhstatic void
165703b705cfSriastradhglyphs_fallback(CARD8 op,
165803b705cfSriastradh		PicturePtr src,
165903b705cfSriastradh		PicturePtr dst,
166003b705cfSriastradh		PictFormatPtr mask_format,
166103b705cfSriastradh		int src_x, int src_y,
166203b705cfSriastradh		int nlist, GlyphListPtr list, GlyphPtr *glyphs)
166303b705cfSriastradh{
166403b705cfSriastradh	struct sna *sna = to_sna_from_drawable(dst->pDrawable);
166503b705cfSriastradh	pixman_image_t *src_image, *dst_image;
166603b705cfSriastradh	int src_dx, src_dy;
166703b705cfSriastradh	ScreenPtr screen = dst->pDrawable->pScreen;
166803b705cfSriastradh	RegionRec region;
166903b705cfSriastradh	int x, y, n;
167003b705cfSriastradh
167103b705cfSriastradh	glyph_extents(nlist, list, glyphs, &region.extents);
167242542f5fSchristos	DBG(("%s: nlist=%d, count=%d, extents (%d, %d), (%d, %d)\n", __FUNCTION__,
167342542f5fSchristos	     nlist, glyph_count(nlist, list),
167442542f5fSchristos	     region.extents.x1, region.extents.y1,
167542542f5fSchristos	     region.extents.x2, region.extents.y2));
167642542f5fSchristos
167703b705cfSriastradh	if (region.extents.x2 <= region.extents.x1 ||
167803b705cfSriastradh	    region.extents.y2 <= region.extents.y1)
167903b705cfSriastradh		return;
168003b705cfSriastradh
168103b705cfSriastradh	region.data = NULL;
168203b705cfSriastradh	RegionTranslate(&region, dst->pDrawable->x, dst->pDrawable->y);
168342542f5fSchristos	RegionIntersect(&region, &region, dst->pCompositeClip);
168403b705cfSriastradh	DBG(("%s: clipped extents (%d, %d), (%d, %d)\n",
168503b705cfSriastradh	     __FUNCTION__,
168603b705cfSriastradh	     RegionExtents(&region)->x1, RegionExtents(&region)->y1,
168703b705cfSriastradh	     RegionExtents(&region)->x2, RegionExtents(&region)->y2));
168803b705cfSriastradh	if (RegionNil(&region))
168903b705cfSriastradh		return;
169003b705cfSriastradh
169103b705cfSriastradh	if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &region,
169203b705cfSriastradh					     MOVE_READ | MOVE_WRITE))
169303b705cfSriastradh		return;
169403b705cfSriastradh	if (dst->alphaMap &&
169503b705cfSriastradh	    !sna_drawable_move_to_cpu(dst->alphaMap->pDrawable,
169603b705cfSriastradh				      MOVE_READ | MOVE_WRITE))
169703b705cfSriastradh		return;
169803b705cfSriastradh
169903b705cfSriastradh	if (src->pDrawable) {
170003b705cfSriastradh		if (!sna_drawable_move_to_cpu(src->pDrawable,
170103b705cfSriastradh					      MOVE_READ))
170203b705cfSriastradh			return;
170303b705cfSriastradh
170403b705cfSriastradh		if (src->alphaMap &&
170503b705cfSriastradh		    !sna_drawable_move_to_cpu(src->alphaMap->pDrawable,
170603b705cfSriastradh					      MOVE_READ))
170703b705cfSriastradh			return;
170803b705cfSriastradh	}
170903b705cfSriastradh	RegionTranslate(&region, -dst->pDrawable->x, -dst->pDrawable->y);
171003b705cfSriastradh
171103b705cfSriastradh	if (mask_format &&
171203b705cfSriastradh	    can_discard_mask(op, src, mask_format, nlist, list, glyphs)) {
171303b705cfSriastradh		DBG(("%s: discarding mask\n", __FUNCTION__));
171403b705cfSriastradh		mask_format = NULL;
171503b705cfSriastradh	}
171603b705cfSriastradh
171703b705cfSriastradh#if HAS_PIXMAN_GLYPHS
171842542f5fSchristos	if (__global_glyph_cache) {
171903b705cfSriastradh		pixman_glyph_t stack_glyphs[N_STACK_GLYPHS];
172003b705cfSriastradh		pixman_glyph_t *pglyphs = stack_glyphs;
172103b705cfSriastradh		int dst_x = list->xOff, dst_y = list->yOff;
172203b705cfSriastradh		int dst_dx, dst_dy, count;
172303b705cfSriastradh
172442542f5fSchristos		pixman_glyph_cache_freeze(__global_glyph_cache);
172503b705cfSriastradh
172603b705cfSriastradh		count = 0;
172703b705cfSriastradh		for (n = 0; n < nlist; ++n)
172803b705cfSriastradh			count += list[n].len;
172903b705cfSriastradh		if (count > N_STACK_GLYPHS) {
173042542f5fSchristos			pglyphs = malloc(count * sizeof(pixman_glyph_t));
173103b705cfSriastradh			if (pglyphs == NULL)
173203b705cfSriastradh				goto out;
173303b705cfSriastradh		}
173403b705cfSriastradh
173503b705cfSriastradh		count = 0;
173603b705cfSriastradh		x = y = 0;
173703b705cfSriastradh		while (nlist--) {
173803b705cfSriastradh			n = list->len;
173903b705cfSriastradh			x += list->xOff;
174003b705cfSriastradh			y += list->yOff;
174103b705cfSriastradh			while (n--) {
174203b705cfSriastradh				GlyphPtr g = *glyphs++;
174303b705cfSriastradh				const void *ptr;
174403b705cfSriastradh
174503b705cfSriastradh				if (!glyph_valid(g))
174603b705cfSriastradh					goto next;
174703b705cfSriastradh
174842542f5fSchristos				ptr = pixman_glyph_cache_lookup(__global_glyph_cache, g, NULL);
174903b705cfSriastradh				if (ptr == NULL) {
175003b705cfSriastradh					pixman_image_t *glyph_image;
175103b705cfSriastradh
175203b705cfSriastradh					glyph_image = sna_glyph_get_image(g, screen);
175303b705cfSriastradh					if (glyph_image == NULL)
175403b705cfSriastradh						goto next;
175503b705cfSriastradh
175642542f5fSchristos					DBG(("%s: inserting glyph %p into pixman cache\n", __FUNCTION__, g));
175742542f5fSchristos					ptr = pixman_glyph_cache_insert(__global_glyph_cache, g, NULL,
175803b705cfSriastradh									g->info.x,
175903b705cfSriastradh									g->info.y,
176003b705cfSriastradh									glyph_image);
176103b705cfSriastradh					if (ptr == NULL)
176242542f5fSchristos						goto next;
176303b705cfSriastradh				}
176403b705cfSriastradh
176542542f5fSchristos				assert(sna_glyph_get_image(g, screen) != NULL);
176642542f5fSchristos
176703b705cfSriastradh				pglyphs[count].x = x;
176803b705cfSriastradh				pglyphs[count].y = y;
176903b705cfSriastradh				pglyphs[count].glyph = ptr;
177003b705cfSriastradh				count++;
177103b705cfSriastradh
177203b705cfSriastradhnext:
177303b705cfSriastradh				x += g->info.xOff;
177403b705cfSriastradh				y += g->info.yOff;
177503b705cfSriastradh			}
177603b705cfSriastradh			list++;
177703b705cfSriastradh		}
177803b705cfSriastradh
177942542f5fSchristos		if (count == 0)
178042542f5fSchristos			goto out;
178142542f5fSchristos
178203b705cfSriastradh		src_image = image_from_pict(src, FALSE, &src_dx, &src_dy);
178303b705cfSriastradh		if (src_image == NULL)
178403b705cfSriastradh			goto out;
178503b705cfSriastradh
178603b705cfSriastradh		dst_image = image_from_pict(dst, TRUE, &dst_dx, &dst_dy);
178703b705cfSriastradh		if (dst_image == NULL)
178803b705cfSriastradh			goto out_free_src;
178903b705cfSriastradh
179042542f5fSchristos		if (sigtrap_get() == 0) {
179142542f5fSchristos			if (mask_format) {
179242542f5fSchristos				pixman_composite_glyphs(op, src_image, dst_image,
1793fe8aea9eSmrg							pixman_format(mask_format),
179442542f5fSchristos							src_x + src_dx + region.extents.x1 - dst_x,
179542542f5fSchristos							src_y + src_dy + region.extents.y1 - dst_y,
179642542f5fSchristos							region.extents.x1, region.extents.y1,
179742542f5fSchristos							region.extents.x1 + dst_dx, region.extents.y1 + dst_dy,
179842542f5fSchristos							region.extents.x2 - region.extents.x1,
179942542f5fSchristos							region.extents.y2 - region.extents.y1,
180042542f5fSchristos							__global_glyph_cache, count, pglyphs);
180142542f5fSchristos			} else {
180242542f5fSchristos				pixman_composite_glyphs_no_mask(op, src_image, dst_image,
180342542f5fSchristos								src_x + src_dx - dst_x, src_y + src_dy - dst_y,
180442542f5fSchristos								dst_dx, dst_dy,
180542542f5fSchristos								__global_glyph_cache, count, pglyphs);
180642542f5fSchristos			}
180742542f5fSchristos			sigtrap_put();
180803b705cfSriastradh		}
180903b705cfSriastradh
181003b705cfSriastradh		free_pixman_pict(dst, dst_image);
181103b705cfSriastradh
181203b705cfSriastradhout_free_src:
181303b705cfSriastradh		free_pixman_pict(src, src_image);
181403b705cfSriastradh
181503b705cfSriastradhout:
181642542f5fSchristos		pixman_glyph_cache_thaw(__global_glyph_cache);
181703b705cfSriastradh		if (pglyphs != stack_glyphs)
181803b705cfSriastradh			free(pglyphs);
181903b705cfSriastradh	} else
182003b705cfSriastradh#endif
182103b705cfSriastradh	{
182203b705cfSriastradh		pixman_image_t *mask_image;
182303b705cfSriastradh
182403b705cfSriastradh		dst_image = image_from_pict(dst, TRUE, &x, &y);
182503b705cfSriastradh		if (dst_image == NULL)
182603b705cfSriastradh			goto cleanup_region;
182703b705cfSriastradh		DBG(("%s: dst offset (%d, %d)\n", __FUNCTION__, x, y));
182803b705cfSriastradh		if (x | y) {
182903b705cfSriastradh			region.extents.x1 += x;
183003b705cfSriastradh			region.extents.x2 += x;
183103b705cfSriastradh			region.extents.y1 += y;
183203b705cfSriastradh			region.extents.y2 += y;
183303b705cfSriastradh		}
183403b705cfSriastradh
183503b705cfSriastradh		src_image = image_from_pict(src, FALSE, &src_dx, &src_dy);
183603b705cfSriastradh		if (src_image == NULL)
183703b705cfSriastradh			goto cleanup_dst;
183803b705cfSriastradh		DBG(("%s: src offset (%d, %d)\n", __FUNCTION__, src_dx, src_dy));
183903b705cfSriastradh		src_x += src_dx - list->xOff;
184003b705cfSriastradh		src_y += src_dy - list->yOff;
184103b705cfSriastradh
184203b705cfSriastradh		if (mask_format) {
184303b705cfSriastradh			DBG(("%s: create mask (%d, %d)x(%d,%d) + (%d,%d) + (%d,%d), depth=%d, format=%lx [%lx], ca? %d\n",
184403b705cfSriastradh			     __FUNCTION__,
184503b705cfSriastradh			     region.extents.x1, region.extents.y1,
184603b705cfSriastradh			     region.extents.x2 - region.extents.x1,
184703b705cfSriastradh			     region.extents.y2 - region.extents.y1,
184803b705cfSriastradh			     dst->pDrawable->x, dst->pDrawable->y,
184903b705cfSriastradh			     x, y,
185003b705cfSriastradh			     mask_format->depth,
185103b705cfSriastradh			     (long)mask_format->format,
1852fe8aea9eSmrg			     (long)pixman_format(mask_format),
185303b705cfSriastradh			     NeedsComponent(mask_format->format)));
185403b705cfSriastradh			mask_image =
1855fe8aea9eSmrg				pixman_image_create_bits(pixman_format(mask_format),
185603b705cfSriastradh							 region.extents.x2 - region.extents.x1,
185703b705cfSriastradh							 region.extents.y2 - region.extents.y1,
185803b705cfSriastradh							 NULL, 0);
185903b705cfSriastradh			if (mask_image == NULL)
186003b705cfSriastradh				goto cleanup_src;
186103b705cfSriastradh			if (NeedsComponent(mask_format->format))
186203b705cfSriastradh				pixman_image_set_component_alpha(mask_image, TRUE);
186303b705cfSriastradh
186403b705cfSriastradh			x -= region.extents.x1;
186503b705cfSriastradh			y -= region.extents.y1;
186603b705cfSriastradh		} else {
186703b705cfSriastradh			mask_image = dst_image;
186803b705cfSriastradh			src_x -= x - dst->pDrawable->x;
186903b705cfSriastradh			src_y -= y - dst->pDrawable->y;
187003b705cfSriastradh		}
187103b705cfSriastradh
187242542f5fSchristos		if (sigtrap_get() == 0) {
187342542f5fSchristos			do {
187442542f5fSchristos				n = list->len;
187542542f5fSchristos				x += list->xOff;
187642542f5fSchristos				y += list->yOff;
187742542f5fSchristos				while (n--) {
187842542f5fSchristos					GlyphPtr g = *glyphs++;
187942542f5fSchristos					pixman_image_t *glyph_image;
188003b705cfSriastradh
188142542f5fSchristos					if (!glyph_valid(g))
188242542f5fSchristos						goto next_glyph;
188303b705cfSriastradh
188442542f5fSchristos					glyph_image = sna_glyph_get_image(g, screen);
188542542f5fSchristos					if (glyph_image == NULL)
188642542f5fSchristos						goto next_glyph;
188703b705cfSriastradh
188842542f5fSchristos					if (mask_format) {
188942542f5fSchristos						DBG(("%s: glyph to mask (%d, %d)x(%d, %d)\n",
189042542f5fSchristos						     __FUNCTION__,
189142542f5fSchristos						     x - g->info.x,
189242542f5fSchristos						     y - g->info.y,
189342542f5fSchristos						     g->info.width,
189442542f5fSchristos						     g->info.height));
189542542f5fSchristos
189642542f5fSchristos						if (list->format == mask_format) {
189742542f5fSchristos							assert(pixman_image_get_format(glyph_image) == pixman_image_get_format(mask_image));
189842542f5fSchristos							pixman_image_composite(PictOpAdd,
189942542f5fSchristos									       glyph_image,
190042542f5fSchristos									       NULL,
190142542f5fSchristos									       mask_image,
190242542f5fSchristos									       0, 0,
190342542f5fSchristos									       0, 0,
190442542f5fSchristos									       x - g->info.x,
190542542f5fSchristos									       y - g->info.y,
190642542f5fSchristos									       g->info.width,
190742542f5fSchristos									       g->info.height);
190842542f5fSchristos						} else {
190942542f5fSchristos							pixman_image_composite(PictOpAdd,
191042542f5fSchristos									       sna->render.white_image,
191142542f5fSchristos									       glyph_image,
191242542f5fSchristos									       mask_image,
191342542f5fSchristos									       0, 0,
191442542f5fSchristos									       0, 0,
191542542f5fSchristos									       x - g->info.x,
191642542f5fSchristos									       y - g->info.y,
191742542f5fSchristos									       g->info.width,
191842542f5fSchristos									       g->info.height);
191942542f5fSchristos						}
192003b705cfSriastradh					} else {
192142542f5fSchristos						int xi = x - g->info.x;
192242542f5fSchristos						int yi = y - g->info.y;
192342542f5fSchristos
192442542f5fSchristos						DBG(("%s: glyph to dst (%d, %d)x(%d, %d)/[(%d, %d)x(%d, %d)], src (%d, %d) [op=%d]\n",
192542542f5fSchristos						     __FUNCTION__,
192642542f5fSchristos						     xi, yi,
192742542f5fSchristos						     g->info.width, g->info.height,
192842542f5fSchristos						     dst->pDrawable->x,
192942542f5fSchristos						     dst->pDrawable->y,
193042542f5fSchristos						     dst->pDrawable->width,
193142542f5fSchristos						     dst->pDrawable->height,
193242542f5fSchristos						     src_x + xi,
193342542f5fSchristos						     src_y + yi,
193442542f5fSchristos						     op));
193542542f5fSchristos
193642542f5fSchristos						pixman_image_composite(op,
193742542f5fSchristos								       src_image,
193803b705cfSriastradh								       glyph_image,
193942542f5fSchristos								       dst_image,
194042542f5fSchristos								       src_x + xi,
194142542f5fSchristos								       src_y + yi,
194203b705cfSriastradh								       0, 0,
194342542f5fSchristos								       xi, yi,
194403b705cfSriastradh								       g->info.width,
194503b705cfSriastradh								       g->info.height);
194603b705cfSriastradh					}
194703b705cfSriastradhnext_glyph:
194842542f5fSchristos					x += g->info.xOff;
194942542f5fSchristos					y += g->info.yOff;
195042542f5fSchristos				}
195142542f5fSchristos				list++;
195242542f5fSchristos			} while (--nlist);
195342542f5fSchristos			sigtrap_put();
195442542f5fSchristos		}
195503b705cfSriastradh
195603b705cfSriastradh		if (mask_format) {
195703b705cfSriastradh			DBG(("%s: glyph mask composite src=(%d+%d,%d+%d) dst=(%d, %d)x(%d, %d)\n",
195803b705cfSriastradh			     __FUNCTION__,
195903b705cfSriastradh			     src_x, region.extents.x1, src_y, region.extents.y1,
196003b705cfSriastradh			     region.extents.x1, region.extents.y1,
196103b705cfSriastradh			     region.extents.x2 - region.extents.x1,
196203b705cfSriastradh			     region.extents.y2 - region.extents.y1));
196303b705cfSriastradh			pixman_image_composite(op, src_image, mask_image, dst_image,
196403b705cfSriastradh					       src_x, src_y,
196503b705cfSriastradh					       0, 0,
196603b705cfSriastradh					       region.extents.x1, region.extents.y1,
196703b705cfSriastradh					       region.extents.x2 - region.extents.x1,
196803b705cfSriastradh					       region.extents.y2 - region.extents.y1);
196903b705cfSriastradh			pixman_image_unref(mask_image);
197003b705cfSriastradh		}
197103b705cfSriastradh
197203b705cfSriastradhcleanup_src:
197303b705cfSriastradh		free_pixman_pict(src, src_image);
197403b705cfSriastradhcleanup_dst:
197503b705cfSriastradh		free_pixman_pict(dst, dst_image);
197603b705cfSriastradh	}
197703b705cfSriastradh
197803b705cfSriastradhcleanup_region:
197903b705cfSriastradh	RegionUninit(&region);
198003b705cfSriastradh}
198103b705cfSriastradh
198203b705cfSriastradhvoid
198303b705cfSriastradhsna_glyphs(CARD8 op,
198403b705cfSriastradh	   PicturePtr src,
198503b705cfSriastradh	   PicturePtr dst,
198603b705cfSriastradh	   PictFormatPtr mask,
198703b705cfSriastradh	   INT16 src_x, INT16 src_y,
198803b705cfSriastradh	   int nlist, GlyphListPtr list, GlyphPtr *glyphs)
198903b705cfSriastradh{
199003b705cfSriastradh	PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable);
199103b705cfSriastradh	struct sna *sna = to_sna_from_pixmap(pixmap);
199203b705cfSriastradh	struct sna_pixmap *priv;
199303b705cfSriastradh
199403b705cfSriastradh	DBG(("%s(op=%d, nlist=%d, src=(%d, %d))\n",
199503b705cfSriastradh	     __FUNCTION__, op, nlist, src_x, src_y));
199603b705cfSriastradh
199742542f5fSchristos	if (RegionNil(dst->pCompositeClip))
199803b705cfSriastradh		return;
199903b705cfSriastradh
200003b705cfSriastradh	if (FALLBACK)
200103b705cfSriastradh		goto fallback;
200203b705cfSriastradh
200303b705cfSriastradh	if (!can_render(sna)) {
200403b705cfSriastradh		DBG(("%s: wedged\n", __FUNCTION__));
200503b705cfSriastradh		goto fallback;
200603b705cfSriastradh	}
200703b705cfSriastradh
200813496ba1Ssnj	if (!can_render_to_picture(dst)) {
200913496ba1Ssnj		DBG(("%s: fallback -- dst incompatible picture\n", __FUNCTION__));
201003b705cfSriastradh		goto fallback;
201103b705cfSriastradh	}
201203b705cfSriastradh
201303b705cfSriastradh	priv = sna_pixmap(pixmap);
201403b705cfSriastradh	if (priv == NULL) {
201503b705cfSriastradh		DBG(("%s: fallback -- destination unattached\n", __FUNCTION__));
201603b705cfSriastradh		goto fallback;
201703b705cfSriastradh	}
201803b705cfSriastradh
201942542f5fSchristos	if (!is_gpu_dst(priv) && !picture_is_gpu(sna, src, 0)) {
202003b705cfSriastradh		DBG(("%s: fallback -- too small (%dx%d)\n",
202103b705cfSriastradh		     __FUNCTION__, dst->pDrawable->width, dst->pDrawable->height));
202203b705cfSriastradh		goto fallback;
202303b705cfSriastradh	}
202403b705cfSriastradh
202503b705cfSriastradh	/* Try to discard the mask for non-overlapping glyphs */
202642542f5fSchristos	if (FORCE_GLYPHS_TO_DST ||
202742542f5fSchristos	    mask == NULL ||
202803b705cfSriastradh	    (dst->pCompositeClip->data == NULL &&
202903b705cfSriastradh	     can_discard_mask(op, src, mask, nlist, list, glyphs))) {
203003b705cfSriastradh		DBG(("%s: discarding mask\n", __FUNCTION__));
203103b705cfSriastradh		if (can_use_glyph0()) {
203203b705cfSriastradh			if (glyphs0_to_dst(sna, op,
203303b705cfSriastradh					   src, dst,
203403b705cfSriastradh					   src_x, src_y,
203503b705cfSriastradh					   nlist, list, glyphs))
203603b705cfSriastradh				return;
203703b705cfSriastradh		} else {
203803b705cfSriastradh			if (glyphs_to_dst(sna, op,
203903b705cfSriastradh					  src, dst,
204003b705cfSriastradh					  src_x, src_y,
204103b705cfSriastradh					  nlist, list, glyphs))
204203b705cfSriastradh				return;
204303b705cfSriastradh		}
204403b705cfSriastradh	}
204503b705cfSriastradh
204603b705cfSriastradh	/* Otherwise see if we can substitute a mask */
204703b705cfSriastradh	if (!mask) {
204803b705cfSriastradh		mask = glyphs_format(nlist, list, glyphs);
204903b705cfSriastradh		DBG(("%s: substituting mask? %d\n", __FUNCTION__, mask!=NULL));
205003b705cfSriastradh	}
205103b705cfSriastradh	if (mask) {
205203b705cfSriastradh		if (glyphs_via_mask(sna, op,
205303b705cfSriastradh				    src, dst, mask,
205403b705cfSriastradh				    src_x, src_y,
205503b705cfSriastradh				    nlist, list, glyphs))
205603b705cfSriastradh			return;
205703b705cfSriastradh	} else {
205803b705cfSriastradh		if (glyphs_slow(sna, op,
205903b705cfSriastradh				src, dst,
206003b705cfSriastradh				src_x, src_y,
206103b705cfSriastradh				nlist, list, glyphs))
206203b705cfSriastradh			return;
206303b705cfSriastradh	}
206403b705cfSriastradh
206503b705cfSriastradhfallback:
206603b705cfSriastradh	glyphs_fallback(op, src, dst, mask, src_x, src_y, nlist, list, glyphs);
206703b705cfSriastradh}
206803b705cfSriastradh
206903b705cfSriastradhstatic bool
207003b705cfSriastradhglyphs_via_image(struct sna *sna,
207103b705cfSriastradh		 CARD8 op,
207203b705cfSriastradh		 PicturePtr src,
207303b705cfSriastradh		 PicturePtr dst,
207403b705cfSriastradh		 PictFormatPtr format,
207503b705cfSriastradh		 INT16 src_x, INT16 src_y,
207603b705cfSriastradh		 int nlist, GlyphListPtr list, GlyphPtr *glyphs)
207703b705cfSriastradh{
207803b705cfSriastradh	ScreenPtr screen = dst->pDrawable->pScreen;
207903b705cfSriastradh	CARD32 component_alpha;
208003b705cfSriastradh	PixmapPtr pixmap;
208103b705cfSriastradh	PicturePtr mask;
208203b705cfSriastradh	int16_t x, y, width, height;
208303b705cfSriastradh	pixman_image_t *mask_image;
208403b705cfSriastradh	int error;
208503b705cfSriastradh	bool ret = false;
208603b705cfSriastradh	BoxRec box;
208703b705cfSriastradh
208803b705cfSriastradh	if (NO_GLYPHS_VIA_MASK)
208903b705cfSriastradh		return false;
209003b705cfSriastradh
209103b705cfSriastradh	DBG(("%s(op=%d, src=(%d, %d), nlist=%d,  dst=(%d, %d)+(%d, %d))\n",
209203b705cfSriastradh	     __FUNCTION__, op, src_x, src_y, nlist,
209303b705cfSriastradh	     list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y));
209403b705cfSriastradh
209503b705cfSriastradh	glyph_extents(nlist, list, glyphs, &box);
209603b705cfSriastradh	if (box.x2 <= box.x1 || box.y2 <= box.y1)
209703b705cfSriastradh		return true;
209803b705cfSriastradh
209942542f5fSchristos	DBG(("%s: nlist=%d, count=%d, bounds=((%d, %d), (%d, %d))\n", __FUNCTION__,
210042542f5fSchristos	     nlist, glyph_count(nlist, list), box.x1, box.y1, box.x2, box.y2));
210103b705cfSriastradh
210203b705cfSriastradh	if (!sna_compute_composite_extents(&box,
210303b705cfSriastradh					   src, NULL, dst,
210403b705cfSriastradh					   src_x, src_y,
210503b705cfSriastradh					   0, 0,
210603b705cfSriastradh					   box.x1, box.y1,
210703b705cfSriastradh					   box.x2 - box.x1,
210803b705cfSriastradh					   box.y2 - box.y1))
210903b705cfSriastradh		return true;
211003b705cfSriastradh
211103b705cfSriastradh	DBG(("%s: extents=((%d, %d), (%d, %d))\n", __FUNCTION__,
211203b705cfSriastradh	     box.x1, box.y1, box.x2, box.y2));
211303b705cfSriastradh
211403b705cfSriastradh	width  = box.x2 - box.x1;
211503b705cfSriastradh	height = box.y2 - box.y1;
211603b705cfSriastradh	box.x1 -= dst->pDrawable->x;
211703b705cfSriastradh	box.y1 -= dst->pDrawable->y;
211803b705cfSriastradh	x = -box.x1;
211903b705cfSriastradh	y = -box.y1;
212003b705cfSriastradh	src_x += box.x1 - list->xOff;
212103b705cfSriastradh	src_y += box.y1 - list->yOff;
212203b705cfSriastradh
212303b705cfSriastradh	DBG(("%s: small mask [format=%lx, depth=%d, size=%d], rendering glyphs to upload buffer\n",
212403b705cfSriastradh	     __FUNCTION__, (unsigned long)format->format,
212503b705cfSriastradh	     format->depth, (uint32_t)width*height*format->depth));
212603b705cfSriastradh
212703b705cfSriastradh	pixmap = sna_pixmap_create_upload(screen,
212803b705cfSriastradh					  width, height,
212903b705cfSriastradh					  format->depth,
213003b705cfSriastradh					  KGEM_BUFFER_WRITE);
213103b705cfSriastradh	if (!pixmap)
213203b705cfSriastradh		return false;
213303b705cfSriastradh
213403b705cfSriastradh	mask_image =
2135fe8aea9eSmrg		pixman_image_create_bits(pixmap->drawable.bitsPerPixel << 24 | format->format,
213603b705cfSriastradh					 width, height,
213703b705cfSriastradh					 pixmap->devPrivate.ptr,
213803b705cfSriastradh					 pixmap->devKind);
213903b705cfSriastradh	if (mask_image == NULL)
214003b705cfSriastradh		goto err_pixmap;
214103b705cfSriastradh
214242542f5fSchristos	if (sigtrap_get()) {
214342542f5fSchristos		pixman_image_unref(mask_image);
214442542f5fSchristos		goto err_pixmap;
214542542f5fSchristos	}
214642542f5fSchristos
214703b705cfSriastradh	memset(pixmap->devPrivate.ptr, 0, pixmap->devKind*height);
214803b705cfSriastradh#if HAS_PIXMAN_GLYPHS
214942542f5fSchristos	if (__global_glyph_cache) {
215003b705cfSriastradh		pixman_glyph_t stack_glyphs[N_STACK_GLYPHS];
215103b705cfSriastradh		pixman_glyph_t *pglyphs = stack_glyphs;
215203b705cfSriastradh		int count, n;
215303b705cfSriastradh
215403b705cfSriastradh		count = 0;
215503b705cfSriastradh		for (n = 0; n < nlist; ++n)
215603b705cfSriastradh			count += list[n].len;
215703b705cfSriastradh		if (count > N_STACK_GLYPHS) {
215842542f5fSchristos			pglyphs = malloc(count * sizeof(pixman_glyph_t));
215903b705cfSriastradh			if (pglyphs == NULL)
216003b705cfSriastradh				goto err_pixmap;
216103b705cfSriastradh		}
216203b705cfSriastradh
216342542f5fSchristos		pixman_glyph_cache_freeze(__global_glyph_cache);
216403b705cfSriastradh		count = 0;
216503b705cfSriastradh		do {
216603b705cfSriastradh			n = list->len;
216703b705cfSriastradh			x += list->xOff;
216803b705cfSriastradh			y += list->yOff;
216903b705cfSriastradh			while (n--) {
217003b705cfSriastradh				GlyphPtr g = *glyphs++;
217103b705cfSriastradh				const void *ptr;
217203b705cfSriastradh
217303b705cfSriastradh				if (!glyph_valid(g))
217403b705cfSriastradh					goto next_pglyph;
217503b705cfSriastradh
217642542f5fSchristos				ptr = pixman_glyph_cache_lookup(__global_glyph_cache, g, NULL);
217703b705cfSriastradh				if (ptr == NULL) {
217803b705cfSriastradh					pixman_image_t *glyph_image;
217903b705cfSriastradh
218003b705cfSriastradh					glyph_image = sna_glyph_get_image(g, screen);
218103b705cfSriastradh					if (glyph_image == NULL)
218203b705cfSriastradh						goto next_pglyph;
218303b705cfSriastradh
218442542f5fSchristos					DBG(("%s: inserting glyph %p into pixman cache\n", __FUNCTION__, g));
218542542f5fSchristos					ptr = pixman_glyph_cache_insert(__global_glyph_cache, g, NULL,
218603b705cfSriastradh									g->info.x,
218703b705cfSriastradh									g->info.y,
218803b705cfSriastradh									glyph_image);
218903b705cfSriastradh					if (ptr == NULL)
219003b705cfSriastradh						goto next_pglyph;
219103b705cfSriastradh				}
219203b705cfSriastradh
219342542f5fSchristos				assert(sna_glyph_get_image(g, screen) != NULL);
219442542f5fSchristos
219503b705cfSriastradh				pglyphs[count].x = x;
219603b705cfSriastradh				pglyphs[count].y = y;
219703b705cfSriastradh				pglyphs[count].glyph = ptr;
219803b705cfSriastradh				count++;
219903b705cfSriastradh
220003b705cfSriastradhnext_pglyph:
220103b705cfSriastradh				x += g->info.xOff;
220203b705cfSriastradh				y += g->info.yOff;
220303b705cfSriastradh			}
220403b705cfSriastradh			list++;
220503b705cfSriastradh		} while (--nlist);
220603b705cfSriastradh
220703b705cfSriastradh		pixman_composite_glyphs_no_mask(PIXMAN_OP_ADD,
220803b705cfSriastradh						sna->render.white_image,
220903b705cfSriastradh						mask_image,
221003b705cfSriastradh						0, 0,
221103b705cfSriastradh						0, 0,
221242542f5fSchristos						__global_glyph_cache, count, pglyphs);
221342542f5fSchristos		pixman_glyph_cache_thaw(__global_glyph_cache);
221403b705cfSriastradh		if (pglyphs != stack_glyphs)
221503b705cfSriastradh			free(pglyphs);
221603b705cfSriastradh	} else
221703b705cfSriastradh#endif
221803b705cfSriastradh		do {
221903b705cfSriastradh			int n = list->len;
222003b705cfSriastradh			x += list->xOff;
222103b705cfSriastradh			y += list->yOff;
222203b705cfSriastradh			while (n--) {
222303b705cfSriastradh				GlyphPtr g = *glyphs++;
222403b705cfSriastradh				pixman_image_t *glyph_image;
222503b705cfSriastradh				int16_t xi, yi;
222603b705cfSriastradh
222703b705cfSriastradh				if (!glyph_valid(g))
222803b705cfSriastradh					goto next_image;
222903b705cfSriastradh
223003b705cfSriastradh				/* If the mask has been cropped, it is likely
223103b705cfSriastradh				 * that some of the glyphs fall outside.
223203b705cfSriastradh				 */
223303b705cfSriastradh				xi = x - g->info.x;
223403b705cfSriastradh				yi = y - g->info.y;
223503b705cfSriastradh				if (xi >= width || yi >= height)
223603b705cfSriastradh					goto next_image;
223703b705cfSriastradh				if (xi + g->info.width  <= 0 ||
223803b705cfSriastradh				    yi + g->info.height <= 0)
223903b705cfSriastradh					goto next_image;
224003b705cfSriastradh
224142542f5fSchristos				glyph_image = sna_glyph_get_image(g, screen);
224203b705cfSriastradh				if (glyph_image == NULL)
224303b705cfSriastradh					goto next_image;
224403b705cfSriastradh
224503b705cfSriastradh				DBG(("%s: glyph to mask (%d, %d)x(%d, %d)\n",
224603b705cfSriastradh				     __FUNCTION__,
224703b705cfSriastradh				     xi, yi,
224803b705cfSriastradh				     g->info.width,
224903b705cfSriastradh				     g->info.height));
225003b705cfSriastradh
225103b705cfSriastradh				if (list->format == format) {
225203b705cfSriastradh					assert(pixman_image_get_format(glyph_image) == pixman_image_get_format(mask_image));
225303b705cfSriastradh					pixman_image_composite(PictOpAdd,
225403b705cfSriastradh							       glyph_image,
225503b705cfSriastradh							       NULL,
225603b705cfSriastradh							       mask_image,
225703b705cfSriastradh							       0, 0,
225803b705cfSriastradh							       0, 0,
225903b705cfSriastradh							       xi, yi,
226003b705cfSriastradh							       g->info.width,
226103b705cfSriastradh							       g->info.height);
226203b705cfSriastradh				} else {
226303b705cfSriastradh					pixman_image_composite(PictOpAdd,
226403b705cfSriastradh							       sna->render.white_image,
226503b705cfSriastradh							       glyph_image,
226603b705cfSriastradh							       mask_image,
226703b705cfSriastradh							       0, 0,
226803b705cfSriastradh							       0, 0,
226903b705cfSriastradh							       xi, yi,
227003b705cfSriastradh							       g->info.width,
227103b705cfSriastradh							       g->info.height);
227203b705cfSriastradh				}
227303b705cfSriastradh
227403b705cfSriastradhnext_image:
227503b705cfSriastradh				x += g->info.xOff;
227603b705cfSriastradh				y += g->info.yOff;
227703b705cfSriastradh			}
227803b705cfSriastradh			list++;
227903b705cfSriastradh		} while (--nlist);
228003b705cfSriastradh	pixman_image_unref(mask_image);
228142542f5fSchristos	sigtrap_put();
228203b705cfSriastradh
228303b705cfSriastradh	component_alpha = NeedsComponent(format->format);
228403b705cfSriastradh
228503b705cfSriastradh	mask = CreatePicture(0, &pixmap->drawable,
228603b705cfSriastradh			     format, CPComponentAlpha,
228703b705cfSriastradh			     &component_alpha, serverClient, &error);
228803b705cfSriastradh	if (!mask)
228903b705cfSriastradh		goto err_pixmap;
229003b705cfSriastradh
229103b705cfSriastradh	ValidatePicture(mask);
229203b705cfSriastradh
229303b705cfSriastradh	sna_composite(op,
229403b705cfSriastradh		      src, mask, dst,
229503b705cfSriastradh		      src_x, src_y,
229603b705cfSriastradh		      0, 0,
229703b705cfSriastradh		      box.x1, box.y1,
229803b705cfSriastradh		      width, height);
229903b705cfSriastradh	FreePicture(mask, 0);
230003b705cfSriastradh	ret = true;
230103b705cfSriastradherr_pixmap:
230203b705cfSriastradh	sna_pixmap_destroy(pixmap);
230303b705cfSriastradh	return ret;
230403b705cfSriastradh}
230503b705cfSriastradh
230603b705cfSriastradhvoid
230703b705cfSriastradhsna_glyphs__shared(CARD8 op,
230803b705cfSriastradh		   PicturePtr src,
230903b705cfSriastradh		   PicturePtr dst,
231003b705cfSriastradh		   PictFormatPtr mask,
231103b705cfSriastradh		   INT16 src_x, INT16 src_y,
231203b705cfSriastradh		   int nlist, GlyphListPtr list, GlyphPtr *glyphs)
231303b705cfSriastradh{
231403b705cfSriastradh	PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable);
231503b705cfSriastradh	struct sna *sna = to_sna_from_pixmap(pixmap);
231603b705cfSriastradh	struct sna_pixmap *priv;
231703b705cfSriastradh
231803b705cfSriastradh	DBG(("%s(op=%d, nlist=%d, src=(%d, %d))\n",
231903b705cfSriastradh	     __FUNCTION__, op, nlist, src_x, src_y));
232003b705cfSriastradh
232142542f5fSchristos	if (RegionNil(dst->pCompositeClip))
232203b705cfSriastradh		return;
232303b705cfSriastradh
232403b705cfSriastradh	if (FALLBACK)
232503b705cfSriastradh		goto fallback;
232603b705cfSriastradh
232703b705cfSriastradh	if (!can_render(sna)) {
232803b705cfSriastradh		DBG(("%s: wedged\n", __FUNCTION__));
232903b705cfSriastradh		goto fallback;
233003b705cfSriastradh	}
233103b705cfSriastradh
233213496ba1Ssnj	if (!can_render_to_picture(dst)) {
233313496ba1Ssnj		DBG(("%s: fallback -- incompatible picture\n", __FUNCTION__));
233403b705cfSriastradh		goto fallback;
233503b705cfSriastradh	}
233603b705cfSriastradh
233703b705cfSriastradh	priv = sna_pixmap(pixmap);
233803b705cfSriastradh	if (priv == NULL) {
233903b705cfSriastradh		DBG(("%s: fallback -- destination unattached\n", __FUNCTION__));
234003b705cfSriastradh		goto fallback;
234103b705cfSriastradh	}
234203b705cfSriastradh
234342542f5fSchristos	if (!is_gpu_dst(priv) && !picture_is_gpu(sna, src, 0)) {
234403b705cfSriastradh		DBG(("%s: fallback -- too small (%dx%d)\n",
234503b705cfSriastradh		     __FUNCTION__, dst->pDrawable->width, dst->pDrawable->height));
234603b705cfSriastradh		goto fallback;
234703b705cfSriastradh	}
234803b705cfSriastradh
234903b705cfSriastradh	if (!mask) {
235003b705cfSriastradh		mask = glyphs_format(nlist, list, glyphs);
235103b705cfSriastradh		DBG(("%s: substituting mask? %d\n", __FUNCTION__, mask!=NULL));
235203b705cfSriastradh	}
235303b705cfSriastradh	if (mask) {
235403b705cfSriastradh		if (glyphs_via_image(sna, op,
235503b705cfSriastradh				     src, dst, mask,
235603b705cfSriastradh				     src_x, src_y,
235703b705cfSriastradh				     nlist, list, glyphs))
235803b705cfSriastradh			return;
235903b705cfSriastradh	}
236003b705cfSriastradh
236103b705cfSriastradhfallback:
236203b705cfSriastradh	glyphs_fallback(op, src, dst, mask, src_x, src_y, nlist, list, glyphs);
236303b705cfSriastradh}
236403b705cfSriastradh
236503b705cfSriastradhvoid
236603b705cfSriastradhsna_glyph_unrealize(ScreenPtr screen, GlyphPtr glyph)
236703b705cfSriastradh{
236803b705cfSriastradh	struct sna_glyph *p = sna_glyph(glyph);
236903b705cfSriastradh
237042542f5fSchristos	DBG(("%s: screen=%d, glyph=%p (image?=%d, atlas?=%d)\n",
237142542f5fSchristos	     __FUNCTION__, screen->myNum, glyph, !!p->image,
237242542f5fSchristos	     p->atlas && p->atlas != GetGlyphPicture(glyph, screen)));
237303b705cfSriastradh
237403b705cfSriastradh	if (p->image) {
237503b705cfSriastradh#if HAS_PIXMAN_GLYPHS
237642542f5fSchristos		if (__global_glyph_cache) {
237742542f5fSchristos			DBG(("%s: removing glyph %p from pixman cache\n",
237842542f5fSchristos			     __FUNCTION__, glyph));
237942542f5fSchristos			pixman_glyph_cache_remove(__global_glyph_cache,
238003b705cfSriastradh						  glyph, NULL);
238142542f5fSchristos		}
238203b705cfSriastradh#endif
238303b705cfSriastradh		pixman_image_unref(p->image);
238403b705cfSriastradh		p->image = NULL;
238503b705cfSriastradh	}
238603b705cfSriastradh
238703b705cfSriastradh	if (p->atlas && p->atlas != GetGlyphPicture(glyph, screen)) {
238803b705cfSriastradh		struct sna *sna = to_sna_from_screen(screen);
238903b705cfSriastradh		struct sna_glyph_cache *cache = &sna->render.glyph[p->pos&1];
239003b705cfSriastradh		DBG(("%s: releasing glyph pos %d from cache %d\n",
239103b705cfSriastradh		     __FUNCTION__, p->pos >> 1, p->pos & 1));
239203b705cfSriastradh		assert(cache->glyphs[p->pos >> 1] == p);
239303b705cfSriastradh		cache->glyphs[p->pos >> 1] = NULL;
239403b705cfSriastradh		p->atlas = NULL;
239503b705cfSriastradh	}
239642542f5fSchristos
239742542f5fSchristos#if HAS_PIXMAN_GLYPHS
239842542f5fSchristos	assert(__global_glyph_cache == NULL ||
239942542f5fSchristos	       pixman_glyph_cache_lookup(__global_glyph_cache, glyph, NULL) == NULL);
240042542f5fSchristos#endif
240103b705cfSriastradh}
2402