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