sna_glyphs.c revision 13496ba1
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
7703b705cfSriastradh#define NO_DISCARD_MASK 0
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{
18803b705cfSriastradh	ScreenPtr screen = sna->scrn->pScreen;
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{
109742542f5fSchristos	if (FORCE_SMALL_MASK)
109842542f5fSchristos		return FORCE_SMALL_MASK > 0;
109942542f5fSchristos
110042542f5fSchristos	if (depth * width * height < 8 * 4096)
110142542f5fSchristos		return true;
110242542f5fSchristos
110342542f5fSchristos	return too_large(sna, width, height);
110442542f5fSchristos}
110542542f5fSchristos
110603b705cfSriastradhflatten static bool
110703b705cfSriastradhglyphs_via_mask(struct sna *sna,
110803b705cfSriastradh		CARD8 op,
110903b705cfSriastradh		PicturePtr src,
111003b705cfSriastradh		PicturePtr dst,
111103b705cfSriastradh		PictFormatPtr format,
111203b705cfSriastradh		INT16 src_x, INT16 src_y,
111303b705cfSriastradh		int nlist, GlyphListPtr list, GlyphPtr *glyphs)
111403b705cfSriastradh{
111503b705cfSriastradh	ScreenPtr screen = dst->pDrawable->pScreen;
111603b705cfSriastradh	CARD32 component_alpha;
111703b705cfSriastradh	PixmapPtr pixmap;
111842542f5fSchristos	PicturePtr mask;
111903b705cfSriastradh	int16_t x, y, width, height;
112003b705cfSriastradh	int error;
112103b705cfSriastradh	bool ret = false;
112203b705cfSriastradh	BoxRec box;
112303b705cfSriastradh
112403b705cfSriastradh	if (NO_GLYPHS_VIA_MASK)
112503b705cfSriastradh		return false;
112603b705cfSriastradh
112703b705cfSriastradh	DBG(("%s(op=%d, src=(%d, %d), nlist=%d,  dst=(%d, %d)+(%d, %d))\n",
112803b705cfSriastradh	     __FUNCTION__, op, src_x, src_y, nlist,
112903b705cfSriastradh	     list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y));
113003b705cfSriastradh
113103b705cfSriastradh	glyph_extents(nlist, list, glyphs, &box);
113203b705cfSriastradh	if (box.x2 <= box.x1 || box.y2 <= box.y1)
113303b705cfSriastradh		return true;
113403b705cfSriastradh
113542542f5fSchristos	DBG(("%s: nlist=%d, count=%d, bounds=((%d, %d), (%d, %d))\n", __FUNCTION__,
113642542f5fSchristos	     nlist, glyph_count(nlist, list), box.x1, box.y1, box.x2, box.y2));
113703b705cfSriastradh
113803b705cfSriastradh	if (!sna_compute_composite_extents(&box,
113903b705cfSriastradh					   src, NULL, dst,
114003b705cfSriastradh					   src_x, src_y,
114103b705cfSriastradh					   0, 0,
114203b705cfSriastradh					   box.x1, box.y1,
114303b705cfSriastradh					   box.x2 - box.x1,
114403b705cfSriastradh					   box.y2 - box.y1))
114503b705cfSriastradh		return true;
114603b705cfSriastradh
114703b705cfSriastradh	DBG(("%s: extents=((%d, %d), (%d, %d))\n", __FUNCTION__,
114803b705cfSriastradh	     box.x1, box.y1, box.x2, box.y2));
114903b705cfSriastradh
115003b705cfSriastradh	width  = box.x2 - box.x1;
115103b705cfSriastradh	height = box.y2 - box.y1;
115203b705cfSriastradh	box.x1 -= dst->pDrawable->x;
115303b705cfSriastradh	box.y1 -= dst->pDrawable->y;
115403b705cfSriastradh	x = -box.x1;
115503b705cfSriastradh	y = -box.y1;
115603b705cfSriastradh	src_x += box.x1 - list->xOff;
115703b705cfSriastradh	src_y += box.y1 - list->yOff;
115803b705cfSriastradh
115903b705cfSriastradh	if (format->depth < 8) {
116003b705cfSriastradh		format = PictureMatchFormat(screen, 8, PICT_a8);
116103b705cfSriastradh		if (!format)
116203b705cfSriastradh			return false;
116303b705cfSriastradh	}
116403b705cfSriastradh
116503b705cfSriastradh	component_alpha = NeedsComponent(format->format);
116642542f5fSchristos	if (use_small_mask(sna, width, height, format->depth)) {
116703b705cfSriastradh		pixman_image_t *mask_image;
116803b705cfSriastradh
116942542f5fSchristosuse_small_mask:
117003b705cfSriastradh		DBG(("%s: small mask [format=%lx, depth=%d, size=%d], rendering glyphs to upload buffer\n",
117103b705cfSriastradh		     __FUNCTION__, (unsigned long)format->format,
117203b705cfSriastradh		     format->depth, (uint32_t)width*height*format->depth));
117303b705cfSriastradh
117403b705cfSriastradh		pixmap = sna_pixmap_create_upload(screen,
117503b705cfSriastradh						  width, height,
117603b705cfSriastradh						  format->depth,
117703b705cfSriastradh						  KGEM_BUFFER_WRITE);
117803b705cfSriastradh		if (!pixmap)
117903b705cfSriastradh			return false;
118003b705cfSriastradh
118103b705cfSriastradh		mask_image =
118203b705cfSriastradh			pixman_image_create_bits(format->depth << 24 | format->format,
118303b705cfSriastradh						 width, height,
118403b705cfSriastradh						 pixmap->devPrivate.ptr,
118503b705cfSriastradh						 pixmap->devKind);
118603b705cfSriastradh		if (mask_image == NULL)
118703b705cfSriastradh			goto err_pixmap;
118803b705cfSriastradh
118942542f5fSchristos		if (sigtrap_get()) {
119042542f5fSchristos			pixman_image_unref(mask_image);
119142542f5fSchristos			goto err_pixmap;
119242542f5fSchristos		}
119342542f5fSchristos
119403b705cfSriastradh		memset(pixmap->devPrivate.ptr, 0, pixmap->devKind*height);
119503b705cfSriastradh#if HAS_PIXMAN_GLYPHS
119642542f5fSchristos		if (__global_glyph_cache) {
119703b705cfSriastradh			pixman_glyph_t stack_glyphs[N_STACK_GLYPHS];
119803b705cfSriastradh			pixman_glyph_t *pglyphs = stack_glyphs;
119903b705cfSriastradh			int count, n;
120003b705cfSriastradh
120103b705cfSriastradh			count = 0;
120203b705cfSriastradh			for (n = 0; n < nlist; ++n)
120303b705cfSriastradh				count += list[n].len;
120403b705cfSriastradh			if (count > N_STACK_GLYPHS) {
120503b705cfSriastradh				pglyphs = malloc (count * sizeof(pixman_glyph_t));
120603b705cfSriastradh				if (pglyphs == NULL)
120703b705cfSriastradh					goto err_pixmap;
120803b705cfSriastradh			}
120903b705cfSriastradh
121042542f5fSchristos			pixman_glyph_cache_freeze(__global_glyph_cache);
121103b705cfSriastradh			count = 0;
121203b705cfSriastradh			do {
121303b705cfSriastradh				n = list->len;
121403b705cfSriastradh				x += list->xOff;
121503b705cfSriastradh				y += list->yOff;
121603b705cfSriastradh				while (n--) {
121703b705cfSriastradh					GlyphPtr g = *glyphs++;
121803b705cfSriastradh					const void *ptr;
121903b705cfSriastradh
122003b705cfSriastradh					if (!glyph_valid(g))
122103b705cfSriastradh						goto next_pglyph;
122203b705cfSriastradh
122342542f5fSchristos					ptr = pixman_glyph_cache_lookup(__global_glyph_cache, g, NULL);
122403b705cfSriastradh					if (ptr == NULL) {
122503b705cfSriastradh						pixman_image_t *glyph_image;
122603b705cfSriastradh
122703b705cfSriastradh						glyph_image = sna_glyph_get_image(g, screen);
122803b705cfSriastradh						if (glyph_image == NULL)
122903b705cfSriastradh							goto next_pglyph;
123003b705cfSriastradh
123142542f5fSchristos						DBG(("%s: inserting glyph %p into pixman cache\n", __FUNCTION__, g));
123242542f5fSchristos						ptr = pixman_glyph_cache_insert(__global_glyph_cache, g, NULL,
123303b705cfSriastradh										g->info.x,
123403b705cfSriastradh										g->info.y,
123503b705cfSriastradh										glyph_image);
123603b705cfSriastradh						if (ptr == NULL)
123703b705cfSriastradh							goto next_pglyph;
123803b705cfSriastradh					}
123903b705cfSriastradh
124042542f5fSchristos					assert(sna_glyph_get_image(g, screen) != NULL);
124142542f5fSchristos
124203b705cfSriastradh					pglyphs[count].x = x;
124303b705cfSriastradh					pglyphs[count].y = y;
124403b705cfSriastradh					pglyphs[count].glyph = ptr;
124503b705cfSriastradh					count++;
124603b705cfSriastradh
124703b705cfSriastradhnext_pglyph:
124803b705cfSriastradh					x += g->info.xOff;
124903b705cfSriastradh					y += g->info.yOff;
125003b705cfSriastradh				}
125103b705cfSriastradh				list++;
125203b705cfSriastradh			} while (--nlist);
125303b705cfSriastradh
125403b705cfSriastradh			pixman_composite_glyphs_no_mask(PIXMAN_OP_ADD,
125503b705cfSriastradh							sna->render.white_image,
125603b705cfSriastradh							mask_image,
125703b705cfSriastradh							0, 0,
125803b705cfSriastradh							0, 0,
125942542f5fSchristos							__global_glyph_cache, count, pglyphs);
126042542f5fSchristos			pixman_glyph_cache_thaw(__global_glyph_cache);
126103b705cfSriastradh			if (pglyphs != stack_glyphs)
126203b705cfSriastradh				free(pglyphs);
126303b705cfSriastradh		} else
126403b705cfSriastradh#endif
126503b705cfSriastradh		do {
126603b705cfSriastradh			int n = list->len;
126703b705cfSriastradh			x += list->xOff;
126803b705cfSriastradh			y += list->yOff;
126903b705cfSriastradh			while (n--) {
127003b705cfSriastradh				GlyphPtr g = *glyphs++;
127103b705cfSriastradh				pixman_image_t *glyph_image;
127203b705cfSriastradh				int16_t xi, yi;
127303b705cfSriastradh
127403b705cfSriastradh				if (!glyph_valid(g))
127503b705cfSriastradh					goto next_image;
127603b705cfSriastradh
127703b705cfSriastradh				/* If the mask has been cropped, it is likely
127803b705cfSriastradh				 * that some of the glyphs fall outside.
127903b705cfSriastradh				 */
128003b705cfSriastradh				xi = x - g->info.x;
128103b705cfSriastradh				yi = y - g->info.y;
128203b705cfSriastradh				if (xi >= width || yi >= height)
128303b705cfSriastradh					goto next_image;
128403b705cfSriastradh				if (xi + g->info.width  <= 0 ||
128503b705cfSriastradh				    yi + g->info.height <= 0)
128603b705cfSriastradh					goto next_image;
128703b705cfSriastradh
128803b705cfSriastradh				glyph_image =
128903b705cfSriastradh					sna_glyph_get_image(g, dst->pDrawable->pScreen);
129003b705cfSriastradh				if (glyph_image == NULL)
129103b705cfSriastradh					goto next_image;
129203b705cfSriastradh
129303b705cfSriastradh				DBG(("%s: glyph to mask (%d, %d)x(%d, %d)\n",
129403b705cfSriastradh				     __FUNCTION__,
129503b705cfSriastradh				     xi, yi,
129603b705cfSriastradh				     g->info.width,
129703b705cfSriastradh				     g->info.height));
129803b705cfSriastradh
129903b705cfSriastradh				if (list->format == format) {
130003b705cfSriastradh					assert(pixman_image_get_format(glyph_image) == pixman_image_get_format(mask_image));
130103b705cfSriastradh					pixman_image_composite(PictOpAdd,
130203b705cfSriastradh							       glyph_image,
130303b705cfSriastradh							       NULL,
130403b705cfSriastradh							       mask_image,
130503b705cfSriastradh							       0, 0,
130603b705cfSriastradh							       0, 0,
130703b705cfSriastradh							       xi, yi,
130803b705cfSriastradh							       g->info.width,
130903b705cfSriastradh							       g->info.height);
131003b705cfSriastradh				} else {
131103b705cfSriastradh					pixman_image_composite(PictOpAdd,
131203b705cfSriastradh							       sna->render.white_image,
131303b705cfSriastradh							       glyph_image,
131403b705cfSriastradh							       mask_image,
131503b705cfSriastradh							       0, 0,
131603b705cfSriastradh							       0, 0,
131703b705cfSriastradh							       xi, yi,
131803b705cfSriastradh							       g->info.width,
131903b705cfSriastradh							       g->info.height);
132003b705cfSriastradh				}
132103b705cfSriastradh
132203b705cfSriastradhnext_image:
132303b705cfSriastradh				x += g->info.xOff;
132403b705cfSriastradh				y += g->info.yOff;
132503b705cfSriastradh			}
132603b705cfSriastradh			list++;
132703b705cfSriastradh		} while (--nlist);
132803b705cfSriastradh		pixman_image_unref(mask_image);
132903b705cfSriastradh
133042542f5fSchristos		sigtrap_put();
133142542f5fSchristos
133203b705cfSriastradh		mask = CreatePicture(0, &pixmap->drawable,
133303b705cfSriastradh				     format, CPComponentAlpha,
133403b705cfSriastradh				     &component_alpha, serverClient, &error);
133503b705cfSriastradh		if (!mask)
133603b705cfSriastradh			goto err_pixmap;
133703b705cfSriastradh
133803b705cfSriastradh		ValidatePicture(mask);
133903b705cfSriastradh	} else {
134042542f5fSchristos		struct sna_composite_op tmp;
134142542f5fSchristos		PicturePtr glyph_atlas = NO_ATLAS;
134242542f5fSchristos
134303b705cfSriastradh		pixmap = screen->CreatePixmap(screen,
134403b705cfSriastradh					      width, height, format->depth,
134503b705cfSriastradh					      SNA_CREATE_SCRATCH);
134603b705cfSriastradh		if (!pixmap)
134742542f5fSchristos			goto use_small_mask;
134842542f5fSchristos
134942542f5fSchristos		assert(__sna_pixmap_get_bo(pixmap));
135003b705cfSriastradh
135103b705cfSriastradh		mask = CreatePicture(0, &pixmap->drawable,
135203b705cfSriastradh				     format, CPComponentAlpha,
135303b705cfSriastradh				     &component_alpha, serverClient, &error);
135403b705cfSriastradh		if (!mask)
135503b705cfSriastradh			goto err_pixmap;
135603b705cfSriastradh
135703b705cfSriastradh		ValidatePicture(mask);
135803b705cfSriastradh		if (!clear_pixmap(sna, pixmap))
135903b705cfSriastradh			goto err_mask;
136003b705cfSriastradh
136103b705cfSriastradh		do {
136203b705cfSriastradh			int n = list->len;
136303b705cfSriastradh			x += list->xOff;
136403b705cfSriastradh			y += list->yOff;
136503b705cfSriastradh			while (n--) {
136603b705cfSriastradh				GlyphPtr glyph = *glyphs++;
136742542f5fSchristos				struct sna_glyph *p = sna_glyph(glyph);
136803b705cfSriastradh				struct sna_composite_rectangles r;
136903b705cfSriastradh
137042542f5fSchristos				if (unlikely(p->atlas != glyph_atlas)) {
137142542f5fSchristos					bool ok;
137242542f5fSchristos
137303b705cfSriastradh					if (unlikely(!glyph_valid(glyph)))
137403b705cfSriastradh						goto next_glyph;
137503b705cfSriastradh
137642542f5fSchristos					if (glyph_atlas != NO_ATLAS) {
137703b705cfSriastradh						tmp.done(sna, &tmp);
137842542f5fSchristos						glyph_atlas = NO_ATLAS;
137903b705cfSriastradh					}
138042542f5fSchristos
138142542f5fSchristos					if (unlikely(p->atlas == NULL)) {
138242542f5fSchristos						if (!glyph_cache(screen, &sna->render, glyph))
138303b705cfSriastradh							goto next_glyph;
138403b705cfSriastradh					}
138503b705cfSriastradh
138603b705cfSriastradh					DBG(("%s: atlas format=%08x, mask format=%08x\n",
138703b705cfSriastradh					     __FUNCTION__,
138803b705cfSriastradh					     (int)p->atlas->format,
138903b705cfSriastradh					     (int)(format->depth << 24 | format->format)));
139042542f5fSchristos
139142542f5fSchristos					memset(&tmp, 0, sizeof(tmp));
139203b705cfSriastradh					if (p->atlas->format == (format->depth << 24 | format->format)) {
139303b705cfSriastradh						ok = sna->render.composite(sna, PictOpAdd,
139403b705cfSriastradh									   p->atlas, NULL, mask,
139503b705cfSriastradh									   0, 0, 0, 0, 0, 0,
139603b705cfSriastradh									   0, 0,
139742542f5fSchristos									   COMPOSITE_PARTIAL, &tmp);
139803b705cfSriastradh					} else {
139903b705cfSriastradh						ok = sna->render.composite(sna, PictOpAdd,
140003b705cfSriastradh									   sna->render.white_picture, p->atlas, mask,
140103b705cfSriastradh									   0, 0, 0, 0, 0, 0,
140203b705cfSriastradh									   0, 0,
140342542f5fSchristos									   COMPOSITE_PARTIAL, &tmp);
140403b705cfSriastradh					}
140503b705cfSriastradh					if (!ok) {
140603b705cfSriastradh						DBG(("%s: fallback -- can not handle PictOpAdd of glyph onto mask!\n",
140703b705cfSriastradh						     __FUNCTION__));
140803b705cfSriastradh						goto err_mask;
140903b705cfSriastradh					}
141003b705cfSriastradh
141103b705cfSriastradh					glyph_atlas = p->atlas;
141203b705cfSriastradh				}
141303b705cfSriastradh
141403b705cfSriastradh				DBG(("%s: blt glyph origin (%d, %d), offset (%d, %d), src (%d, %d), size (%d, %d)\n",
141503b705cfSriastradh				     __FUNCTION__,
141603b705cfSriastradh				     x, y,
141703b705cfSriastradh				     glyph->info.x, glyph->info.y,
141803b705cfSriastradh				     p->coordinate.x, p->coordinate.y,
141903b705cfSriastradh				     glyph->info.width, glyph->info.height));
142003b705cfSriastradh
142103b705cfSriastradh				r.mask = r.src = p->coordinate;
142203b705cfSriastradh				r.dst.x = x - glyph->info.x;
142303b705cfSriastradh				r.dst.y = y - glyph->info.y;
142403b705cfSriastradh				glyph_copy_size(&r, glyph);
142503b705cfSriastradh				tmp.blt(sna, &tmp, &r);
142603b705cfSriastradh
142703b705cfSriastradhnext_glyph:
142803b705cfSriastradh				x += glyph->info.xOff;
142903b705cfSriastradh				y += glyph->info.yOff;
143003b705cfSriastradh			}
143103b705cfSriastradh			list++;
143203b705cfSriastradh		} while (--nlist);
143342542f5fSchristos		if (glyph_atlas != NO_ATLAS)
143403b705cfSriastradh			tmp.done(sna, &tmp);
143503b705cfSriastradh	}
143603b705cfSriastradh
143703b705cfSriastradh	sna_composite(op,
143803b705cfSriastradh		      src, mask, dst,
143903b705cfSriastradh		      src_x, src_y,
144003b705cfSriastradh		      0, 0,
144103b705cfSriastradh		      box.x1, box.y1,
144203b705cfSriastradh		      width, height);
144303b705cfSriastradh	ret = true;
144403b705cfSriastradherr_mask:
144503b705cfSriastradh	FreePicture(mask, 0);
144603b705cfSriastradherr_pixmap:
144703b705cfSriastradh	sna_pixmap_destroy(pixmap);
144803b705cfSriastradh	return ret;
144903b705cfSriastradh}
145003b705cfSriastradh
145103b705cfSriastradhstatic PictFormatPtr
145203b705cfSriastradhglyphs_format(int nlist, GlyphListPtr list, GlyphPtr * glyphs)
145303b705cfSriastradh{
145403b705cfSriastradh	PictFormatPtr format = list[0].format;
145503b705cfSriastradh	int16_t x1, x2, y1, y2;
145603b705cfSriastradh	int16_t x, y;
145703b705cfSriastradh	BoxRec stack_extents[64], *list_extents = stack_extents;
145803b705cfSriastradh	int i, j;
145903b705cfSriastradh
146003b705cfSriastradh	if (nlist > ARRAY_SIZE(stack_extents)) {
146103b705cfSriastradh		list_extents = malloc(sizeof(BoxRec) * nlist);
146203b705cfSriastradh		if (list_extents == NULL)
146303b705cfSriastradh			return NULL;
146403b705cfSriastradh	}
146503b705cfSriastradh
146642542f5fSchristos	x = y = 0; i = 0;
146742542f5fSchristos	while (nlist--) {
146803b705cfSriastradh		BoxRec extents;
146903b705cfSriastradh		bool first = true;
147003b705cfSriastradh		int n = list->len;
147103b705cfSriastradh
147203b705cfSriastradh		/* Check the intersection of each glyph within the list and
147303b705cfSriastradh		 * then each list against the previous lists.
147403b705cfSriastradh		 *
147503b705cfSriastradh		 * If we overlap then we cannot substitute a mask as the
147603b705cfSriastradh		 * rendering will be altered.
147703b705cfSriastradh		 */
147803b705cfSriastradh		if (format->format != list->format->format) {
147942542f5fSchristos			DBG(("%s: switching formats from %x to %x\n",
148042542f5fSchristos			     __FUNCTION__,
148142542f5fSchristos			     (unsigned)format->format,
148242542f5fSchristos			     (unsigned)list->format->format));
148303b705cfSriastradh			format = NULL;
148403b705cfSriastradh			goto out;
148503b705cfSriastradh		}
148603b705cfSriastradh
148703b705cfSriastradh		x += list->xOff;
148803b705cfSriastradh		y += list->yOff;
148903b705cfSriastradh		list++;
149003b705cfSriastradh		while (n--) {
149103b705cfSriastradh			GlyphPtr glyph = *glyphs++;
149203b705cfSriastradh
149303b705cfSriastradh			if (!glyph_valid(glyph))
149403b705cfSriastradh				goto skip_glyph;
149503b705cfSriastradh
149603b705cfSriastradh			x1 = x - glyph->info.x;
149703b705cfSriastradh			y1 = y - glyph->info.y;
149803b705cfSriastradh			x2 = x1 + glyph->info.width;
149903b705cfSriastradh			y2 = y1 + glyph->info.height;
150003b705cfSriastradh
150103b705cfSriastradh			if (first) {
150203b705cfSriastradh				extents.x1 = x1;
150303b705cfSriastradh				extents.y1 = y1;
150403b705cfSriastradh				extents.x2 = x2;
150503b705cfSriastradh				extents.y2 = y2;
150603b705cfSriastradh				first = false;
150703b705cfSriastradh			} else {
150803b705cfSriastradh				/* Potential overlap?
150903b705cfSriastradh				 * We cheat and ignore the boundary pixels, as
151003b705cfSriastradh				 * the likelihood of an actual overlap of
151103b705cfSriastradh				 * inkedk pixels being noticeable in the
151203b705cfSriastradh				 * boundary is small, yet glyphs frequently
151303b705cfSriastradh				 * overlap on the boundaries.
151403b705cfSriastradh				 */
151542542f5fSchristos				if (x1 < extents.x2-GLYPH_TOLERANCE &&
151642542f5fSchristos				    x2 > extents.x1+GLYPH_TOLERANCE &&
151742542f5fSchristos				    y1 < extents.y2-GLYPH_TOLERANCE &&
151842542f5fSchristos				    y2 > extents.y1+GLYPH_TOLERANCE) {
151942542f5fSchristos					DBG(("%s: overlapping glyph inside line, current bbox (%d, %d), (%d, %d), glyph (%d, %d), (%d, %d)\n",
152042542f5fSchristos					     __FUNCTION__,
152142542f5fSchristos					     extents.x1, extents.y1, extents.x2, extents.y2,
152242542f5fSchristos					     x1, y1, x2, y2));
152303b705cfSriastradh					format = NULL;
152403b705cfSriastradh					goto out;
152503b705cfSriastradh				}
152603b705cfSriastradh
152703b705cfSriastradh				if (x1 < extents.x1)
152803b705cfSriastradh					extents.x1 = x1;
152903b705cfSriastradh				if (x2 > extents.x2)
153003b705cfSriastradh					extents.x2 = x2;
153103b705cfSriastradh				if (y1 < extents.y1)
153203b705cfSriastradh					extents.y1 = y1;
153303b705cfSriastradh				if (y2 > extents.y2)
153403b705cfSriastradh					extents.y2 = y2;
153503b705cfSriastradh			}
153603b705cfSriastradhskip_glyph:
153703b705cfSriastradh			x += glyph->info.xOff;
153803b705cfSriastradh			y += glyph->info.yOff;
153903b705cfSriastradh		}
154003b705cfSriastradh
154103b705cfSriastradh		/* Incrementally building a region is expensive. We expect
154203b705cfSriastradh		 * the number of lists to be small, so just keep a list
154303b705cfSriastradh		 * of the previous boxes and walk those.
154403b705cfSriastradh		 */
154542542f5fSchristos		if (!first) {
154642542f5fSchristos			for (j = 0; j < i; j++) {
154742542f5fSchristos				if (extents.x1 < list_extents[j].x2-GLYPH_TOLERANCE &&
154842542f5fSchristos				    extents.x2 > list_extents[j].x1+GLYPH_TOLERANCE &&
154942542f5fSchristos				    extents.y1 < list_extents[j].y2-GLYPH_TOLERANCE &&
155042542f5fSchristos				    extents.y2 > list_extents[j].y1+GLYPH_TOLERANCE) {
155142542f5fSchristos					DBG(("%s: overlapping lines, current bbox (%d, %d), (%d, %d), previous line (%d, %d), (%d, %d)\n",
155242542f5fSchristos					     __FUNCTION__,
155342542f5fSchristos					     extents.x1, extents.y1, extents.x2, extents.y2,
155442542f5fSchristos					     list_extents[j].x1, list_extents[j].y1,
155542542f5fSchristos					     list_extents[j].x2, list_extents[j].y2));
155642542f5fSchristos					format = NULL;
155742542f5fSchristos					goto out;
155842542f5fSchristos				}
155903b705cfSriastradh			}
156042542f5fSchristos			list_extents[i++] = extents;
156103b705cfSriastradh		}
156203b705cfSriastradh	}
156303b705cfSriastradh
156403b705cfSriastradhout:
156503b705cfSriastradh	if (list_extents != stack_extents)
156603b705cfSriastradh		free(list_extents);
156703b705cfSriastradh	return format;
156803b705cfSriastradh}
156903b705cfSriastradh
157003b705cfSriastradhstatic bool can_discard_mask(uint8_t op, PicturePtr src, PictFormatPtr mask,
157103b705cfSriastradh			     int nlist, GlyphListPtr list, GlyphPtr *glyphs)
157203b705cfSriastradh{
157303b705cfSriastradh	PictFormatPtr g;
157403b705cfSriastradh	uint32_t color;
157503b705cfSriastradh
157603b705cfSriastradh	if (NO_DISCARD_MASK)
157703b705cfSriastradh		return false;
157803b705cfSriastradh
157942542f5fSchristos	DBG(("%s: nlist=%d, mask=%08x, depth %d, op=%d (bounded? %d)\n",
158042542f5fSchristos	     __FUNCTION__, nlist,
158142542f5fSchristos	     mask ? (unsigned)mask->format : 0, mask ? mask->depth : 0,
158242542f5fSchristos	     op, op_is_bounded(op)));
158342542f5fSchristos
158403b705cfSriastradh	if (nlist == 1 && list->len == 1)
158503b705cfSriastradh		return true;
158603b705cfSriastradh
158703b705cfSriastradh	if (!op_is_bounded(op))
158803b705cfSriastradh		return false;
158903b705cfSriastradh
159003b705cfSriastradh	/* No glyphs overlap and we are not performing a mask conversion. */
159103b705cfSriastradh	g = glyphs_format(nlist, list, glyphs);
159203b705cfSriastradh	if (mask == g)
159303b705cfSriastradh		return true;
159403b705cfSriastradh
159542542f5fSchristos	DBG(("%s: preferred mask format %08x, depth %d\n",
159642542f5fSchristos	     __FUNCTION__, g ? (unsigned)g->format : 0,  g ? g->depth : 0));
159742542f5fSchristos
159803b705cfSriastradh	/* Otherwise if the glyphs are all bitmaps and we have an
159903b705cfSriastradh	 * opaque source we can also render directly to the dst.
160003b705cfSriastradh	 */
160103b705cfSriastradh	if (g == NULL) {
160203b705cfSriastradh		while (nlist--) {
160303b705cfSriastradh			if (list->format->depth != 1)
160403b705cfSriastradh				return false;
160503b705cfSriastradh
160603b705cfSriastradh			list++;
160703b705cfSriastradh		}
160803b705cfSriastradh	} else {
160903b705cfSriastradh		if (PICT_FORMAT_A(mask->format) >= PICT_FORMAT_A(g->format))
161003b705cfSriastradh			return true;
161103b705cfSriastradh
161203b705cfSriastradh		if (g->depth != 1)
161303b705cfSriastradh			return false;
161403b705cfSriastradh	}
161503b705cfSriastradh
161603b705cfSriastradh	if (!sna_picture_is_solid(src, &color))
161703b705cfSriastradh		return false;
161803b705cfSriastradh
161903b705cfSriastradh	return color >> 24 == 0xff;
162003b705cfSriastradh}
162103b705cfSriastradh
162203b705cfSriastradhstatic void
162303b705cfSriastradhglyphs_fallback(CARD8 op,
162403b705cfSriastradh		PicturePtr src,
162503b705cfSriastradh		PicturePtr dst,
162603b705cfSriastradh		PictFormatPtr mask_format,
162703b705cfSriastradh		int src_x, int src_y,
162803b705cfSriastradh		int nlist, GlyphListPtr list, GlyphPtr *glyphs)
162903b705cfSriastradh{
163003b705cfSriastradh	struct sna *sna = to_sna_from_drawable(dst->pDrawable);
163103b705cfSriastradh	pixman_image_t *src_image, *dst_image;
163203b705cfSriastradh	int src_dx, src_dy;
163303b705cfSriastradh	ScreenPtr screen = dst->pDrawable->pScreen;
163403b705cfSriastradh	RegionRec region;
163503b705cfSriastradh	int x, y, n;
163603b705cfSriastradh
163703b705cfSriastradh	glyph_extents(nlist, list, glyphs, &region.extents);
163842542f5fSchristos	DBG(("%s: nlist=%d, count=%d, extents (%d, %d), (%d, %d)\n", __FUNCTION__,
163942542f5fSchristos	     nlist, glyph_count(nlist, list),
164042542f5fSchristos	     region.extents.x1, region.extents.y1,
164142542f5fSchristos	     region.extents.x2, region.extents.y2));
164242542f5fSchristos
164303b705cfSriastradh	if (region.extents.x2 <= region.extents.x1 ||
164403b705cfSriastradh	    region.extents.y2 <= region.extents.y1)
164503b705cfSriastradh		return;
164603b705cfSriastradh
164703b705cfSriastradh	region.data = NULL;
164803b705cfSriastradh	RegionTranslate(&region, dst->pDrawable->x, dst->pDrawable->y);
164942542f5fSchristos	RegionIntersect(&region, &region, dst->pCompositeClip);
165003b705cfSriastradh	DBG(("%s: clipped extents (%d, %d), (%d, %d)\n",
165103b705cfSriastradh	     __FUNCTION__,
165203b705cfSriastradh	     RegionExtents(&region)->x1, RegionExtents(&region)->y1,
165303b705cfSriastradh	     RegionExtents(&region)->x2, RegionExtents(&region)->y2));
165403b705cfSriastradh	if (RegionNil(&region))
165503b705cfSriastradh		return;
165603b705cfSriastradh
165703b705cfSriastradh	if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &region,
165803b705cfSriastradh					     MOVE_READ | MOVE_WRITE))
165903b705cfSriastradh		return;
166003b705cfSriastradh	if (dst->alphaMap &&
166103b705cfSriastradh	    !sna_drawable_move_to_cpu(dst->alphaMap->pDrawable,
166203b705cfSriastradh				      MOVE_READ | MOVE_WRITE))
166303b705cfSriastradh		return;
166403b705cfSriastradh
166503b705cfSriastradh	if (src->pDrawable) {
166603b705cfSriastradh		if (!sna_drawable_move_to_cpu(src->pDrawable,
166703b705cfSriastradh					      MOVE_READ))
166803b705cfSriastradh			return;
166903b705cfSriastradh
167003b705cfSriastradh		if (src->alphaMap &&
167103b705cfSriastradh		    !sna_drawable_move_to_cpu(src->alphaMap->pDrawable,
167203b705cfSriastradh					      MOVE_READ))
167303b705cfSriastradh			return;
167403b705cfSriastradh	}
167503b705cfSriastradh	RegionTranslate(&region, -dst->pDrawable->x, -dst->pDrawable->y);
167603b705cfSriastradh
167703b705cfSriastradh	if (mask_format &&
167803b705cfSriastradh	    can_discard_mask(op, src, mask_format, nlist, list, glyphs)) {
167903b705cfSriastradh		DBG(("%s: discarding mask\n", __FUNCTION__));
168003b705cfSriastradh		mask_format = NULL;
168103b705cfSriastradh	}
168203b705cfSriastradh
168303b705cfSriastradh#if HAS_PIXMAN_GLYPHS
168442542f5fSchristos	if (__global_glyph_cache) {
168503b705cfSriastradh		pixman_glyph_t stack_glyphs[N_STACK_GLYPHS];
168603b705cfSriastradh		pixman_glyph_t *pglyphs = stack_glyphs;
168703b705cfSriastradh		int dst_x = list->xOff, dst_y = list->yOff;
168803b705cfSriastradh		int dst_dx, dst_dy, count;
168903b705cfSriastradh
169042542f5fSchristos		pixman_glyph_cache_freeze(__global_glyph_cache);
169103b705cfSriastradh
169203b705cfSriastradh		count = 0;
169303b705cfSriastradh		for (n = 0; n < nlist; ++n)
169403b705cfSriastradh			count += list[n].len;
169503b705cfSriastradh		if (count > N_STACK_GLYPHS) {
169642542f5fSchristos			pglyphs = malloc(count * sizeof(pixman_glyph_t));
169703b705cfSriastradh			if (pglyphs == NULL)
169803b705cfSriastradh				goto out;
169903b705cfSriastradh		}
170003b705cfSriastradh
170103b705cfSriastradh		count = 0;
170203b705cfSriastradh		x = y = 0;
170303b705cfSriastradh		while (nlist--) {
170403b705cfSriastradh			n = list->len;
170503b705cfSriastradh			x += list->xOff;
170603b705cfSriastradh			y += list->yOff;
170703b705cfSriastradh			while (n--) {
170803b705cfSriastradh				GlyphPtr g = *glyphs++;
170903b705cfSriastradh				const void *ptr;
171003b705cfSriastradh
171103b705cfSriastradh				if (!glyph_valid(g))
171203b705cfSriastradh					goto next;
171303b705cfSriastradh
171442542f5fSchristos				ptr = pixman_glyph_cache_lookup(__global_glyph_cache, g, NULL);
171503b705cfSriastradh				if (ptr == NULL) {
171603b705cfSriastradh					pixman_image_t *glyph_image;
171703b705cfSriastradh
171803b705cfSriastradh					glyph_image = sna_glyph_get_image(g, screen);
171903b705cfSriastradh					if (glyph_image == NULL)
172003b705cfSriastradh						goto next;
172103b705cfSriastradh
172242542f5fSchristos					DBG(("%s: inserting glyph %p into pixman cache\n", __FUNCTION__, g));
172342542f5fSchristos					ptr = pixman_glyph_cache_insert(__global_glyph_cache, g, NULL,
172403b705cfSriastradh									g->info.x,
172503b705cfSriastradh									g->info.y,
172603b705cfSriastradh									glyph_image);
172703b705cfSriastradh					if (ptr == NULL)
172842542f5fSchristos						goto next;
172903b705cfSriastradh				}
173003b705cfSriastradh
173142542f5fSchristos				assert(sna_glyph_get_image(g, screen) != NULL);
173242542f5fSchristos
173303b705cfSriastradh				pglyphs[count].x = x;
173403b705cfSriastradh				pglyphs[count].y = y;
173503b705cfSriastradh				pglyphs[count].glyph = ptr;
173603b705cfSriastradh				count++;
173703b705cfSriastradh
173803b705cfSriastradhnext:
173903b705cfSriastradh				x += g->info.xOff;
174003b705cfSriastradh				y += g->info.yOff;
174103b705cfSriastradh			}
174203b705cfSriastradh			list++;
174303b705cfSriastradh		}
174403b705cfSriastradh
174542542f5fSchristos		if (count == 0)
174642542f5fSchristos			goto out;
174742542f5fSchristos
174803b705cfSriastradh		src_image = image_from_pict(src, FALSE, &src_dx, &src_dy);
174903b705cfSriastradh		if (src_image == NULL)
175003b705cfSriastradh			goto out;
175103b705cfSriastradh
175203b705cfSriastradh		dst_image = image_from_pict(dst, TRUE, &dst_dx, &dst_dy);
175303b705cfSriastradh		if (dst_image == NULL)
175403b705cfSriastradh			goto out_free_src;
175503b705cfSriastradh
175642542f5fSchristos		if (sigtrap_get() == 0) {
175742542f5fSchristos			if (mask_format) {
175842542f5fSchristos				pixman_composite_glyphs(op, src_image, dst_image,
175942542f5fSchristos							mask_format->format | (mask_format->depth << 24),
176042542f5fSchristos							src_x + src_dx + region.extents.x1 - dst_x,
176142542f5fSchristos							src_y + src_dy + region.extents.y1 - dst_y,
176242542f5fSchristos							region.extents.x1, region.extents.y1,
176342542f5fSchristos							region.extents.x1 + dst_dx, region.extents.y1 + dst_dy,
176442542f5fSchristos							region.extents.x2 - region.extents.x1,
176542542f5fSchristos							region.extents.y2 - region.extents.y1,
176642542f5fSchristos							__global_glyph_cache, count, pglyphs);
176742542f5fSchristos			} else {
176842542f5fSchristos				pixman_composite_glyphs_no_mask(op, src_image, dst_image,
176942542f5fSchristos								src_x + src_dx - dst_x, src_y + src_dy - dst_y,
177042542f5fSchristos								dst_dx, dst_dy,
177142542f5fSchristos								__global_glyph_cache, count, pglyphs);
177242542f5fSchristos			}
177342542f5fSchristos			sigtrap_put();
177403b705cfSriastradh		}
177503b705cfSriastradh
177603b705cfSriastradh		free_pixman_pict(dst, dst_image);
177703b705cfSriastradh
177803b705cfSriastradhout_free_src:
177903b705cfSriastradh		free_pixman_pict(src, src_image);
178003b705cfSriastradh
178103b705cfSriastradhout:
178242542f5fSchristos		pixman_glyph_cache_thaw(__global_glyph_cache);
178303b705cfSriastradh		if (pglyphs != stack_glyphs)
178403b705cfSriastradh			free(pglyphs);
178503b705cfSriastradh	} else
178603b705cfSriastradh#endif
178703b705cfSriastradh	{
178803b705cfSriastradh		pixman_image_t *mask_image;
178903b705cfSriastradh
179003b705cfSriastradh		dst_image = image_from_pict(dst, TRUE, &x, &y);
179103b705cfSriastradh		if (dst_image == NULL)
179203b705cfSriastradh			goto cleanup_region;
179303b705cfSriastradh		DBG(("%s: dst offset (%d, %d)\n", __FUNCTION__, x, y));
179403b705cfSriastradh		if (x | y) {
179503b705cfSriastradh			region.extents.x1 += x;
179603b705cfSriastradh			region.extents.x2 += x;
179703b705cfSriastradh			region.extents.y1 += y;
179803b705cfSriastradh			region.extents.y2 += y;
179903b705cfSriastradh		}
180003b705cfSriastradh
180103b705cfSriastradh		src_image = image_from_pict(src, FALSE, &src_dx, &src_dy);
180203b705cfSriastradh		if (src_image == NULL)
180303b705cfSriastradh			goto cleanup_dst;
180403b705cfSriastradh		DBG(("%s: src offset (%d, %d)\n", __FUNCTION__, src_dx, src_dy));
180503b705cfSriastradh		src_x += src_dx - list->xOff;
180603b705cfSriastradh		src_y += src_dy - list->yOff;
180703b705cfSriastradh
180803b705cfSriastradh		if (mask_format) {
180903b705cfSriastradh			DBG(("%s: create mask (%d, %d)x(%d,%d) + (%d,%d) + (%d,%d), depth=%d, format=%lx [%lx], ca? %d\n",
181003b705cfSriastradh			     __FUNCTION__,
181103b705cfSriastradh			     region.extents.x1, region.extents.y1,
181203b705cfSriastradh			     region.extents.x2 - region.extents.x1,
181303b705cfSriastradh			     region.extents.y2 - region.extents.y1,
181403b705cfSriastradh			     dst->pDrawable->x, dst->pDrawable->y,
181503b705cfSriastradh			     x, y,
181603b705cfSriastradh			     mask_format->depth,
181703b705cfSriastradh			     (long)mask_format->format,
181803b705cfSriastradh			     (long)(mask_format->depth << 24 | mask_format->format),
181903b705cfSriastradh			     NeedsComponent(mask_format->format)));
182003b705cfSriastradh			mask_image =
182103b705cfSriastradh				pixman_image_create_bits(mask_format->depth << 24 | mask_format->format,
182203b705cfSriastradh							 region.extents.x2 - region.extents.x1,
182303b705cfSriastradh							 region.extents.y2 - region.extents.y1,
182403b705cfSriastradh							 NULL, 0);
182503b705cfSriastradh			if (mask_image == NULL)
182603b705cfSriastradh				goto cleanup_src;
182703b705cfSriastradh			if (NeedsComponent(mask_format->format))
182803b705cfSriastradh				pixman_image_set_component_alpha(mask_image, TRUE);
182903b705cfSriastradh
183003b705cfSriastradh			x -= region.extents.x1;
183103b705cfSriastradh			y -= region.extents.y1;
183203b705cfSriastradh		} else {
183303b705cfSriastradh			mask_image = dst_image;
183403b705cfSriastradh			src_x -= x - dst->pDrawable->x;
183503b705cfSriastradh			src_y -= y - dst->pDrawable->y;
183603b705cfSriastradh		}
183703b705cfSriastradh
183842542f5fSchristos		if (sigtrap_get() == 0) {
183942542f5fSchristos			do {
184042542f5fSchristos				n = list->len;
184142542f5fSchristos				x += list->xOff;
184242542f5fSchristos				y += list->yOff;
184342542f5fSchristos				while (n--) {
184442542f5fSchristos					GlyphPtr g = *glyphs++;
184542542f5fSchristos					pixman_image_t *glyph_image;
184603b705cfSriastradh
184742542f5fSchristos					if (!glyph_valid(g))
184842542f5fSchristos						goto next_glyph;
184903b705cfSriastradh
185042542f5fSchristos					glyph_image = sna_glyph_get_image(g, screen);
185142542f5fSchristos					if (glyph_image == NULL)
185242542f5fSchristos						goto next_glyph;
185303b705cfSriastradh
185442542f5fSchristos					if (mask_format) {
185542542f5fSchristos						DBG(("%s: glyph to mask (%d, %d)x(%d, %d)\n",
185642542f5fSchristos						     __FUNCTION__,
185742542f5fSchristos						     x - g->info.x,
185842542f5fSchristos						     y - g->info.y,
185942542f5fSchristos						     g->info.width,
186042542f5fSchristos						     g->info.height));
186142542f5fSchristos
186242542f5fSchristos						if (list->format == mask_format) {
186342542f5fSchristos							assert(pixman_image_get_format(glyph_image) == pixman_image_get_format(mask_image));
186442542f5fSchristos							pixman_image_composite(PictOpAdd,
186542542f5fSchristos									       glyph_image,
186642542f5fSchristos									       NULL,
186742542f5fSchristos									       mask_image,
186842542f5fSchristos									       0, 0,
186942542f5fSchristos									       0, 0,
187042542f5fSchristos									       x - g->info.x,
187142542f5fSchristos									       y - g->info.y,
187242542f5fSchristos									       g->info.width,
187342542f5fSchristos									       g->info.height);
187442542f5fSchristos						} else {
187542542f5fSchristos							pixman_image_composite(PictOpAdd,
187642542f5fSchristos									       sna->render.white_image,
187742542f5fSchristos									       glyph_image,
187842542f5fSchristos									       mask_image,
187942542f5fSchristos									       0, 0,
188042542f5fSchristos									       0, 0,
188142542f5fSchristos									       x - g->info.x,
188242542f5fSchristos									       y - g->info.y,
188342542f5fSchristos									       g->info.width,
188442542f5fSchristos									       g->info.height);
188542542f5fSchristos						}
188603b705cfSriastradh					} else {
188742542f5fSchristos						int xi = x - g->info.x;
188842542f5fSchristos						int yi = y - g->info.y;
188942542f5fSchristos
189042542f5fSchristos						DBG(("%s: glyph to dst (%d, %d)x(%d, %d)/[(%d, %d)x(%d, %d)], src (%d, %d) [op=%d]\n",
189142542f5fSchristos						     __FUNCTION__,
189242542f5fSchristos						     xi, yi,
189342542f5fSchristos						     g->info.width, g->info.height,
189442542f5fSchristos						     dst->pDrawable->x,
189542542f5fSchristos						     dst->pDrawable->y,
189642542f5fSchristos						     dst->pDrawable->width,
189742542f5fSchristos						     dst->pDrawable->height,
189842542f5fSchristos						     src_x + xi,
189942542f5fSchristos						     src_y + yi,
190042542f5fSchristos						     op));
190142542f5fSchristos
190242542f5fSchristos						pixman_image_composite(op,
190342542f5fSchristos								       src_image,
190403b705cfSriastradh								       glyph_image,
190542542f5fSchristos								       dst_image,
190642542f5fSchristos								       src_x + xi,
190742542f5fSchristos								       src_y + yi,
190803b705cfSriastradh								       0, 0,
190942542f5fSchristos								       xi, yi,
191003b705cfSriastradh								       g->info.width,
191103b705cfSriastradh								       g->info.height);
191203b705cfSriastradh					}
191303b705cfSriastradhnext_glyph:
191442542f5fSchristos					x += g->info.xOff;
191542542f5fSchristos					y += g->info.yOff;
191642542f5fSchristos				}
191742542f5fSchristos				list++;
191842542f5fSchristos			} while (--nlist);
191942542f5fSchristos			sigtrap_put();
192042542f5fSchristos		}
192103b705cfSriastradh
192203b705cfSriastradh		if (mask_format) {
192303b705cfSriastradh			DBG(("%s: glyph mask composite src=(%d+%d,%d+%d) dst=(%d, %d)x(%d, %d)\n",
192403b705cfSriastradh			     __FUNCTION__,
192503b705cfSriastradh			     src_x, region.extents.x1, src_y, region.extents.y1,
192603b705cfSriastradh			     region.extents.x1, region.extents.y1,
192703b705cfSriastradh			     region.extents.x2 - region.extents.x1,
192803b705cfSriastradh			     region.extents.y2 - region.extents.y1));
192903b705cfSriastradh			pixman_image_composite(op, src_image, mask_image, dst_image,
193003b705cfSriastradh					       src_x, src_y,
193103b705cfSriastradh					       0, 0,
193203b705cfSriastradh					       region.extents.x1, region.extents.y1,
193303b705cfSriastradh					       region.extents.x2 - region.extents.x1,
193403b705cfSriastradh					       region.extents.y2 - region.extents.y1);
193503b705cfSriastradh			pixman_image_unref(mask_image);
193603b705cfSriastradh		}
193703b705cfSriastradh
193803b705cfSriastradhcleanup_src:
193903b705cfSriastradh		free_pixman_pict(src, src_image);
194003b705cfSriastradhcleanup_dst:
194103b705cfSriastradh		free_pixman_pict(dst, dst_image);
194203b705cfSriastradh	}
194303b705cfSriastradh
194403b705cfSriastradhcleanup_region:
194503b705cfSriastradh	RegionUninit(&region);
194603b705cfSriastradh}
194703b705cfSriastradh
194803b705cfSriastradhvoid
194903b705cfSriastradhsna_glyphs(CARD8 op,
195003b705cfSriastradh	   PicturePtr src,
195103b705cfSriastradh	   PicturePtr dst,
195203b705cfSriastradh	   PictFormatPtr mask,
195303b705cfSriastradh	   INT16 src_x, INT16 src_y,
195403b705cfSriastradh	   int nlist, GlyphListPtr list, GlyphPtr *glyphs)
195503b705cfSriastradh{
195603b705cfSriastradh	PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable);
195703b705cfSriastradh	struct sna *sna = to_sna_from_pixmap(pixmap);
195803b705cfSriastradh	struct sna_pixmap *priv;
195903b705cfSriastradh
196003b705cfSriastradh	DBG(("%s(op=%d, nlist=%d, src=(%d, %d))\n",
196103b705cfSriastradh	     __FUNCTION__, op, nlist, src_x, src_y));
196203b705cfSriastradh
196342542f5fSchristos	if (RegionNil(dst->pCompositeClip))
196403b705cfSriastradh		return;
196503b705cfSriastradh
196603b705cfSriastradh	if (FALLBACK)
196703b705cfSriastradh		goto fallback;
196803b705cfSriastradh
196903b705cfSriastradh	if (!can_render(sna)) {
197003b705cfSriastradh		DBG(("%s: wedged\n", __FUNCTION__));
197103b705cfSriastradh		goto fallback;
197203b705cfSriastradh	}
197303b705cfSriastradh
197413496ba1Ssnj	if (!can_render_to_picture(dst)) {
197513496ba1Ssnj		DBG(("%s: fallback -- dst incompatible picture\n", __FUNCTION__));
197603b705cfSriastradh		goto fallback;
197703b705cfSriastradh	}
197803b705cfSriastradh
197903b705cfSriastradh	priv = sna_pixmap(pixmap);
198003b705cfSriastradh	if (priv == NULL) {
198103b705cfSriastradh		DBG(("%s: fallback -- destination unattached\n", __FUNCTION__));
198203b705cfSriastradh		goto fallback;
198303b705cfSriastradh	}
198403b705cfSriastradh
198542542f5fSchristos	if (!is_gpu_dst(priv) && !picture_is_gpu(sna, src, 0)) {
198603b705cfSriastradh		DBG(("%s: fallback -- too small (%dx%d)\n",
198703b705cfSriastradh		     __FUNCTION__, dst->pDrawable->width, dst->pDrawable->height));
198803b705cfSriastradh		goto fallback;
198903b705cfSriastradh	}
199003b705cfSriastradh
199103b705cfSriastradh	/* Try to discard the mask for non-overlapping glyphs */
199242542f5fSchristos	if (FORCE_GLYPHS_TO_DST ||
199342542f5fSchristos	    mask == NULL ||
199403b705cfSriastradh	    (dst->pCompositeClip->data == NULL &&
199503b705cfSriastradh	     can_discard_mask(op, src, mask, nlist, list, glyphs))) {
199603b705cfSriastradh		DBG(("%s: discarding mask\n", __FUNCTION__));
199703b705cfSriastradh		if (can_use_glyph0()) {
199803b705cfSriastradh			if (glyphs0_to_dst(sna, op,
199903b705cfSriastradh					   src, dst,
200003b705cfSriastradh					   src_x, src_y,
200103b705cfSriastradh					   nlist, list, glyphs))
200203b705cfSriastradh				return;
200303b705cfSriastradh		} else {
200403b705cfSriastradh			if (glyphs_to_dst(sna, op,
200503b705cfSriastradh					  src, dst,
200603b705cfSriastradh					  src_x, src_y,
200703b705cfSriastradh					  nlist, list, glyphs))
200803b705cfSriastradh				return;
200903b705cfSriastradh		}
201003b705cfSriastradh	}
201103b705cfSriastradh
201203b705cfSriastradh	/* Otherwise see if we can substitute a mask */
201303b705cfSriastradh	if (!mask) {
201403b705cfSriastradh		mask = glyphs_format(nlist, list, glyphs);
201503b705cfSriastradh		DBG(("%s: substituting mask? %d\n", __FUNCTION__, mask!=NULL));
201603b705cfSriastradh	}
201703b705cfSriastradh	if (mask) {
201803b705cfSriastradh		if (glyphs_via_mask(sna, op,
201903b705cfSriastradh				    src, dst, mask,
202003b705cfSriastradh				    src_x, src_y,
202103b705cfSriastradh				    nlist, list, glyphs))
202203b705cfSriastradh			return;
202303b705cfSriastradh	} else {
202403b705cfSriastradh		if (glyphs_slow(sna, op,
202503b705cfSriastradh				src, dst,
202603b705cfSriastradh				src_x, src_y,
202703b705cfSriastradh				nlist, list, glyphs))
202803b705cfSriastradh			return;
202903b705cfSriastradh	}
203003b705cfSriastradh
203103b705cfSriastradhfallback:
203203b705cfSriastradh	glyphs_fallback(op, src, dst, mask, src_x, src_y, nlist, list, glyphs);
203303b705cfSriastradh}
203403b705cfSriastradh
203503b705cfSriastradhstatic bool
203603b705cfSriastradhglyphs_via_image(struct sna *sna,
203703b705cfSriastradh		 CARD8 op,
203803b705cfSriastradh		 PicturePtr src,
203903b705cfSriastradh		 PicturePtr dst,
204003b705cfSriastradh		 PictFormatPtr format,
204103b705cfSriastradh		 INT16 src_x, INT16 src_y,
204203b705cfSriastradh		 int nlist, GlyphListPtr list, GlyphPtr *glyphs)
204303b705cfSriastradh{
204403b705cfSriastradh	ScreenPtr screen = dst->pDrawable->pScreen;
204503b705cfSriastradh	CARD32 component_alpha;
204603b705cfSriastradh	PixmapPtr pixmap;
204703b705cfSriastradh	PicturePtr mask;
204803b705cfSriastradh	int16_t x, y, width, height;
204903b705cfSriastradh	pixman_image_t *mask_image;
205003b705cfSriastradh	int error;
205103b705cfSriastradh	bool ret = false;
205203b705cfSriastradh	BoxRec box;
205303b705cfSriastradh
205403b705cfSriastradh	if (NO_GLYPHS_VIA_MASK)
205503b705cfSriastradh		return false;
205603b705cfSriastradh
205703b705cfSriastradh	DBG(("%s(op=%d, src=(%d, %d), nlist=%d,  dst=(%d, %d)+(%d, %d))\n",
205803b705cfSriastradh	     __FUNCTION__, op, src_x, src_y, nlist,
205903b705cfSriastradh	     list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y));
206003b705cfSriastradh
206103b705cfSriastradh	glyph_extents(nlist, list, glyphs, &box);
206203b705cfSriastradh	if (box.x2 <= box.x1 || box.y2 <= box.y1)
206303b705cfSriastradh		return true;
206403b705cfSriastradh
206542542f5fSchristos	DBG(("%s: nlist=%d, count=%d, bounds=((%d, %d), (%d, %d))\n", __FUNCTION__,
206642542f5fSchristos	     nlist, glyph_count(nlist, list), box.x1, box.y1, box.x2, box.y2));
206703b705cfSriastradh
206803b705cfSriastradh	if (!sna_compute_composite_extents(&box,
206903b705cfSriastradh					   src, NULL, dst,
207003b705cfSriastradh					   src_x, src_y,
207103b705cfSriastradh					   0, 0,
207203b705cfSriastradh					   box.x1, box.y1,
207303b705cfSriastradh					   box.x2 - box.x1,
207403b705cfSriastradh					   box.y2 - box.y1))
207503b705cfSriastradh		return true;
207603b705cfSriastradh
207703b705cfSriastradh	DBG(("%s: extents=((%d, %d), (%d, %d))\n", __FUNCTION__,
207803b705cfSriastradh	     box.x1, box.y1, box.x2, box.y2));
207903b705cfSriastradh
208003b705cfSriastradh	width  = box.x2 - box.x1;
208103b705cfSriastradh	height = box.y2 - box.y1;
208203b705cfSriastradh	box.x1 -= dst->pDrawable->x;
208303b705cfSriastradh	box.y1 -= dst->pDrawable->y;
208403b705cfSriastradh	x = -box.x1;
208503b705cfSriastradh	y = -box.y1;
208603b705cfSriastradh	src_x += box.x1 - list->xOff;
208703b705cfSriastradh	src_y += box.y1 - list->yOff;
208803b705cfSriastradh
208903b705cfSriastradh	if (format->depth < 8) {
209003b705cfSriastradh		format = PictureMatchFormat(screen, 8, PICT_a8);
209103b705cfSriastradh		if (!format)
209203b705cfSriastradh			return false;
209303b705cfSriastradh	}
209403b705cfSriastradh
209503b705cfSriastradh	DBG(("%s: small mask [format=%lx, depth=%d, size=%d], rendering glyphs to upload buffer\n",
209603b705cfSriastradh	     __FUNCTION__, (unsigned long)format->format,
209703b705cfSriastradh	     format->depth, (uint32_t)width*height*format->depth));
209803b705cfSriastradh
209903b705cfSriastradh	pixmap = sna_pixmap_create_upload(screen,
210003b705cfSriastradh					  width, height,
210103b705cfSriastradh					  format->depth,
210203b705cfSriastradh					  KGEM_BUFFER_WRITE);
210303b705cfSriastradh	if (!pixmap)
210403b705cfSriastradh		return false;
210503b705cfSriastradh
210603b705cfSriastradh	mask_image =
210703b705cfSriastradh		pixman_image_create_bits(format->depth << 24 | format->format,
210803b705cfSriastradh					 width, height,
210903b705cfSriastradh					 pixmap->devPrivate.ptr,
211003b705cfSriastradh					 pixmap->devKind);
211103b705cfSriastradh	if (mask_image == NULL)
211203b705cfSriastradh		goto err_pixmap;
211303b705cfSriastradh
211442542f5fSchristos	if (sigtrap_get()) {
211542542f5fSchristos		pixman_image_unref(mask_image);
211642542f5fSchristos		goto err_pixmap;
211742542f5fSchristos	}
211842542f5fSchristos
211903b705cfSriastradh	memset(pixmap->devPrivate.ptr, 0, pixmap->devKind*height);
212003b705cfSriastradh#if HAS_PIXMAN_GLYPHS
212142542f5fSchristos	if (__global_glyph_cache) {
212203b705cfSriastradh		pixman_glyph_t stack_glyphs[N_STACK_GLYPHS];
212303b705cfSriastradh		pixman_glyph_t *pglyphs = stack_glyphs;
212403b705cfSriastradh		int count, n;
212503b705cfSriastradh
212603b705cfSriastradh		count = 0;
212703b705cfSriastradh		for (n = 0; n < nlist; ++n)
212803b705cfSriastradh			count += list[n].len;
212903b705cfSriastradh		if (count > N_STACK_GLYPHS) {
213042542f5fSchristos			pglyphs = malloc(count * sizeof(pixman_glyph_t));
213103b705cfSriastradh			if (pglyphs == NULL)
213203b705cfSriastradh				goto err_pixmap;
213303b705cfSriastradh		}
213403b705cfSriastradh
213542542f5fSchristos		pixman_glyph_cache_freeze(__global_glyph_cache);
213603b705cfSriastradh		count = 0;
213703b705cfSriastradh		do {
213803b705cfSriastradh			n = list->len;
213903b705cfSriastradh			x += list->xOff;
214003b705cfSriastradh			y += list->yOff;
214103b705cfSriastradh			while (n--) {
214203b705cfSriastradh				GlyphPtr g = *glyphs++;
214303b705cfSriastradh				const void *ptr;
214403b705cfSriastradh
214503b705cfSriastradh				if (!glyph_valid(g))
214603b705cfSriastradh					goto next_pglyph;
214703b705cfSriastradh
214842542f5fSchristos				ptr = pixman_glyph_cache_lookup(__global_glyph_cache, g, NULL);
214903b705cfSriastradh				if (ptr == NULL) {
215003b705cfSriastradh					pixman_image_t *glyph_image;
215103b705cfSriastradh
215203b705cfSriastradh					glyph_image = sna_glyph_get_image(g, screen);
215303b705cfSriastradh					if (glyph_image == NULL)
215403b705cfSriastradh						goto next_pglyph;
215503b705cfSriastradh
215642542f5fSchristos					DBG(("%s: inserting glyph %p into pixman cache\n", __FUNCTION__, g));
215742542f5fSchristos					ptr = pixman_glyph_cache_insert(__global_glyph_cache, g, NULL,
215803b705cfSriastradh									g->info.x,
215903b705cfSriastradh									g->info.y,
216003b705cfSriastradh									glyph_image);
216103b705cfSriastradh					if (ptr == NULL)
216203b705cfSriastradh						goto next_pglyph;
216303b705cfSriastradh				}
216403b705cfSriastradh
216542542f5fSchristos				assert(sna_glyph_get_image(g, screen) != NULL);
216642542f5fSchristos
216703b705cfSriastradh				pglyphs[count].x = x;
216803b705cfSriastradh				pglyphs[count].y = y;
216903b705cfSriastradh				pglyphs[count].glyph = ptr;
217003b705cfSriastradh				count++;
217103b705cfSriastradh
217203b705cfSriastradhnext_pglyph:
217303b705cfSriastradh				x += g->info.xOff;
217403b705cfSriastradh				y += g->info.yOff;
217503b705cfSriastradh			}
217603b705cfSriastradh			list++;
217703b705cfSriastradh		} while (--nlist);
217803b705cfSriastradh
217903b705cfSriastradh		pixman_composite_glyphs_no_mask(PIXMAN_OP_ADD,
218003b705cfSriastradh						sna->render.white_image,
218103b705cfSriastradh						mask_image,
218203b705cfSriastradh						0, 0,
218303b705cfSriastradh						0, 0,
218442542f5fSchristos						__global_glyph_cache, count, pglyphs);
218542542f5fSchristos		pixman_glyph_cache_thaw(__global_glyph_cache);
218603b705cfSriastradh		if (pglyphs != stack_glyphs)
218703b705cfSriastradh			free(pglyphs);
218803b705cfSriastradh	} else
218903b705cfSriastradh#endif
219003b705cfSriastradh		do {
219103b705cfSriastradh			int n = list->len;
219203b705cfSriastradh			x += list->xOff;
219303b705cfSriastradh			y += list->yOff;
219403b705cfSriastradh			while (n--) {
219503b705cfSriastradh				GlyphPtr g = *glyphs++;
219603b705cfSriastradh				pixman_image_t *glyph_image;
219703b705cfSriastradh				int16_t xi, yi;
219803b705cfSriastradh
219903b705cfSriastradh				if (!glyph_valid(g))
220003b705cfSriastradh					goto next_image;
220103b705cfSriastradh
220203b705cfSriastradh				/* If the mask has been cropped, it is likely
220303b705cfSriastradh				 * that some of the glyphs fall outside.
220403b705cfSriastradh				 */
220503b705cfSriastradh				xi = x - g->info.x;
220603b705cfSriastradh				yi = y - g->info.y;
220703b705cfSriastradh				if (xi >= width || yi >= height)
220803b705cfSriastradh					goto next_image;
220903b705cfSriastradh				if (xi + g->info.width  <= 0 ||
221003b705cfSriastradh				    yi + g->info.height <= 0)
221103b705cfSriastradh					goto next_image;
221203b705cfSriastradh
221342542f5fSchristos				glyph_image = sna_glyph_get_image(g, screen);
221403b705cfSriastradh				if (glyph_image == NULL)
221503b705cfSriastradh					goto next_image;
221603b705cfSriastradh
221703b705cfSriastradh				DBG(("%s: glyph to mask (%d, %d)x(%d, %d)\n",
221803b705cfSriastradh				     __FUNCTION__,
221903b705cfSriastradh				     xi, yi,
222003b705cfSriastradh				     g->info.width,
222103b705cfSriastradh				     g->info.height));
222203b705cfSriastradh
222303b705cfSriastradh				if (list->format == format) {
222403b705cfSriastradh					assert(pixman_image_get_format(glyph_image) == pixman_image_get_format(mask_image));
222503b705cfSriastradh					pixman_image_composite(PictOpAdd,
222603b705cfSriastradh							       glyph_image,
222703b705cfSriastradh							       NULL,
222803b705cfSriastradh							       mask_image,
222903b705cfSriastradh							       0, 0,
223003b705cfSriastradh							       0, 0,
223103b705cfSriastradh							       xi, yi,
223203b705cfSriastradh							       g->info.width,
223303b705cfSriastradh							       g->info.height);
223403b705cfSriastradh				} else {
223503b705cfSriastradh					pixman_image_composite(PictOpAdd,
223603b705cfSriastradh							       sna->render.white_image,
223703b705cfSriastradh							       glyph_image,
223803b705cfSriastradh							       mask_image,
223903b705cfSriastradh							       0, 0,
224003b705cfSriastradh							       0, 0,
224103b705cfSriastradh							       xi, yi,
224203b705cfSriastradh							       g->info.width,
224303b705cfSriastradh							       g->info.height);
224403b705cfSriastradh				}
224503b705cfSriastradh
224603b705cfSriastradhnext_image:
224703b705cfSriastradh				x += g->info.xOff;
224803b705cfSriastradh				y += g->info.yOff;
224903b705cfSriastradh			}
225003b705cfSriastradh			list++;
225103b705cfSriastradh		} while (--nlist);
225203b705cfSriastradh	pixman_image_unref(mask_image);
225342542f5fSchristos	sigtrap_put();
225403b705cfSriastradh
225503b705cfSriastradh	component_alpha = NeedsComponent(format->format);
225603b705cfSriastradh
225703b705cfSriastradh	mask = CreatePicture(0, &pixmap->drawable,
225803b705cfSriastradh			     format, CPComponentAlpha,
225903b705cfSriastradh			     &component_alpha, serverClient, &error);
226003b705cfSriastradh	if (!mask)
226103b705cfSriastradh		goto err_pixmap;
226203b705cfSriastradh
226303b705cfSriastradh	ValidatePicture(mask);
226403b705cfSriastradh
226503b705cfSriastradh	sna_composite(op,
226603b705cfSriastradh		      src, mask, dst,
226703b705cfSriastradh		      src_x, src_y,
226803b705cfSriastradh		      0, 0,
226903b705cfSriastradh		      box.x1, box.y1,
227003b705cfSriastradh		      width, height);
227103b705cfSriastradh	FreePicture(mask, 0);
227203b705cfSriastradh	ret = true;
227303b705cfSriastradherr_pixmap:
227403b705cfSriastradh	sna_pixmap_destroy(pixmap);
227503b705cfSriastradh	return ret;
227603b705cfSriastradh}
227703b705cfSriastradh
227803b705cfSriastradhvoid
227903b705cfSriastradhsna_glyphs__shared(CARD8 op,
228003b705cfSriastradh		   PicturePtr src,
228103b705cfSriastradh		   PicturePtr dst,
228203b705cfSriastradh		   PictFormatPtr mask,
228303b705cfSriastradh		   INT16 src_x, INT16 src_y,
228403b705cfSriastradh		   int nlist, GlyphListPtr list, GlyphPtr *glyphs)
228503b705cfSriastradh{
228603b705cfSriastradh	PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable);
228703b705cfSriastradh	struct sna *sna = to_sna_from_pixmap(pixmap);
228803b705cfSriastradh	struct sna_pixmap *priv;
228903b705cfSriastradh
229003b705cfSriastradh	DBG(("%s(op=%d, nlist=%d, src=(%d, %d))\n",
229103b705cfSriastradh	     __FUNCTION__, op, nlist, src_x, src_y));
229203b705cfSriastradh
229342542f5fSchristos	if (RegionNil(dst->pCompositeClip))
229403b705cfSriastradh		return;
229503b705cfSriastradh
229603b705cfSriastradh	if (FALLBACK)
229703b705cfSriastradh		goto fallback;
229803b705cfSriastradh
229903b705cfSriastradh	if (!can_render(sna)) {
230003b705cfSriastradh		DBG(("%s: wedged\n", __FUNCTION__));
230103b705cfSriastradh		goto fallback;
230203b705cfSriastradh	}
230303b705cfSriastradh
230413496ba1Ssnj	if (!can_render_to_picture(dst)) {
230513496ba1Ssnj		DBG(("%s: fallback -- incompatible picture\n", __FUNCTION__));
230603b705cfSriastradh		goto fallback;
230703b705cfSriastradh	}
230803b705cfSriastradh
230903b705cfSriastradh	priv = sna_pixmap(pixmap);
231003b705cfSriastradh	if (priv == NULL) {
231103b705cfSriastradh		DBG(("%s: fallback -- destination unattached\n", __FUNCTION__));
231203b705cfSriastradh		goto fallback;
231303b705cfSriastradh	}
231403b705cfSriastradh
231542542f5fSchristos	if (!is_gpu_dst(priv) && !picture_is_gpu(sna, src, 0)) {
231603b705cfSriastradh		DBG(("%s: fallback -- too small (%dx%d)\n",
231703b705cfSriastradh		     __FUNCTION__, dst->pDrawable->width, dst->pDrawable->height));
231803b705cfSriastradh		goto fallback;
231903b705cfSriastradh	}
232003b705cfSriastradh
232103b705cfSriastradh	if (!mask) {
232203b705cfSriastradh		mask = glyphs_format(nlist, list, glyphs);
232303b705cfSriastradh		DBG(("%s: substituting mask? %d\n", __FUNCTION__, mask!=NULL));
232403b705cfSriastradh	}
232503b705cfSriastradh	if (mask) {
232603b705cfSriastradh		if (glyphs_via_image(sna, op,
232703b705cfSriastradh				     src, dst, mask,
232803b705cfSriastradh				     src_x, src_y,
232903b705cfSriastradh				     nlist, list, glyphs))
233003b705cfSriastradh			return;
233103b705cfSriastradh	}
233203b705cfSriastradh
233303b705cfSriastradhfallback:
233403b705cfSriastradh	glyphs_fallback(op, src, dst, mask, src_x, src_y, nlist, list, glyphs);
233503b705cfSriastradh}
233603b705cfSriastradh
233703b705cfSriastradhvoid
233803b705cfSriastradhsna_glyph_unrealize(ScreenPtr screen, GlyphPtr glyph)
233903b705cfSriastradh{
234003b705cfSriastradh	struct sna_glyph *p = sna_glyph(glyph);
234103b705cfSriastradh
234242542f5fSchristos	DBG(("%s: screen=%d, glyph=%p (image?=%d, atlas?=%d)\n",
234342542f5fSchristos	     __FUNCTION__, screen->myNum, glyph, !!p->image,
234442542f5fSchristos	     p->atlas && p->atlas != GetGlyphPicture(glyph, screen)));
234503b705cfSriastradh
234603b705cfSriastradh	if (p->image) {
234703b705cfSriastradh#if HAS_PIXMAN_GLYPHS
234842542f5fSchristos		if (__global_glyph_cache) {
234942542f5fSchristos			DBG(("%s: removing glyph %p from pixman cache\n",
235042542f5fSchristos			     __FUNCTION__, glyph));
235142542f5fSchristos			pixman_glyph_cache_remove(__global_glyph_cache,
235203b705cfSriastradh						  glyph, NULL);
235342542f5fSchristos		}
235403b705cfSriastradh#endif
235503b705cfSriastradh		pixman_image_unref(p->image);
235603b705cfSriastradh		p->image = NULL;
235703b705cfSriastradh	}
235803b705cfSriastradh
235903b705cfSriastradh	if (p->atlas && p->atlas != GetGlyphPicture(glyph, screen)) {
236003b705cfSriastradh		struct sna *sna = to_sna_from_screen(screen);
236103b705cfSriastradh		struct sna_glyph_cache *cache = &sna->render.glyph[p->pos&1];
236203b705cfSriastradh		DBG(("%s: releasing glyph pos %d from cache %d\n",
236303b705cfSriastradh		     __FUNCTION__, p->pos >> 1, p->pos & 1));
236403b705cfSriastradh		assert(cache->glyphs[p->pos >> 1] == p);
236503b705cfSriastradh		cache->glyphs[p->pos >> 1] = NULL;
236603b705cfSriastradh		p->atlas = NULL;
236703b705cfSriastradh	}
236842542f5fSchristos
236942542f5fSchristos#if HAS_PIXMAN_GLYPHS
237042542f5fSchristos	assert(__global_glyph_cache == NULL ||
237142542f5fSchristos	       pixman_glyph_cache_lookup(__global_glyph_cache, glyph, NULL) == NULL);
237242542f5fSchristos#endif
237303b705cfSriastradh}
2374