sna_glyphs.c revision 13496ba1
103b705cfSriastradh/* 203b705cfSriastradh * Copyright © 2010 Intel Corporation 303b705cfSriastradh * Partly based on code Copyright © 2008 Red Hat, Inc. 403b705cfSriastradh * Partly based on code Copyright © 2000 SuSE, Inc. 503b705cfSriastradh * 603b705cfSriastradh * Permission to use, copy, modify, distribute, and sell this software and its 703b705cfSriastradh * documentation for any purpose is hereby granted without fee, provided that 803b705cfSriastradh * the above copyright notice appear in all copies and that both that 903b705cfSriastradh * copyright notice and this permission notice appear in supporting 1003b705cfSriastradh * documentation, and that the name of Intel not be used in advertising or 1103b705cfSriastradh * publicity pertaining to distribution of the software without specific, 1203b705cfSriastradh * written prior permission. Intel makes no representations about the 1303b705cfSriastradh * suitability of this software for any purpose. It is provided "as is" 1403b705cfSriastradh * without express or implied warranty. 1503b705cfSriastradh * 1603b705cfSriastradh * INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 1703b705cfSriastradh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INTEL 1803b705cfSriastradh * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1903b705cfSriastradh * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 2003b705cfSriastradh * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 2103b705cfSriastradh * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 2203b705cfSriastradh * 2303b705cfSriastradh * Permission to use, copy, modify, distribute, and sell this software and its 2403b705cfSriastradh * documentation for any purpose is hereby granted without fee, provided that 2503b705cfSriastradh * the above copyright notice appear in all copies and that both that 2603b705cfSriastradh * copyright notice and this permission notice appear in supporting 2703b705cfSriastradh * documentation, and that the name of Red Hat not be used in advertising or 2803b705cfSriastradh * publicity pertaining to distribution of the software without specific, 2903b705cfSriastradh * written prior permission. Red Hat makes no representations about the 3003b705cfSriastradh * suitability of this software for any purpose. It is provided "as is" 3103b705cfSriastradh * without express or implied warranty. 3203b705cfSriastradh * 3303b705cfSriastradh * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 3403b705cfSriastradh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat 3503b705cfSriastradh * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 3603b705cfSriastradh * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 3703b705cfSriastradh * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 3803b705cfSriastradh * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 3903b705cfSriastradh * 4003b705cfSriastradh * Permission to use, copy, modify, distribute, and sell this software and its 4103b705cfSriastradh * documentation for any purpose is hereby granted without fee, provided that 4203b705cfSriastradh * the above copyright notice appear in all copies and that both that 4303b705cfSriastradh * copyright notice and this permission notice appear in supporting 4403b705cfSriastradh * documentation, and that the name of SuSE not be used in advertising or 4503b705cfSriastradh * publicity pertaining to distribution of the software without specific, 4603b705cfSriastradh * written prior permission. SuSE makes no representations about the 4703b705cfSriastradh * suitability of this software for any purpose. It is provided "as is" 4803b705cfSriastradh * without express or implied warranty. 4903b705cfSriastradh * 5003b705cfSriastradh * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 5103b705cfSriastradh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE 5203b705cfSriastradh * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 5303b705cfSriastradh * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 5403b705cfSriastradh * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 5503b705cfSriastradh * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 5603b705cfSriastradh * 5703b705cfSriastradh * Author: Chris Wilson <chris@chris-wilson.co.uk> 5803b705cfSriastradh * Based on code by: Keith Packard <keithp@keithp.com> and Owen Taylor <otaylor@fishsoup.net> 5903b705cfSriastradh */ 6003b705cfSriastradh 6103b705cfSriastradh#ifdef HAVE_CONFIG_H 6203b705cfSriastradh#include "config.h" 6303b705cfSriastradh#endif 6403b705cfSriastradh 6503b705cfSriastradh#include "sna.h" 6603b705cfSriastradh#include "sna_render.h" 6703b705cfSriastradh#include "sna_render_inline.h" 6803b705cfSriastradh#include "fb/fbpict.h" 6903b705cfSriastradh 7003b705cfSriastradh#define FALLBACK 0 7103b705cfSriastradh#define NO_GLYPH_CACHE 0 7203b705cfSriastradh#define NO_GLYPHS_TO_DST 0 7342542f5fSchristos#define FORCE_GLYPHS_TO_DST 0 7403b705cfSriastradh#define NO_GLYPHS_VIA_MASK 0 7542542f5fSchristos#define FORCE_SMALL_MASK 0 /* -1 = never, 1 = always */ 7603b705cfSriastradh#define NO_GLYPHS_SLOW 0 7703b705cfSriastradh#define NO_DISCARD_MASK 0 7803b705cfSriastradh 7903b705cfSriastradh#define CACHE_PICTURE_SIZE 1024 8003b705cfSriastradh#define GLYPH_MIN_SIZE 8 8103b705cfSriastradh#define GLYPH_MAX_SIZE 64 8203b705cfSriastradh#define GLYPH_CACHE_SIZE (CACHE_PICTURE_SIZE * CACHE_PICTURE_SIZE / (GLYPH_MIN_SIZE * GLYPH_MIN_SIZE)) 8303b705cfSriastradh 8403b705cfSriastradh#define N_STACK_GLYPHS 512 8542542f5fSchristos#define NO_ATLAS ((PicturePtr)-1) 8642542f5fSchristos#define GLYPH_TOLERANCE 3 8703b705cfSriastradh 8803b705cfSriastradh#define glyph_valid(g) *((uint32_t *)&(g)->info.width) 8903b705cfSriastradh#define glyph_copy_size(r, g) *(uint32_t *)&(r)->width = *(uint32_t *)&g->info.width 9003b705cfSriastradh 9142542f5fSchristos#if HAS_PIXMAN_GLYPHS 9242542f5fSchristosstatic pixman_glyph_cache_t *__global_glyph_cache; 9342542f5fSchristos#endif 9442542f5fSchristos 9503b705cfSriastradh#if HAS_DEBUG_FULL 9603b705cfSriastradhstatic void _assert_pixmap_contains_box(PixmapPtr pixmap, BoxPtr box, const char *function) 9703b705cfSriastradh{ 9803b705cfSriastradh if (box->x1 < 0 || box->y1 < 0 || 9903b705cfSriastradh box->x2 > pixmap->drawable.width || 10003b705cfSriastradh box->y2 > pixmap->drawable.height) 10103b705cfSriastradh { 10242542f5fSchristos FatalError("%s: damage box is beyond the pixmap: box=(%d, %d), (%d, %d), pixmap=(%d, %d)\n", 10342542f5fSchristos function, 10442542f5fSchristos box->x1, box->y1, box->x2, box->y2, 10542542f5fSchristos pixmap->drawable.width, 10642542f5fSchristos pixmap->drawable.height); 10703b705cfSriastradh } 10803b705cfSriastradh} 10903b705cfSriastradh#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__) 11003b705cfSriastradh#else 11103b705cfSriastradh#define assert_pixmap_contains_box(p, b) 11203b705cfSriastradh#endif 11303b705cfSriastradh 11403b705cfSriastradhextern DevPrivateKeyRec sna_glyph_key; 11503b705cfSriastradh 11603b705cfSriastradhstatic inline struct sna_glyph *sna_glyph(GlyphPtr glyph) 11703b705cfSriastradh{ 11803b705cfSriastradh return __get_private(glyph, sna_glyph_key); 11903b705cfSriastradh} 12003b705cfSriastradh 12103b705cfSriastradhstatic inline struct sna_glyph *sna_glyph0(GlyphPtr glyph) 12203b705cfSriastradh{ 12303b705cfSriastradh return (struct sna_glyph *)glyph->devPrivates; 12403b705cfSriastradh} 12503b705cfSriastradh 12603b705cfSriastradhstatic inline bool can_use_glyph0(void) 12703b705cfSriastradh{ 12803b705cfSriastradh#if HAS_DEVPRIVATEKEYREC 12903b705cfSriastradh return sna_glyph_key.offset == 0; 13003b705cfSriastradh#else 13103b705cfSriastradh return 0; 13203b705cfSriastradh#endif 13303b705cfSriastradh} 13403b705cfSriastradh 13503b705cfSriastradh#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) 13603b705cfSriastradh 13703b705cfSriastradhstatic bool op_is_bounded(uint8_t op) 13803b705cfSriastradh{ 13903b705cfSriastradh switch (op) { 14003b705cfSriastradh case PictOpOver: 14103b705cfSriastradh case PictOpOutReverse: 14203b705cfSriastradh case PictOpAdd: 14303b705cfSriastradh case PictOpXor: 14403b705cfSriastradh return true; 14503b705cfSriastradh default: 14603b705cfSriastradh return false; 14703b705cfSriastradh } 14803b705cfSriastradh} 14903b705cfSriastradh 15003b705cfSriastradhvoid sna_glyphs_close(struct sna *sna) 15103b705cfSriastradh{ 15203b705cfSriastradh struct sna_render *render = &sna->render; 15303b705cfSriastradh unsigned int i; 15403b705cfSriastradh 15503b705cfSriastradh DBG(("%s\n", __FUNCTION__)); 15603b705cfSriastradh 15703b705cfSriastradh for (i = 0; i < ARRAY_SIZE(render->glyph); i++) { 15803b705cfSriastradh struct sna_glyph_cache *cache = &render->glyph[i]; 15903b705cfSriastradh 16003b705cfSriastradh if (cache->picture) 16103b705cfSriastradh FreePicture(cache->picture, 0); 16203b705cfSriastradh 16303b705cfSriastradh free(cache->glyphs); 16403b705cfSriastradh } 16503b705cfSriastradh memset(render->glyph, 0, sizeof(render->glyph)); 16603b705cfSriastradh 16703b705cfSriastradh if (render->white_image) { 16803b705cfSriastradh pixman_image_unref(render->white_image); 16903b705cfSriastradh render->white_image = NULL; 17003b705cfSriastradh } 17103b705cfSriastradh if (render->white_picture) { 17203b705cfSriastradh FreePicture(render->white_picture, 0); 17303b705cfSriastradh render->white_picture = NULL; 17403b705cfSriastradh } 17503b705cfSriastradh} 17603b705cfSriastradh 17703b705cfSriastradh/* All caches for a single format share a single pixmap for glyph storage, 17803b705cfSriastradh * allowing mixing glyphs of different sizes without paying a penalty 17903b705cfSriastradh * for switching between source pixmaps. (Note that for a size of font 18003b705cfSriastradh * right at the border between two sizes, we might be switching for almost 18103b705cfSriastradh * every glyph.) 18203b705cfSriastradh * 18303b705cfSriastradh * This function allocates the storage pixmap, and then fills in the 18403b705cfSriastradh * rest of the allocated structures for all caches with the given format. 18503b705cfSriastradh */ 18603b705cfSriastradhbool sna_glyphs_create(struct sna *sna) 18703b705cfSriastradh{ 18803b705cfSriastradh ScreenPtr screen = sna->scrn->pScreen; 18903b705cfSriastradh pixman_color_t white = { 0xffff, 0xffff, 0xffff, 0xffff }; 19003b705cfSriastradh unsigned int formats[] = { 19103b705cfSriastradh PIXMAN_a8, 19203b705cfSriastradh PIXMAN_a8r8g8b8, 19303b705cfSriastradh }; 19403b705cfSriastradh unsigned int i; 19503b705cfSriastradh int error; 19603b705cfSriastradh 19703b705cfSriastradh DBG(("%s\n", __FUNCTION__)); 19803b705cfSriastradh 19903b705cfSriastradh#if HAS_PIXMAN_GLYPHS 20042542f5fSchristos if (__global_glyph_cache == NULL) { 20142542f5fSchristos __global_glyph_cache = pixman_glyph_cache_create(); 20242542f5fSchristos if (__global_glyph_cache == NULL) 20342542f5fSchristos goto bail; 20442542f5fSchristos } 20503b705cfSriastradh#endif 20603b705cfSriastradh 20703b705cfSriastradh sna->render.white_image = pixman_image_create_solid_fill(&white); 20803b705cfSriastradh if (sna->render.white_image == NULL) 20903b705cfSriastradh goto bail; 21003b705cfSriastradh 21103b705cfSriastradh if (!can_render(sna)) { 21203b705cfSriastradh DBG(("%s: no render acceleration, no render glyph caches\n", 21303b705cfSriastradh __FUNCTION__)); 21403b705cfSriastradh return true; 21503b705cfSriastradh } 21603b705cfSriastradh 21703b705cfSriastradh if (xf86IsEntityShared(sna->scrn->entityList[0])) { 21803b705cfSriastradh DBG(("%s: shared GlyphPictures, no render glyph caches\n", 21903b705cfSriastradh __FUNCTION__)); 22003b705cfSriastradh return true; 22103b705cfSriastradh } 22203b705cfSriastradh 22303b705cfSriastradh for (i = 0; i < ARRAY_SIZE(formats); i++) { 22403b705cfSriastradh struct sna_glyph_cache *cache = &sna->render.glyph[i]; 22503b705cfSriastradh struct sna_pixmap *priv; 22603b705cfSriastradh PixmapPtr pixmap; 22703b705cfSriastradh PicturePtr picture = NULL; 22803b705cfSriastradh PictFormatPtr pPictFormat; 22903b705cfSriastradh CARD32 component_alpha; 23003b705cfSriastradh int depth = PIXMAN_FORMAT_DEPTH(formats[i]); 23103b705cfSriastradh 23203b705cfSriastradh pPictFormat = PictureMatchFormat(screen, depth, formats[i]); 23303b705cfSriastradh if (!pPictFormat) 23403b705cfSriastradh goto bail; 23503b705cfSriastradh 23603b705cfSriastradh /* Now allocate the pixmap and picture */ 23703b705cfSriastradh pixmap = screen->CreatePixmap(screen, 23803b705cfSriastradh CACHE_PICTURE_SIZE, 23903b705cfSriastradh CACHE_PICTURE_SIZE, 24003b705cfSriastradh depth, 24142542f5fSchristos SNA_CREATE_SCRATCH); 24203b705cfSriastradh if (!pixmap) { 24303b705cfSriastradh DBG(("%s: failed to allocate pixmap for Glyph cache\n", 24403b705cfSriastradh __FUNCTION__)); 24503b705cfSriastradh goto bail; 24603b705cfSriastradh } 24703b705cfSriastradh 24803b705cfSriastradh priv = sna_pixmap(pixmap); 24903b705cfSriastradh if (priv != NULL) { 25003b705cfSriastradh /* Prevent the cache from ever being paged out */ 25142542f5fSchristos assert(priv->gpu_bo); 25203b705cfSriastradh priv->pinned = PIN_SCANOUT; 25303b705cfSriastradh 25403b705cfSriastradh component_alpha = NeedsComponent(pPictFormat->format); 25503b705cfSriastradh picture = CreatePicture(0, &pixmap->drawable, pPictFormat, 25603b705cfSriastradh CPComponentAlpha, &component_alpha, 25703b705cfSriastradh serverClient, &error); 25803b705cfSriastradh } 25903b705cfSriastradh 26003b705cfSriastradh screen->DestroyPixmap(pixmap); 26103b705cfSriastradh if (!picture) 26203b705cfSriastradh goto bail; 26303b705cfSriastradh 26403b705cfSriastradh ValidatePicture(picture); 26503b705cfSriastradh assert(picture->pDrawable == &pixmap->drawable); 26603b705cfSriastradh 26703b705cfSriastradh cache->count = cache->evict = 0; 26803b705cfSriastradh cache->picture = picture; 26903b705cfSriastradh cache->glyphs = calloc(sizeof(struct sna_glyph *), 27003b705cfSriastradh GLYPH_CACHE_SIZE); 27103b705cfSriastradh if (!cache->glyphs) 27203b705cfSriastradh goto bail; 27303b705cfSriastradh 27403b705cfSriastradh cache->evict = rand() % GLYPH_CACHE_SIZE; 27503b705cfSriastradh } 27603b705cfSriastradh 27703b705cfSriastradh sna->render.white_picture = 27803b705cfSriastradh CreateSolidPicture(0, (xRenderColor *)&white, &error); 27903b705cfSriastradh if (sna->render.white_picture == NULL) 28003b705cfSriastradh goto bail; 28103b705cfSriastradh 28203b705cfSriastradh return true; 28303b705cfSriastradh 28403b705cfSriastradhbail: 28503b705cfSriastradh sna_glyphs_close(sna); 28603b705cfSriastradh return false; 28703b705cfSriastradh} 28803b705cfSriastradh 28903b705cfSriastradhstatic void 29003b705cfSriastradhglyph_cache_upload(struct sna_glyph_cache *cache, 29103b705cfSriastradh GlyphPtr glyph, PicturePtr glyph_picture, 29203b705cfSriastradh int16_t x, int16_t y) 29303b705cfSriastradh{ 29403b705cfSriastradh DBG(("%s: upload glyph %p to cache (%d, %d)x(%d, %d)\n", 29503b705cfSriastradh __FUNCTION__, 29603b705cfSriastradh glyph, x, y, 29703b705cfSriastradh glyph_picture->pDrawable->width, 29803b705cfSriastradh glyph_picture->pDrawable->height)); 29903b705cfSriastradh sna_composite(PictOpSrc, 30003b705cfSriastradh glyph_picture, 0, cache->picture, 30103b705cfSriastradh 0, 0, 30203b705cfSriastradh 0, 0, 30303b705cfSriastradh x, y, 30403b705cfSriastradh glyph_picture->pDrawable->width, 30503b705cfSriastradh glyph_picture->pDrawable->height); 30603b705cfSriastradh} 30703b705cfSriastradh 30803b705cfSriastradhstatic void 30903b705cfSriastradhglyph_extents(int nlist, 31003b705cfSriastradh GlyphListPtr list, 31103b705cfSriastradh GlyphPtr *glyphs, 31203b705cfSriastradh BoxPtr extents) 31303b705cfSriastradh{ 31442542f5fSchristos int x1, x2, y1, y2; 31542542f5fSchristos int x, y; 31603b705cfSriastradh 31703b705cfSriastradh x1 = y1 = MAXSHORT; 31803b705cfSriastradh x2 = y2 = MINSHORT; 31903b705cfSriastradh x = y = 0; 32003b705cfSriastradh while (nlist--) { 32103b705cfSriastradh int n = list->len; 32203b705cfSriastradh x += list->xOff; 32303b705cfSriastradh y += list->yOff; 32403b705cfSriastradh list++; 32503b705cfSriastradh while (n--) { 32603b705cfSriastradh GlyphPtr glyph = *glyphs++; 32703b705cfSriastradh 32803b705cfSriastradh if (glyph_valid(glyph)) { 32903b705cfSriastradh int v; 33003b705cfSriastradh 33103b705cfSriastradh v = x - glyph->info.x; 33203b705cfSriastradh if (v < x1) 33303b705cfSriastradh x1 = v; 33403b705cfSriastradh v += glyph->info.width; 33503b705cfSriastradh if (v > x2) 33603b705cfSriastradh x2 = v; 33703b705cfSriastradh 33803b705cfSriastradh v = y - glyph->info.y; 33903b705cfSriastradh if (v < y1) 34003b705cfSriastradh y1 = v; 34103b705cfSriastradh v += glyph->info.height; 34203b705cfSriastradh if (v > y2) 34303b705cfSriastradh y2 = v; 34403b705cfSriastradh } 34503b705cfSriastradh 34603b705cfSriastradh x += glyph->info.xOff; 34703b705cfSriastradh y += glyph->info.yOff; 34803b705cfSriastradh } 34903b705cfSriastradh } 35003b705cfSriastradh 35142542f5fSchristos extents->x1 = x1 > MINSHORT ? x1 : MINSHORT; 35242542f5fSchristos extents->y1 = y1 > MINSHORT ? y1 : MINSHORT; 35342542f5fSchristos extents->x2 = x2 < MAXSHORT ? x2 : MAXSHORT; 35442542f5fSchristos extents->y2 = y2 < MAXSHORT ? y2 : MAXSHORT; 35542542f5fSchristos} 35642542f5fSchristos 35742542f5fSchristos#if HAS_DEBUG_FULL 35842542f5fSchristosstatic int 35942542f5fSchristosglyph_count(int nlist, 36042542f5fSchristos GlyphListPtr list) 36142542f5fSchristos{ 36242542f5fSchristos int count = 0; 36342542f5fSchristos while (nlist--) { 36442542f5fSchristos count += list->len; 36542542f5fSchristos list++; 36642542f5fSchristos } 36742542f5fSchristos return count; 36803b705cfSriastradh} 36942542f5fSchristos#endif 37003b705cfSriastradh 37103b705cfSriastradhstatic inline unsigned int 37203b705cfSriastradhglyph_size_to_count(int size) 37303b705cfSriastradh{ 37403b705cfSriastradh size /= GLYPH_MIN_SIZE; 37503b705cfSriastradh return size * size; 37603b705cfSriastradh} 37703b705cfSriastradh 37803b705cfSriastradhstatic inline unsigned int 37903b705cfSriastradhglyph_count_to_mask(int count) 38003b705cfSriastradh{ 38103b705cfSriastradh return ~(count - 1); 38203b705cfSriastradh} 38303b705cfSriastradh 38403b705cfSriastradhstatic inline unsigned int 38503b705cfSriastradhglyph_size_to_mask(int size) 38603b705cfSriastradh{ 38703b705cfSriastradh return glyph_count_to_mask(glyph_size_to_count(size)); 38803b705cfSriastradh} 38903b705cfSriastradh 39003b705cfSriastradhstatic int 39103b705cfSriastradhglyph_cache(ScreenPtr screen, 39203b705cfSriastradh struct sna_render *render, 39303b705cfSriastradh GlyphPtr glyph) 39403b705cfSriastradh{ 39503b705cfSriastradh PicturePtr glyph_picture; 39603b705cfSriastradh struct sna_glyph_cache *cache; 39703b705cfSriastradh struct sna_glyph *p; 39803b705cfSriastradh int size, mask, pos, s; 39903b705cfSriastradh 40042542f5fSchristos assert(glyph_valid(glyph)); 40103b705cfSriastradh 40203b705cfSriastradh glyph_picture = GetGlyphPicture(glyph, screen); 40303b705cfSriastradh if (unlikely(glyph_picture == NULL)) { 40403b705cfSriastradh glyph->info.width = glyph->info.height = 0; 40503b705cfSriastradh return false; 40603b705cfSriastradh } 40703b705cfSriastradh 40842542f5fSchristos if (NO_GLYPH_CACHE || 40942542f5fSchristos glyph->info.width > GLYPH_MAX_SIZE || 41003b705cfSriastradh glyph->info.height > GLYPH_MAX_SIZE) { 41103b705cfSriastradh PixmapPtr pixmap = (PixmapPtr)glyph_picture->pDrawable; 41203b705cfSriastradh assert(glyph_picture->pDrawable->type == DRAWABLE_PIXMAP); 41303b705cfSriastradh if (pixmap->drawable.depth >= 8) { 41403b705cfSriastradh pixmap->usage_hint = 0; 41503b705cfSriastradh sna_pixmap_force_to_gpu(pixmap, MOVE_READ); 41603b705cfSriastradh } 41742542f5fSchristos 41842542f5fSchristos /* no cache for this glyph */ 41942542f5fSchristos p = sna_glyph(glyph); 42042542f5fSchristos p->atlas = glyph_picture; 42142542f5fSchristos p->coordinate.x = p->coordinate.y = 0; 42242542f5fSchristos return true; 42303b705cfSriastradh } 42403b705cfSriastradh 42503b705cfSriastradh for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2) 42603b705cfSriastradh if (glyph->info.width <= size && glyph->info.height <= size) 42703b705cfSriastradh break; 42803b705cfSriastradh 42903b705cfSriastradh cache = &render->glyph[PICT_FORMAT_RGB(glyph_picture->format) != 0]; 43003b705cfSriastradh s = glyph_size_to_count(size); 43103b705cfSriastradh mask = glyph_count_to_mask(s); 43203b705cfSriastradh pos = (cache->count + s - 1) & mask; 43303b705cfSriastradh if (pos < GLYPH_CACHE_SIZE) { 43403b705cfSriastradh cache->count = pos + s; 43503b705cfSriastradh } else { 43603b705cfSriastradh p = NULL; 43703b705cfSriastradh for (s = size; s <= GLYPH_MAX_SIZE; s *= 2) { 43803b705cfSriastradh int i = cache->evict & glyph_size_to_mask(s); 43903b705cfSriastradh p = cache->glyphs[i]; 44003b705cfSriastradh if (p == NULL) 44103b705cfSriastradh continue; 44203b705cfSriastradh 44303b705cfSriastradh if (p->size >= s) { 44403b705cfSriastradh cache->glyphs[i] = NULL; 44503b705cfSriastradh p->atlas = NULL; 44603b705cfSriastradh pos = i; 44703b705cfSriastradh } else 44803b705cfSriastradh p = NULL; 44903b705cfSriastradh break; 45003b705cfSriastradh } 45103b705cfSriastradh if (p == NULL) { 45203b705cfSriastradh int count = glyph_size_to_count(size); 45303b705cfSriastradh pos = cache->evict & glyph_count_to_mask(count); 45403b705cfSriastradh for (s = 0; s < count; s++) { 45503b705cfSriastradh p = cache->glyphs[pos + s]; 45603b705cfSriastradh if (p != NULL) { 45703b705cfSriastradh p->atlas =NULL; 45803b705cfSriastradh cache->glyphs[pos + s] = NULL; 45903b705cfSriastradh } 46003b705cfSriastradh } 46103b705cfSriastradh } 46203b705cfSriastradh 46303b705cfSriastradh /* And pick a new eviction position */ 46403b705cfSriastradh cache->evict = rand() % GLYPH_CACHE_SIZE; 46503b705cfSriastradh } 46603b705cfSriastradh assert(cache->glyphs[pos] == NULL); 46703b705cfSriastradh 46803b705cfSriastradh p = sna_glyph(glyph); 46903b705cfSriastradh DBG(("%s(%d): adding glyph to cache %d, pos %d\n", 47003b705cfSriastradh __FUNCTION__, screen->myNum, 47103b705cfSriastradh PICT_FORMAT_RGB(glyph_picture->format) != 0, pos)); 47203b705cfSriastradh cache->glyphs[pos] = p; 47303b705cfSriastradh p->atlas = cache->picture; 47403b705cfSriastradh p->size = size; 47503b705cfSriastradh p->pos = pos << 1 | (PICT_FORMAT_RGB(glyph_picture->format) != 0); 47603b705cfSriastradh s = pos / ((GLYPH_MAX_SIZE / GLYPH_MIN_SIZE) * (GLYPH_MAX_SIZE / GLYPH_MIN_SIZE)); 47703b705cfSriastradh p->coordinate.x = s % (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE) * GLYPH_MAX_SIZE; 47803b705cfSriastradh p->coordinate.y = (s / (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE)) * GLYPH_MAX_SIZE; 47903b705cfSriastradh for (s = GLYPH_MIN_SIZE; s < GLYPH_MAX_SIZE; s *= 2) { 48003b705cfSriastradh if (pos & 1) 48103b705cfSriastradh p->coordinate.x += s; 48203b705cfSriastradh if (pos & 2) 48303b705cfSriastradh p->coordinate.y += s; 48403b705cfSriastradh pos >>= 2; 48503b705cfSriastradh } 48603b705cfSriastradh 48703b705cfSriastradh glyph_cache_upload(cache, glyph, glyph_picture, 48803b705cfSriastradh p->coordinate.x, p->coordinate.y); 48903b705cfSriastradh 49003b705cfSriastradh return true; 49103b705cfSriastradh} 49203b705cfSriastradh 49303b705cfSriastradhstatic void apply_damage(struct sna_composite_op *op, 49403b705cfSriastradh const struct sna_composite_rectangles *r) 49503b705cfSriastradh{ 49603b705cfSriastradh BoxRec box; 49703b705cfSriastradh 49803b705cfSriastradh if (op->damage == NULL) 49903b705cfSriastradh return; 50003b705cfSriastradh 50103b705cfSriastradh box.x1 = r->dst.x + op->dst.x; 50203b705cfSriastradh box.y1 = r->dst.y + op->dst.y; 50303b705cfSriastradh box.x2 = box.x1 + r->width; 50403b705cfSriastradh box.y2 = box.y1 + r->height; 50503b705cfSriastradh 50603b705cfSriastradh assert_pixmap_contains_box(op->dst.pixmap, &box); 50703b705cfSriastradh sna_damage_add_box(op->damage, &box); 50803b705cfSriastradh} 50903b705cfSriastradh 51003b705cfSriastradhstatic void apply_damage_clipped_to_dst(struct sna_composite_op *op, 51103b705cfSriastradh const struct sna_composite_rectangles *r, 51203b705cfSriastradh DrawablePtr dst) 51303b705cfSriastradh{ 51403b705cfSriastradh BoxRec box; 51503b705cfSriastradh 51603b705cfSriastradh if (op->damage == NULL) 51703b705cfSriastradh return; 51803b705cfSriastradh 51903b705cfSriastradh box.x1 = r->dst.x + op->dst.x; 52003b705cfSriastradh box.y1 = r->dst.y + op->dst.y; 52103b705cfSriastradh box.x2 = box.x1 + r->width; 52203b705cfSriastradh box.y2 = box.y1 + r->height; 52303b705cfSriastradh 52403b705cfSriastradh if (box.x1 < dst->x) 52503b705cfSriastradh box.x1 = dst->x; 52603b705cfSriastradh 52703b705cfSriastradh if (box.x2 > op->dst.width) 52803b705cfSriastradh box.x2 = op->dst.width; 52903b705cfSriastradh 53003b705cfSriastradh if (box.y1 < dst->y) 53103b705cfSriastradh box.y1 = dst->y; 53203b705cfSriastradh 53303b705cfSriastradh if (box.y2 > op->dst.height) 53403b705cfSriastradh box.y2 = op->dst.height; 53503b705cfSriastradh 53603b705cfSriastradh assert_pixmap_contains_box(op->dst.pixmap, &box); 53703b705cfSriastradh sna_damage_add_box(op->damage, &box); 53803b705cfSriastradh} 53903b705cfSriastradh 54042542f5fSchristosstatic inline bool region_matches_pixmap(const RegionRec *r, PixmapPtr pixmap) 54142542f5fSchristos{ 54242542f5fSchristos return (r->extents.x2 - r->extents.x1 >= pixmap->drawable.width && 54342542f5fSchristos r->extents.y2 - r->extents.y1 >= pixmap->drawable.height); 54442542f5fSchristos} 54542542f5fSchristos 54642542f5fSchristosstatic inline bool clipped_glyphs(PicturePtr dst, int nlist, GlyphListPtr list, GlyphPtr *glyphs) 54742542f5fSchristos{ 54842542f5fSchristos BoxRec box; 54942542f5fSchristos 55042542f5fSchristos if (dst->pCompositeClip->data == NULL && 55142542f5fSchristos region_matches_pixmap(dst->pCompositeClip, 55242542f5fSchristos get_drawable_pixmap(dst->pDrawable))) { 55342542f5fSchristos DBG(("%s: no, clip region (%d, %d), (%d, %d) matches drawable pixmap=%ld size=%dx%d\n", 55442542f5fSchristos __FUNCTION__, 55542542f5fSchristos dst->pCompositeClip->extents.x1, 55642542f5fSchristos dst->pCompositeClip->extents.y1, 55742542f5fSchristos dst->pCompositeClip->extents.x2, 55842542f5fSchristos dst->pCompositeClip->extents.y2, 55942542f5fSchristos get_drawable_pixmap(dst->pDrawable), 56042542f5fSchristos get_drawable_pixmap(dst->pDrawable)->drawable.width, 56142542f5fSchristos get_drawable_pixmap(dst->pDrawable)->drawable.height)); 56242542f5fSchristos return false; 56342542f5fSchristos } 56442542f5fSchristos 56542542f5fSchristos glyph_extents(nlist, list, glyphs, &box); 56642542f5fSchristos 56742542f5fSchristos box.x1 += dst->pDrawable->x; 56842542f5fSchristos box.x2 += dst->pDrawable->x; 56942542f5fSchristos box.y1 += dst->pDrawable->y; 57042542f5fSchristos box.y2 += dst->pDrawable->y; 57142542f5fSchristos 57242542f5fSchristos DBG(("%s? %d glyph in %d lists extents (%d, %d), (%d, %d), region (%d, %d), (%d, %d): %s\n", 57342542f5fSchristos __FUNCTION__, glyph_count(nlist, list), nlist, box.x1, box.y1, box.x2, box.y2, 57442542f5fSchristos dst->pCompositeClip->extents.x1, dst->pCompositeClip->extents.y1, 57542542f5fSchristos dst->pCompositeClip->extents.x2, dst->pCompositeClip->extents.y2, 57642542f5fSchristos pixman_region_contains_rectangle(dst->pCompositeClip, 57742542f5fSchristos &box) != PIXMAN_REGION_IN ? "yes" : "no")); 57842542f5fSchristos 57942542f5fSchristos return pixman_region_contains_rectangle(dst->pCompositeClip, 58042542f5fSchristos &box) != PIXMAN_REGION_IN; 58142542f5fSchristos} 58242542f5fSchristos 58303b705cfSriastradhflatten static bool 58403b705cfSriastradhglyphs_to_dst(struct sna *sna, 58503b705cfSriastradh CARD8 op, 58603b705cfSriastradh PicturePtr src, 58703b705cfSriastradh PicturePtr dst, 58803b705cfSriastradh INT16 src_x, INT16 src_y, 58903b705cfSriastradh int nlist, GlyphListPtr list, GlyphPtr *glyphs) 59003b705cfSriastradh{ 59103b705cfSriastradh struct sna_composite_op tmp; 59203b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 59303b705cfSriastradh PicturePtr glyph_atlas; 59442542f5fSchristos const BoxRec *rects; 59503b705cfSriastradh int nrect; 59603b705cfSriastradh int16_t x, y; 59703b705cfSriastradh 59803b705cfSriastradh if (NO_GLYPHS_TO_DST) 59903b705cfSriastradh return false; 60003b705cfSriastradh 60103b705cfSriastradh memset(&tmp, 0, sizeof(tmp)); 60203b705cfSriastradh 60303b705cfSriastradh DBG(("%s(op=%d, src=(%d, %d), nlist=%d, dst=(%d, %d)+(%d, %d))\n", 60403b705cfSriastradh __FUNCTION__, op, src_x, src_y, nlist, 60503b705cfSriastradh list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y)); 60603b705cfSriastradh 60742542f5fSchristos if (clipped_glyphs(dst, nlist, list, glyphs)) { 60842542f5fSchristos rects = region_rects(dst->pCompositeClip); 60942542f5fSchristos nrect = region_num_rects(dst->pCompositeClip); 61003b705cfSriastradh } else 61103b705cfSriastradh nrect = 0; 61203b705cfSriastradh 61303b705cfSriastradh x = dst->pDrawable->x; 61403b705cfSriastradh y = dst->pDrawable->y; 61503b705cfSriastradh src_x -= list->xOff + x; 61603b705cfSriastradh src_y -= list->yOff + y; 61703b705cfSriastradh 61842542f5fSchristos glyph_atlas = NO_ATLAS; 61903b705cfSriastradh while (nlist--) { 62003b705cfSriastradh int n = list->len; 62103b705cfSriastradh x += list->xOff; 62203b705cfSriastradh y += list->yOff; 62303b705cfSriastradh while (n--) { 62403b705cfSriastradh GlyphPtr glyph = *glyphs++; 62503b705cfSriastradh struct sna_glyph *p; 62603b705cfSriastradh int i; 62703b705cfSriastradh 62803b705cfSriastradh p = sna_glyph(glyph); 62942542f5fSchristos if (unlikely(p->atlas != glyph_atlas)) { 63003b705cfSriastradh if (unlikely(!glyph_valid(glyph))) 63103b705cfSriastradh goto next_glyph; 63203b705cfSriastradh 63342542f5fSchristos if (glyph_atlas != NO_ATLAS) { 63403b705cfSriastradh tmp.done(sna, &tmp); 63542542f5fSchristos glyph_atlas = NO_ATLAS; 63603b705cfSriastradh } 63703b705cfSriastradh 63842542f5fSchristos if (p->atlas == NULL && 63942542f5fSchristos !glyph_cache(screen, &sna->render, glyph)) 64042542f5fSchristos goto next_glyph; 64103b705cfSriastradh 64203b705cfSriastradh if (!sna->render.composite(sna, 64303b705cfSriastradh op, src, p->atlas, dst, 64403b705cfSriastradh 0, 0, 0, 0, 0, 0, 64503b705cfSriastradh 0, 0, 64642542f5fSchristos COMPOSITE_PARTIAL, &tmp)) 64703b705cfSriastradh return false; 64803b705cfSriastradh 64903b705cfSriastradh glyph_atlas = p->atlas; 65003b705cfSriastradh } 65103b705cfSriastradh 65203b705cfSriastradh if (nrect) { 65342542f5fSchristos int xi = x - glyph->info.x; 65442542f5fSchristos int yi = y - glyph->info.y; 65542542f5fSchristos 65642542f5fSchristos if (xi < dst->pCompositeClip->extents.x2 && 65742542f5fSchristos yi < dst->pCompositeClip->extents.y2 && 65842542f5fSchristos xi + glyph->info.width > dst->pCompositeClip->extents.x1 && 65942542f5fSchristos yi + glyph->info.height > dst->pCompositeClip->extents.y1) { 66042542f5fSchristos for (i = 0; i < nrect; i++) { 66142542f5fSchristos struct sna_composite_rectangles r; 66242542f5fSchristos int16_t dx, dy; 66342542f5fSchristos int16_t x2, y2; 66442542f5fSchristos 66542542f5fSchristos r.dst.x = xi; 66642542f5fSchristos r.dst.y = yi; 66742542f5fSchristos x2 = xi + glyph->info.width; 66842542f5fSchristos y2 = yi + glyph->info.height; 66942542f5fSchristos dx = dy = 0; 67042542f5fSchristos 67142542f5fSchristos DBG(("%s: glyph=(%d, %d), (%d, %d), clip=(%d, %d), (%d, %d)\n", 67242542f5fSchristos __FUNCTION__, 67342542f5fSchristos r.dst.x, r.dst.y, x2, y2, 67442542f5fSchristos rects[i].x1, rects[i].y1, 67542542f5fSchristos rects[i].x2, rects[i].y2)); 67642542f5fSchristos if (rects[i].y1 >= y2) 67742542f5fSchristos break; 67842542f5fSchristos 67942542f5fSchristos if (r.dst.x < rects[i].x1) 68042542f5fSchristos dx = rects[i].x1 - r.dst.x, r.dst.x = rects[i].x1; 68142542f5fSchristos if (x2 > rects[i].x2) 68242542f5fSchristos x2 = rects[i].x2; 68342542f5fSchristos if (r.dst.y < rects[i].y1) 68442542f5fSchristos dy = rects[i].y1 - r.dst.y, r.dst.y = rects[i].y1; 68542542f5fSchristos if (y2 > rects[i].y2) 68642542f5fSchristos y2 = rects[i].y2; 68742542f5fSchristos 68842542f5fSchristos assert(dx >= 0 && dy >= 0); 68942542f5fSchristos 69042542f5fSchristos if (r.dst.x < x2 && r.dst.y < y2) { 69142542f5fSchristos DBG(("%s: blt=(%d, %d), (%d, %d)\n", 69242542f5fSchristos __FUNCTION__, r.dst.x, r.dst.y, x2, y2)); 69342542f5fSchristos 69442542f5fSchristos r.src.x = r.dst.x + src_x; 69542542f5fSchristos r.src.y = r.dst.y + src_y; 69642542f5fSchristos r.mask.x = dx + p->coordinate.x; 69742542f5fSchristos r.mask.y = dy + p->coordinate.y; 69842542f5fSchristos r.width = x2 - r.dst.x; 69942542f5fSchristos r.height = y2 - r.dst.y; 70042542f5fSchristos tmp.blt(sna, &tmp, &r); 70142542f5fSchristos apply_damage(&tmp, &r); 70242542f5fSchristos } 70303b705cfSriastradh } 70403b705cfSriastradh } 70503b705cfSriastradh } else { 70603b705cfSriastradh struct sna_composite_rectangles r; 70703b705cfSriastradh 70803b705cfSriastradh r.dst.x = x - glyph->info.x; 70903b705cfSriastradh r.dst.y = y - glyph->info.y; 71003b705cfSriastradh r.src.x = r.dst.x + src_x; 71103b705cfSriastradh r.src.y = r.dst.y + src_y; 71203b705cfSriastradh r.mask = p->coordinate; 71303b705cfSriastradh glyph_copy_size(&r, glyph); 71403b705cfSriastradh 71503b705cfSriastradh DBG(("%s: glyph=(%d, %d)x(%d, %d), unclipped\n", 71603b705cfSriastradh __FUNCTION__, 71703b705cfSriastradh r.dst.x, r.dst.y, 71803b705cfSriastradh r.width, r.height)); 71903b705cfSriastradh 72003b705cfSriastradh tmp.blt(sna, &tmp, &r); 72103b705cfSriastradh apply_damage_clipped_to_dst(&tmp, &r, dst->pDrawable); 72203b705cfSriastradh } 72303b705cfSriastradh 72403b705cfSriastradhnext_glyph: 72503b705cfSriastradh x += glyph->info.xOff; 72603b705cfSriastradh y += glyph->info.yOff; 72703b705cfSriastradh } 72803b705cfSriastradh list++; 72903b705cfSriastradh } 73013496ba1Ssnj if (glyph_atlas != NO_ATLAS) 73103b705cfSriastradh tmp.done(sna, &tmp); 73203b705cfSriastradh 73303b705cfSriastradh return true; 73403b705cfSriastradh} 73503b705cfSriastradh 73603b705cfSriastradhflatten static bool 73703b705cfSriastradhglyphs0_to_dst(struct sna *sna, 73803b705cfSriastradh CARD8 op, 73903b705cfSriastradh PicturePtr src, 74003b705cfSriastradh PicturePtr dst, 74103b705cfSriastradh INT16 src_x, INT16 src_y, 74203b705cfSriastradh int nlist, GlyphListPtr list, GlyphPtr *glyphs) 74303b705cfSriastradh{ 74403b705cfSriastradh struct sna_composite_op tmp; 74503b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 74642542f5fSchristos PicturePtr glyph_atlas = NO_ATLAS; 74742542f5fSchristos int x, y; 74803b705cfSriastradh 74903b705cfSriastradh if (NO_GLYPHS_TO_DST) 75003b705cfSriastradh return false; 75103b705cfSriastradh 75203b705cfSriastradh memset(&tmp, 0, sizeof(tmp)); 75303b705cfSriastradh 75403b705cfSriastradh DBG(("%s(op=%d, src=(%d, %d), nlist=%d, dst=(%d, %d)+(%d, %d))\n", 75503b705cfSriastradh __FUNCTION__, op, src_x, src_y, nlist, 75603b705cfSriastradh list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y)); 75703b705cfSriastradh 75803b705cfSriastradh x = dst->pDrawable->x; 75903b705cfSriastradh y = dst->pDrawable->y; 76003b705cfSriastradh src_x -= list->xOff + x; 76103b705cfSriastradh src_y -= list->yOff + y; 76203b705cfSriastradh 76342542f5fSchristos if (clipped_glyphs(dst, nlist, list, glyphs)) { 76442542f5fSchristos const BoxRec *rects = region_rects(dst->pCompositeClip); 76542542f5fSchristos int nrect = region_num_rects(dst->pCompositeClip); 76642542f5fSchristos if (nrect == 0) 76742542f5fSchristos return true; 76842542f5fSchristos 76942542f5fSchristos while (nlist--) { 77042542f5fSchristos int n = list->len; 77142542f5fSchristos x += list->xOff; 77242542f5fSchristos y += list->yOff; 77342542f5fSchristos while (n--) { 77442542f5fSchristos GlyphPtr glyph = *glyphs++; 77542542f5fSchristos struct sna_glyph *p = sna_glyph0(glyph); 77642542f5fSchristos int i, xi, yi; 77742542f5fSchristos 77842542f5fSchristos if (unlikely(p->atlas != glyph_atlas)) { 77942542f5fSchristos if (unlikely(!glyph_valid(glyph))) 78042542f5fSchristos goto next_glyph_N; 78142542f5fSchristos 78242542f5fSchristos if (glyph_atlas != NO_ATLAS) { 78342542f5fSchristos tmp.done(sna, &tmp); 78442542f5fSchristos glyph_atlas = NO_ATLAS; 78542542f5fSchristos } 78642542f5fSchristos 78742542f5fSchristos if (unlikely(p->atlas == NULL)) { 78842542f5fSchristos if (!glyph_cache(screen, &sna->render, glyph)) 78942542f5fSchristos goto next_glyph_N; 79042542f5fSchristos } 79142542f5fSchristos 79242542f5fSchristos if (!sna->render.composite(sna, 79342542f5fSchristos op, src, p->atlas, dst, 79442542f5fSchristos 0, 0, 0, 0, 0, 0, 79542542f5fSchristos 0, 0, 79642542f5fSchristos COMPOSITE_PARTIAL, &tmp)) 79742542f5fSchristos return false; 79842542f5fSchristos 79942542f5fSchristos glyph_atlas = p->atlas; 80042542f5fSchristos } 80142542f5fSchristos 80242542f5fSchristos xi = x - glyph->info.x; 80342542f5fSchristos yi = y - glyph->info.y; 80442542f5fSchristos 80542542f5fSchristos if (xi < dst->pCompositeClip->extents.x2 && 80642542f5fSchristos yi < dst->pCompositeClip->extents.y2 && 80742542f5fSchristos xi + glyph->info.width > dst->pCompositeClip->extents.x1 && 80842542f5fSchristos yi + glyph->info.height > dst->pCompositeClip->extents.y1) { 80942542f5fSchristos for (i = 0; i < nrect; i++) { 81042542f5fSchristos struct sna_composite_rectangles r; 81142542f5fSchristos int16_t dx, dy; 81242542f5fSchristos int16_t x2, y2; 81342542f5fSchristos 81442542f5fSchristos r.dst.x = xi; 81542542f5fSchristos r.dst.y = yi; 81642542f5fSchristos x2 = xi + glyph->info.width; 81742542f5fSchristos y2 = yi + glyph->info.height; 81842542f5fSchristos dx = dy = 0; 81942542f5fSchristos 82042542f5fSchristos DBG(("%s: glyph=(%d, %d), (%d, %d), clip=(%d, %d), (%d, %d)\n", 82142542f5fSchristos __FUNCTION__, 82242542f5fSchristos r.dst.x, r.dst.y, x2, y2, 82342542f5fSchristos rects[i].x1, rects[i].y1, 82442542f5fSchristos rects[i].x2, rects[i].y2)); 82542542f5fSchristos if (rects[i].y1 >= y2) 82642542f5fSchristos break; 82742542f5fSchristos 82842542f5fSchristos if (r.dst.x < rects[i].x1) 82942542f5fSchristos dx = rects[i].x1 - r.dst.x, r.dst.x = rects[i].x1; 83042542f5fSchristos if (x2 > rects[i].x2) 83142542f5fSchristos x2 = rects[i].x2; 83242542f5fSchristos if (r.dst.y < rects[i].y1) 83342542f5fSchristos dy = rects[i].y1 - r.dst.y, r.dst.y = rects[i].y1; 83442542f5fSchristos if (y2 > rects[i].y2) 83542542f5fSchristos y2 = rects[i].y2; 83642542f5fSchristos 83742542f5fSchristos assert(dx >= 0 && dy >= 0); 83842542f5fSchristos 83942542f5fSchristos if (r.dst.x < x2 && r.dst.y < y2) { 84042542f5fSchristos DBG(("%s: blt=(%d, %d), (%d, %d)\n", 84142542f5fSchristos __FUNCTION__, r.dst.x, r.dst.y, x2, y2)); 84242542f5fSchristos 84342542f5fSchristos r.src.x = r.dst.x + src_x; 84442542f5fSchristos r.src.y = r.dst.y + src_y; 84542542f5fSchristos r.mask.x = dx + p->coordinate.x; 84642542f5fSchristos r.mask.y = dy + p->coordinate.y; 84742542f5fSchristos r.width = x2 - r.dst.x; 84842542f5fSchristos r.height = y2 - r.dst.y; 84942542f5fSchristos tmp.blt(sna, &tmp, &r); 85042542f5fSchristos apply_damage(&tmp, &r); 85142542f5fSchristos } 85242542f5fSchristos } 85342542f5fSchristos } 85442542f5fSchristos 85542542f5fSchristosnext_glyph_N: 85642542f5fSchristos x += glyph->info.xOff; 85742542f5fSchristos y += glyph->info.yOff; 85842542f5fSchristos } 85942542f5fSchristos list++; 86042542f5fSchristos } 86142542f5fSchristos } else while (nlist--) { 86203b705cfSriastradh int n = list->len; 86303b705cfSriastradh x += list->xOff; 86403b705cfSriastradh y += list->yOff; 86503b705cfSriastradh while (n--) { 86603b705cfSriastradh GlyphPtr glyph = *glyphs++; 86742542f5fSchristos struct sna_glyph *p = sna_glyph0(glyph); 86842542f5fSchristos struct sna_composite_rectangles r; 86903b705cfSriastradh 87042542f5fSchristos if (unlikely(p->atlas != glyph_atlas)) { 87103b705cfSriastradh if (unlikely(!glyph_valid(glyph))) 87242542f5fSchristos goto next_glyph_0; 87303b705cfSriastradh 87442542f5fSchristos if (glyph_atlas != NO_ATLAS) { 87503b705cfSriastradh tmp.done(sna, &tmp); 87642542f5fSchristos glyph_atlas = NO_ATLAS; 87703b705cfSriastradh } 87803b705cfSriastradh 87942542f5fSchristos if (unlikely(p->atlas == NULL)) { 88042542f5fSchristos if (!glyph_cache(screen, &sna->render, glyph)) 88142542f5fSchristos goto next_glyph_0; 88242542f5fSchristos } 88303b705cfSriastradh 88403b705cfSriastradh if (!sna->render.composite(sna, 88503b705cfSriastradh op, src, p->atlas, dst, 88603b705cfSriastradh 0, 0, 0, 0, 0, 0, 88703b705cfSriastradh 0, 0, 88842542f5fSchristos COMPOSITE_PARTIAL, &tmp)) 88903b705cfSriastradh return false; 89003b705cfSriastradh 89103b705cfSriastradh glyph_atlas = p->atlas; 89203b705cfSriastradh } 89303b705cfSriastradh 89442542f5fSchristos r.dst.x = x - glyph->info.x; 89542542f5fSchristos r.dst.y = y - glyph->info.y; 89642542f5fSchristos r.src.x = r.dst.x + src_x; 89742542f5fSchristos r.src.y = r.dst.y + src_y; 89842542f5fSchristos r.mask = p->coordinate; 89942542f5fSchristos glyph_copy_size(&r, glyph); 90003b705cfSriastradh 90142542f5fSchristos DBG(("%s: glyph=(%d, %d)x(%d, %d), unclipped\n", 90242542f5fSchristos __FUNCTION__, 90342542f5fSchristos r.dst.x, r.dst.y, 90442542f5fSchristos r.width, r.height)); 90503b705cfSriastradh 90642542f5fSchristos tmp.blt(sna, &tmp, &r); 90742542f5fSchristos apply_damage_clipped_to_dst(&tmp, &r, dst->pDrawable); 90803b705cfSriastradh 90942542f5fSchristosnext_glyph_0: 91003b705cfSriastradh x += glyph->info.xOff; 91103b705cfSriastradh y += glyph->info.yOff; 91203b705cfSriastradh } 91303b705cfSriastradh list++; 91403b705cfSriastradh } 91542542f5fSchristos if (glyph_atlas != NO_ATLAS) 91603b705cfSriastradh tmp.done(sna, &tmp); 91703b705cfSriastradh 91803b705cfSriastradh return true; 91903b705cfSriastradh} 92003b705cfSriastradh 92103b705cfSriastradhstatic bool 92203b705cfSriastradhglyphs_slow(struct sna *sna, 92303b705cfSriastradh CARD8 op, 92403b705cfSriastradh PicturePtr src, 92503b705cfSriastradh PicturePtr dst, 92603b705cfSriastradh INT16 src_x, INT16 src_y, 92703b705cfSriastradh int nlist, GlyphListPtr list, GlyphPtr *glyphs) 92803b705cfSriastradh{ 92903b705cfSriastradh struct sna_composite_op tmp; 93003b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 93103b705cfSriastradh int16_t x, y; 93203b705cfSriastradh 93303b705cfSriastradh if (NO_GLYPHS_SLOW) 93403b705cfSriastradh return false; 93503b705cfSriastradh 93603b705cfSriastradh DBG(("%s(op=%d, src=(%d, %d), nlist=%d, dst=(%d, %d)+(%d, %d))\n", 93703b705cfSriastradh __FUNCTION__, op, src_x, src_y, nlist, 93803b705cfSriastradh list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y)); 93903b705cfSriastradh 94003b705cfSriastradh x = dst->pDrawable->x; 94103b705cfSriastradh y = dst->pDrawable->y; 94203b705cfSriastradh src_x -= list->xOff + x; 94303b705cfSriastradh src_y -= list->yOff + y; 94403b705cfSriastradh 94503b705cfSriastradh while (nlist--) { 94603b705cfSriastradh int n = list->len; 94703b705cfSriastradh x += list->xOff; 94803b705cfSriastradh y += list->yOff; 94903b705cfSriastradh while (n--) { 95003b705cfSriastradh GlyphPtr glyph = *glyphs++; 95103b705cfSriastradh struct sna_glyph *p; 95242542f5fSchristos const BoxRec *rects; 95303b705cfSriastradh BoxRec box; 95403b705cfSriastradh int nrect; 95503b705cfSriastradh 95603b705cfSriastradh box.x1 = x - glyph->info.x; 95703b705cfSriastradh box.y1 = y - glyph->info.y; 95803b705cfSriastradh box.x2 = bound(box.x1, glyph->info.width); 95903b705cfSriastradh box.y2 = bound(box.y1, glyph->info.height); 96003b705cfSriastradh 96103b705cfSriastradh if (!box_intersect(&box, 96203b705cfSriastradh &dst->pCompositeClip->extents)) 96303b705cfSriastradh goto next_glyph; 96403b705cfSriastradh 96503b705cfSriastradh p = sna_glyph(glyph); 96603b705cfSriastradh if (unlikely(p->atlas == NULL)) { 96703b705cfSriastradh if (unlikely(!glyph_valid(glyph))) 96803b705cfSriastradh goto next_glyph; 96903b705cfSriastradh 97042542f5fSchristos if (!glyph_cache(screen, &sna->render, glyph)) 97142542f5fSchristos goto next_glyph; 97203b705cfSriastradh } 97303b705cfSriastradh 97403b705cfSriastradh DBG(("%s: glyph=(%d, %d)x(%d, %d), src=(%d, %d), mask=(%d, %d)\n", 97503b705cfSriastradh __FUNCTION__, 97603b705cfSriastradh x - glyph->info.x, 97703b705cfSriastradh y - glyph->info.y, 97803b705cfSriastradh glyph->info.width, 97903b705cfSriastradh glyph->info.height, 98003b705cfSriastradh src_x + x - glyph->info.x, 98103b705cfSriastradh src_y + y - glyph->info.y, 98203b705cfSriastradh p->coordinate.x, p->coordinate.y)); 98303b705cfSriastradh 98403b705cfSriastradh if (!sna->render.composite(sna, 98503b705cfSriastradh op, src, p->atlas, dst, 98603b705cfSriastradh src_x + x - glyph->info.x, 98703b705cfSriastradh src_y + y - glyph->info.y, 98803b705cfSriastradh p->coordinate.x, p->coordinate.y, 98903b705cfSriastradh x - glyph->info.x, 99003b705cfSriastradh y - glyph->info.y, 99103b705cfSriastradh glyph->info.width, 99203b705cfSriastradh glyph->info.height, 99342542f5fSchristos COMPOSITE_PARTIAL, memset(&tmp, 0, sizeof(tmp)))) 99403b705cfSriastradh return false; 99503b705cfSriastradh 99642542f5fSchristos rects = region_rects(dst->pCompositeClip); 99742542f5fSchristos nrect = region_num_rects(dst->pCompositeClip); 99803b705cfSriastradh do { 99903b705cfSriastradh struct sna_composite_rectangles r; 100003b705cfSriastradh int16_t x2, y2; 100103b705cfSriastradh 100203b705cfSriastradh r.dst.x = x - glyph->info.x; 100303b705cfSriastradh r.dst.y = y - glyph->info.y; 100403b705cfSriastradh x2 = r.dst.x + glyph->info.width; 100503b705cfSriastradh y2 = r.dst.y + glyph->info.height; 100603b705cfSriastradh 100703b705cfSriastradh DBG(("%s: glyph=(%d, %d), (%d, %d), clip=(%d, %d), (%d, %d)\n", 100803b705cfSriastradh __FUNCTION__, 100903b705cfSriastradh r.dst.x, r.dst.y, x2, y2, 101003b705cfSriastradh rects->x1, rects->y1, 101103b705cfSriastradh rects->x2, rects->y2)); 101203b705cfSriastradh if (rects->y1 >= y2) 101303b705cfSriastradh break; 101403b705cfSriastradh 101503b705cfSriastradh if (r.dst.x < rects->x1) 101603b705cfSriastradh r.dst.x = rects->x1; 101703b705cfSriastradh if (x2 > rects->x2) 101803b705cfSriastradh x2 = rects->x2; 101903b705cfSriastradh 102003b705cfSriastradh if (r.dst.y < rects->y1) 102103b705cfSriastradh r.dst.y = rects->y1; 102203b705cfSriastradh if (y2 > rects->y2) 102303b705cfSriastradh y2 = rects->y2; 102403b705cfSriastradh 102503b705cfSriastradh if (r.dst.x < x2 && r.dst.y < y2) { 102603b705cfSriastradh DBG(("%s: blt=(%d, %d), (%d, %d)\n", 102703b705cfSriastradh __FUNCTION__, r.dst.x, r.dst.y, x2, y2)); 102803b705cfSriastradh r.width = x2 - r.dst.x; 102903b705cfSriastradh r.height = y2 - r.dst.y; 103003b705cfSriastradh r.src = r.mask = r .dst; 103103b705cfSriastradh tmp.blt(sna, &tmp, &r); 103203b705cfSriastradh apply_damage(&tmp, &r); 103303b705cfSriastradh } 103403b705cfSriastradh rects++; 103503b705cfSriastradh } while (--nrect); 103603b705cfSriastradh tmp.done(sna, &tmp); 103703b705cfSriastradh 103803b705cfSriastradhnext_glyph: 103903b705cfSriastradh x += glyph->info.xOff; 104003b705cfSriastradh y += glyph->info.yOff; 104103b705cfSriastradh } 104203b705cfSriastradh list++; 104303b705cfSriastradh } 104403b705cfSriastradh 104503b705cfSriastradh return true; 104603b705cfSriastradh} 104703b705cfSriastradh 104803b705cfSriastradhstatic bool 104903b705cfSriastradhclear_pixmap(struct sna *sna, PixmapPtr pixmap) 105003b705cfSriastradh{ 105103b705cfSriastradh struct sna_pixmap *priv = sna_pixmap(pixmap); 105203b705cfSriastradh return sna->render.clear(sna, pixmap, priv->gpu_bo); 105303b705cfSriastradh} 105403b705cfSriastradh 105503b705cfSriastradhstatic bool 105603b705cfSriastradhtoo_large(struct sna *sna, int width, int height) 105703b705cfSriastradh{ 105803b705cfSriastradh return (width > sna->render.max_3d_size || 105903b705cfSriastradh height > sna->render.max_3d_size); 106003b705cfSriastradh} 106103b705cfSriastradh 106203b705cfSriastradhstatic pixman_image_t * 106303b705cfSriastradh__sna_glyph_get_image(GlyphPtr g, ScreenPtr s) 106403b705cfSriastradh{ 106503b705cfSriastradh pixman_image_t *image; 106603b705cfSriastradh PicturePtr p; 106703b705cfSriastradh int dx, dy; 106803b705cfSriastradh 106942542f5fSchristos DBG(("%s: creating image cache for glyph %p (on screen %d)\n", __FUNCTION__, g, s->myNum)); 107042542f5fSchristos 107103b705cfSriastradh p = GetGlyphPicture(g, s); 107203b705cfSriastradh if (unlikely(p == NULL)) 107303b705cfSriastradh return NULL; 107403b705cfSriastradh 107503b705cfSriastradh image = image_from_pict(p, FALSE, &dx, &dy); 107603b705cfSriastradh if (!image) 107703b705cfSriastradh return NULL; 107803b705cfSriastradh 107903b705cfSriastradh assert(dx == 0 && dy == 0); 108003b705cfSriastradh return sna_glyph(g)->image = image; 108103b705cfSriastradh} 108203b705cfSriastradh 108303b705cfSriastradhstatic inline pixman_image_t * 108403b705cfSriastradhsna_glyph_get_image(GlyphPtr g, ScreenPtr s) 108503b705cfSriastradh{ 108603b705cfSriastradh pixman_image_t *image; 108703b705cfSriastradh 108803b705cfSriastradh image = sna_glyph(g)->image; 108903b705cfSriastradh if (image == NULL) 109003b705cfSriastradh image = __sna_glyph_get_image(g, s); 109103b705cfSriastradh 109203b705cfSriastradh return image; 109303b705cfSriastradh} 109403b705cfSriastradh 109542542f5fSchristosstatic inline bool use_small_mask(struct sna *sna, int16_t width, int16_t height, int depth) 109642542f5fSchristos{ 109742542f5fSchristos if (FORCE_SMALL_MASK) 109842542f5fSchristos return FORCE_SMALL_MASK > 0; 109942542f5fSchristos 110042542f5fSchristos if (depth * width * height < 8 * 4096) 110142542f5fSchristos return true; 110242542f5fSchristos 110342542f5fSchristos return too_large(sna, width, height); 110442542f5fSchristos} 110542542f5fSchristos 110603b705cfSriastradhflatten static bool 110703b705cfSriastradhglyphs_via_mask(struct sna *sna, 110803b705cfSriastradh CARD8 op, 110903b705cfSriastradh PicturePtr src, 111003b705cfSriastradh PicturePtr dst, 111103b705cfSriastradh PictFormatPtr format, 111203b705cfSriastradh INT16 src_x, INT16 src_y, 111303b705cfSriastradh int nlist, GlyphListPtr list, GlyphPtr *glyphs) 111403b705cfSriastradh{ 111503b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 111603b705cfSriastradh CARD32 component_alpha; 111703b705cfSriastradh PixmapPtr pixmap; 111842542f5fSchristos PicturePtr mask; 111903b705cfSriastradh int16_t x, y, width, height; 112003b705cfSriastradh int error; 112103b705cfSriastradh bool ret = false; 112203b705cfSriastradh BoxRec box; 112303b705cfSriastradh 112403b705cfSriastradh if (NO_GLYPHS_VIA_MASK) 112503b705cfSriastradh return false; 112603b705cfSriastradh 112703b705cfSriastradh DBG(("%s(op=%d, src=(%d, %d), nlist=%d, dst=(%d, %d)+(%d, %d))\n", 112803b705cfSriastradh __FUNCTION__, op, src_x, src_y, nlist, 112903b705cfSriastradh list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y)); 113003b705cfSriastradh 113103b705cfSriastradh glyph_extents(nlist, list, glyphs, &box); 113203b705cfSriastradh if (box.x2 <= box.x1 || box.y2 <= box.y1) 113303b705cfSriastradh return true; 113403b705cfSriastradh 113542542f5fSchristos DBG(("%s: nlist=%d, count=%d, bounds=((%d, %d), (%d, %d))\n", __FUNCTION__, 113642542f5fSchristos nlist, glyph_count(nlist, list), box.x1, box.y1, box.x2, box.y2)); 113703b705cfSriastradh 113803b705cfSriastradh if (!sna_compute_composite_extents(&box, 113903b705cfSriastradh src, NULL, dst, 114003b705cfSriastradh src_x, src_y, 114103b705cfSriastradh 0, 0, 114203b705cfSriastradh box.x1, box.y1, 114303b705cfSriastradh box.x2 - box.x1, 114403b705cfSriastradh box.y2 - box.y1)) 114503b705cfSriastradh return true; 114603b705cfSriastradh 114703b705cfSriastradh DBG(("%s: extents=((%d, %d), (%d, %d))\n", __FUNCTION__, 114803b705cfSriastradh box.x1, box.y1, box.x2, box.y2)); 114903b705cfSriastradh 115003b705cfSriastradh width = box.x2 - box.x1; 115103b705cfSriastradh height = box.y2 - box.y1; 115203b705cfSriastradh box.x1 -= dst->pDrawable->x; 115303b705cfSriastradh box.y1 -= dst->pDrawable->y; 115403b705cfSriastradh x = -box.x1; 115503b705cfSriastradh y = -box.y1; 115603b705cfSriastradh src_x += box.x1 - list->xOff; 115703b705cfSriastradh src_y += box.y1 - list->yOff; 115803b705cfSriastradh 115903b705cfSriastradh if (format->depth < 8) { 116003b705cfSriastradh format = PictureMatchFormat(screen, 8, PICT_a8); 116103b705cfSriastradh if (!format) 116203b705cfSriastradh return false; 116303b705cfSriastradh } 116403b705cfSriastradh 116503b705cfSriastradh component_alpha = NeedsComponent(format->format); 116642542f5fSchristos if (use_small_mask(sna, width, height, format->depth)) { 116703b705cfSriastradh pixman_image_t *mask_image; 116803b705cfSriastradh 116942542f5fSchristosuse_small_mask: 117003b705cfSriastradh DBG(("%s: small mask [format=%lx, depth=%d, size=%d], rendering glyphs to upload buffer\n", 117103b705cfSriastradh __FUNCTION__, (unsigned long)format->format, 117203b705cfSriastradh format->depth, (uint32_t)width*height*format->depth)); 117303b705cfSriastradh 117403b705cfSriastradh pixmap = sna_pixmap_create_upload(screen, 117503b705cfSriastradh width, height, 117603b705cfSriastradh format->depth, 117703b705cfSriastradh KGEM_BUFFER_WRITE); 117803b705cfSriastradh if (!pixmap) 117903b705cfSriastradh return false; 118003b705cfSriastradh 118103b705cfSriastradh mask_image = 118203b705cfSriastradh pixman_image_create_bits(format->depth << 24 | format->format, 118303b705cfSriastradh width, height, 118403b705cfSriastradh pixmap->devPrivate.ptr, 118503b705cfSriastradh pixmap->devKind); 118603b705cfSriastradh if (mask_image == NULL) 118703b705cfSriastradh goto err_pixmap; 118803b705cfSriastradh 118942542f5fSchristos if (sigtrap_get()) { 119042542f5fSchristos pixman_image_unref(mask_image); 119142542f5fSchristos goto err_pixmap; 119242542f5fSchristos } 119342542f5fSchristos 119403b705cfSriastradh memset(pixmap->devPrivate.ptr, 0, pixmap->devKind*height); 119503b705cfSriastradh#if HAS_PIXMAN_GLYPHS 119642542f5fSchristos if (__global_glyph_cache) { 119703b705cfSriastradh pixman_glyph_t stack_glyphs[N_STACK_GLYPHS]; 119803b705cfSriastradh pixman_glyph_t *pglyphs = stack_glyphs; 119903b705cfSriastradh int count, n; 120003b705cfSriastradh 120103b705cfSriastradh count = 0; 120203b705cfSriastradh for (n = 0; n < nlist; ++n) 120303b705cfSriastradh count += list[n].len; 120403b705cfSriastradh if (count > N_STACK_GLYPHS) { 120503b705cfSriastradh pglyphs = malloc (count * sizeof(pixman_glyph_t)); 120603b705cfSriastradh if (pglyphs == NULL) 120703b705cfSriastradh goto err_pixmap; 120803b705cfSriastradh } 120903b705cfSriastradh 121042542f5fSchristos pixman_glyph_cache_freeze(__global_glyph_cache); 121103b705cfSriastradh count = 0; 121203b705cfSriastradh do { 121303b705cfSriastradh n = list->len; 121403b705cfSriastradh x += list->xOff; 121503b705cfSriastradh y += list->yOff; 121603b705cfSriastradh while (n--) { 121703b705cfSriastradh GlyphPtr g = *glyphs++; 121803b705cfSriastradh const void *ptr; 121903b705cfSriastradh 122003b705cfSriastradh if (!glyph_valid(g)) 122103b705cfSriastradh goto next_pglyph; 122203b705cfSriastradh 122342542f5fSchristos ptr = pixman_glyph_cache_lookup(__global_glyph_cache, g, NULL); 122403b705cfSriastradh if (ptr == NULL) { 122503b705cfSriastradh pixman_image_t *glyph_image; 122603b705cfSriastradh 122703b705cfSriastradh glyph_image = sna_glyph_get_image(g, screen); 122803b705cfSriastradh if (glyph_image == NULL) 122903b705cfSriastradh goto next_pglyph; 123003b705cfSriastradh 123142542f5fSchristos DBG(("%s: inserting glyph %p into pixman cache\n", __FUNCTION__, g)); 123242542f5fSchristos ptr = pixman_glyph_cache_insert(__global_glyph_cache, g, NULL, 123303b705cfSriastradh g->info.x, 123403b705cfSriastradh g->info.y, 123503b705cfSriastradh glyph_image); 123603b705cfSriastradh if (ptr == NULL) 123703b705cfSriastradh goto next_pglyph; 123803b705cfSriastradh } 123903b705cfSriastradh 124042542f5fSchristos assert(sna_glyph_get_image(g, screen) != NULL); 124142542f5fSchristos 124203b705cfSriastradh pglyphs[count].x = x; 124303b705cfSriastradh pglyphs[count].y = y; 124403b705cfSriastradh pglyphs[count].glyph = ptr; 124503b705cfSriastradh count++; 124603b705cfSriastradh 124703b705cfSriastradhnext_pglyph: 124803b705cfSriastradh x += g->info.xOff; 124903b705cfSriastradh y += g->info.yOff; 125003b705cfSriastradh } 125103b705cfSriastradh list++; 125203b705cfSriastradh } while (--nlist); 125303b705cfSriastradh 125403b705cfSriastradh pixman_composite_glyphs_no_mask(PIXMAN_OP_ADD, 125503b705cfSriastradh sna->render.white_image, 125603b705cfSriastradh mask_image, 125703b705cfSriastradh 0, 0, 125803b705cfSriastradh 0, 0, 125942542f5fSchristos __global_glyph_cache, count, pglyphs); 126042542f5fSchristos pixman_glyph_cache_thaw(__global_glyph_cache); 126103b705cfSriastradh if (pglyphs != stack_glyphs) 126203b705cfSriastradh free(pglyphs); 126303b705cfSriastradh } else 126403b705cfSriastradh#endif 126503b705cfSriastradh do { 126603b705cfSriastradh int n = list->len; 126703b705cfSriastradh x += list->xOff; 126803b705cfSriastradh y += list->yOff; 126903b705cfSriastradh while (n--) { 127003b705cfSriastradh GlyphPtr g = *glyphs++; 127103b705cfSriastradh pixman_image_t *glyph_image; 127203b705cfSriastradh int16_t xi, yi; 127303b705cfSriastradh 127403b705cfSriastradh if (!glyph_valid(g)) 127503b705cfSriastradh goto next_image; 127603b705cfSriastradh 127703b705cfSriastradh /* If the mask has been cropped, it is likely 127803b705cfSriastradh * that some of the glyphs fall outside. 127903b705cfSriastradh */ 128003b705cfSriastradh xi = x - g->info.x; 128103b705cfSriastradh yi = y - g->info.y; 128203b705cfSriastradh if (xi >= width || yi >= height) 128303b705cfSriastradh goto next_image; 128403b705cfSriastradh if (xi + g->info.width <= 0 || 128503b705cfSriastradh yi + g->info.height <= 0) 128603b705cfSriastradh goto next_image; 128703b705cfSriastradh 128803b705cfSriastradh glyph_image = 128903b705cfSriastradh sna_glyph_get_image(g, dst->pDrawable->pScreen); 129003b705cfSriastradh if (glyph_image == NULL) 129103b705cfSriastradh goto next_image; 129203b705cfSriastradh 129303b705cfSriastradh DBG(("%s: glyph to mask (%d, %d)x(%d, %d)\n", 129403b705cfSriastradh __FUNCTION__, 129503b705cfSriastradh xi, yi, 129603b705cfSriastradh g->info.width, 129703b705cfSriastradh g->info.height)); 129803b705cfSriastradh 129903b705cfSriastradh if (list->format == format) { 130003b705cfSriastradh assert(pixman_image_get_format(glyph_image) == pixman_image_get_format(mask_image)); 130103b705cfSriastradh pixman_image_composite(PictOpAdd, 130203b705cfSriastradh glyph_image, 130303b705cfSriastradh NULL, 130403b705cfSriastradh mask_image, 130503b705cfSriastradh 0, 0, 130603b705cfSriastradh 0, 0, 130703b705cfSriastradh xi, yi, 130803b705cfSriastradh g->info.width, 130903b705cfSriastradh g->info.height); 131003b705cfSriastradh } else { 131103b705cfSriastradh pixman_image_composite(PictOpAdd, 131203b705cfSriastradh sna->render.white_image, 131303b705cfSriastradh glyph_image, 131403b705cfSriastradh mask_image, 131503b705cfSriastradh 0, 0, 131603b705cfSriastradh 0, 0, 131703b705cfSriastradh xi, yi, 131803b705cfSriastradh g->info.width, 131903b705cfSriastradh g->info.height); 132003b705cfSriastradh } 132103b705cfSriastradh 132203b705cfSriastradhnext_image: 132303b705cfSriastradh x += g->info.xOff; 132403b705cfSriastradh y += g->info.yOff; 132503b705cfSriastradh } 132603b705cfSriastradh list++; 132703b705cfSriastradh } while (--nlist); 132803b705cfSriastradh pixman_image_unref(mask_image); 132903b705cfSriastradh 133042542f5fSchristos sigtrap_put(); 133142542f5fSchristos 133203b705cfSriastradh mask = CreatePicture(0, &pixmap->drawable, 133303b705cfSriastradh format, CPComponentAlpha, 133403b705cfSriastradh &component_alpha, serverClient, &error); 133503b705cfSriastradh if (!mask) 133603b705cfSriastradh goto err_pixmap; 133703b705cfSriastradh 133803b705cfSriastradh ValidatePicture(mask); 133903b705cfSriastradh } else { 134042542f5fSchristos struct sna_composite_op tmp; 134142542f5fSchristos PicturePtr glyph_atlas = NO_ATLAS; 134242542f5fSchristos 134303b705cfSriastradh pixmap = screen->CreatePixmap(screen, 134403b705cfSriastradh width, height, format->depth, 134503b705cfSriastradh SNA_CREATE_SCRATCH); 134603b705cfSriastradh if (!pixmap) 134742542f5fSchristos goto use_small_mask; 134842542f5fSchristos 134942542f5fSchristos assert(__sna_pixmap_get_bo(pixmap)); 135003b705cfSriastradh 135103b705cfSriastradh mask = CreatePicture(0, &pixmap->drawable, 135203b705cfSriastradh format, CPComponentAlpha, 135303b705cfSriastradh &component_alpha, serverClient, &error); 135403b705cfSriastradh if (!mask) 135503b705cfSriastradh goto err_pixmap; 135603b705cfSriastradh 135703b705cfSriastradh ValidatePicture(mask); 135803b705cfSriastradh if (!clear_pixmap(sna, pixmap)) 135903b705cfSriastradh goto err_mask; 136003b705cfSriastradh 136103b705cfSriastradh do { 136203b705cfSriastradh int n = list->len; 136303b705cfSriastradh x += list->xOff; 136403b705cfSriastradh y += list->yOff; 136503b705cfSriastradh while (n--) { 136603b705cfSriastradh GlyphPtr glyph = *glyphs++; 136742542f5fSchristos struct sna_glyph *p = sna_glyph(glyph); 136803b705cfSriastradh struct sna_composite_rectangles r; 136903b705cfSriastradh 137042542f5fSchristos if (unlikely(p->atlas != glyph_atlas)) { 137142542f5fSchristos bool ok; 137242542f5fSchristos 137303b705cfSriastradh if (unlikely(!glyph_valid(glyph))) 137403b705cfSriastradh goto next_glyph; 137503b705cfSriastradh 137642542f5fSchristos if (glyph_atlas != NO_ATLAS) { 137703b705cfSriastradh tmp.done(sna, &tmp); 137842542f5fSchristos glyph_atlas = NO_ATLAS; 137903b705cfSriastradh } 138042542f5fSchristos 138142542f5fSchristos if (unlikely(p->atlas == NULL)) { 138242542f5fSchristos if (!glyph_cache(screen, &sna->render, glyph)) 138303b705cfSriastradh goto next_glyph; 138403b705cfSriastradh } 138503b705cfSriastradh 138603b705cfSriastradh DBG(("%s: atlas format=%08x, mask format=%08x\n", 138703b705cfSriastradh __FUNCTION__, 138803b705cfSriastradh (int)p->atlas->format, 138903b705cfSriastradh (int)(format->depth << 24 | format->format))); 139042542f5fSchristos 139142542f5fSchristos memset(&tmp, 0, sizeof(tmp)); 139203b705cfSriastradh if (p->atlas->format == (format->depth << 24 | format->format)) { 139303b705cfSriastradh ok = sna->render.composite(sna, PictOpAdd, 139403b705cfSriastradh p->atlas, NULL, mask, 139503b705cfSriastradh 0, 0, 0, 0, 0, 0, 139603b705cfSriastradh 0, 0, 139742542f5fSchristos COMPOSITE_PARTIAL, &tmp); 139803b705cfSriastradh } else { 139903b705cfSriastradh ok = sna->render.composite(sna, PictOpAdd, 140003b705cfSriastradh sna->render.white_picture, p->atlas, mask, 140103b705cfSriastradh 0, 0, 0, 0, 0, 0, 140203b705cfSriastradh 0, 0, 140342542f5fSchristos COMPOSITE_PARTIAL, &tmp); 140403b705cfSriastradh } 140503b705cfSriastradh if (!ok) { 140603b705cfSriastradh DBG(("%s: fallback -- can not handle PictOpAdd of glyph onto mask!\n", 140703b705cfSriastradh __FUNCTION__)); 140803b705cfSriastradh goto err_mask; 140903b705cfSriastradh } 141003b705cfSriastradh 141103b705cfSriastradh glyph_atlas = p->atlas; 141203b705cfSriastradh } 141303b705cfSriastradh 141403b705cfSriastradh DBG(("%s: blt glyph origin (%d, %d), offset (%d, %d), src (%d, %d), size (%d, %d)\n", 141503b705cfSriastradh __FUNCTION__, 141603b705cfSriastradh x, y, 141703b705cfSriastradh glyph->info.x, glyph->info.y, 141803b705cfSriastradh p->coordinate.x, p->coordinate.y, 141903b705cfSriastradh glyph->info.width, glyph->info.height)); 142003b705cfSriastradh 142103b705cfSriastradh r.mask = r.src = p->coordinate; 142203b705cfSriastradh r.dst.x = x - glyph->info.x; 142303b705cfSriastradh r.dst.y = y - glyph->info.y; 142403b705cfSriastradh glyph_copy_size(&r, glyph); 142503b705cfSriastradh tmp.blt(sna, &tmp, &r); 142603b705cfSriastradh 142703b705cfSriastradhnext_glyph: 142803b705cfSriastradh x += glyph->info.xOff; 142903b705cfSriastradh y += glyph->info.yOff; 143003b705cfSriastradh } 143103b705cfSriastradh list++; 143203b705cfSriastradh } while (--nlist); 143342542f5fSchristos if (glyph_atlas != NO_ATLAS) 143403b705cfSriastradh tmp.done(sna, &tmp); 143503b705cfSriastradh } 143603b705cfSriastradh 143703b705cfSriastradh sna_composite(op, 143803b705cfSriastradh src, mask, dst, 143903b705cfSriastradh src_x, src_y, 144003b705cfSriastradh 0, 0, 144103b705cfSriastradh box.x1, box.y1, 144203b705cfSriastradh width, height); 144303b705cfSriastradh ret = true; 144403b705cfSriastradherr_mask: 144503b705cfSriastradh FreePicture(mask, 0); 144603b705cfSriastradherr_pixmap: 144703b705cfSriastradh sna_pixmap_destroy(pixmap); 144803b705cfSriastradh return ret; 144903b705cfSriastradh} 145003b705cfSriastradh 145103b705cfSriastradhstatic PictFormatPtr 145203b705cfSriastradhglyphs_format(int nlist, GlyphListPtr list, GlyphPtr * glyphs) 145303b705cfSriastradh{ 145403b705cfSriastradh PictFormatPtr format = list[0].format; 145503b705cfSriastradh int16_t x1, x2, y1, y2; 145603b705cfSriastradh int16_t x, y; 145703b705cfSriastradh BoxRec stack_extents[64], *list_extents = stack_extents; 145803b705cfSriastradh int i, j; 145903b705cfSriastradh 146003b705cfSriastradh if (nlist > ARRAY_SIZE(stack_extents)) { 146103b705cfSriastradh list_extents = malloc(sizeof(BoxRec) * nlist); 146203b705cfSriastradh if (list_extents == NULL) 146303b705cfSriastradh return NULL; 146403b705cfSriastradh } 146503b705cfSriastradh 146642542f5fSchristos x = y = 0; i = 0; 146742542f5fSchristos while (nlist--) { 146803b705cfSriastradh BoxRec extents; 146903b705cfSriastradh bool first = true; 147003b705cfSriastradh int n = list->len; 147103b705cfSriastradh 147203b705cfSriastradh /* Check the intersection of each glyph within the list and 147303b705cfSriastradh * then each list against the previous lists. 147403b705cfSriastradh * 147503b705cfSriastradh * If we overlap then we cannot substitute a mask as the 147603b705cfSriastradh * rendering will be altered. 147703b705cfSriastradh */ 147803b705cfSriastradh if (format->format != list->format->format) { 147942542f5fSchristos DBG(("%s: switching formats from %x to %x\n", 148042542f5fSchristos __FUNCTION__, 148142542f5fSchristos (unsigned)format->format, 148242542f5fSchristos (unsigned)list->format->format)); 148303b705cfSriastradh format = NULL; 148403b705cfSriastradh goto out; 148503b705cfSriastradh } 148603b705cfSriastradh 148703b705cfSriastradh x += list->xOff; 148803b705cfSriastradh y += list->yOff; 148903b705cfSriastradh list++; 149003b705cfSriastradh while (n--) { 149103b705cfSriastradh GlyphPtr glyph = *glyphs++; 149203b705cfSriastradh 149303b705cfSriastradh if (!glyph_valid(glyph)) 149403b705cfSriastradh goto skip_glyph; 149503b705cfSriastradh 149603b705cfSriastradh x1 = x - glyph->info.x; 149703b705cfSriastradh y1 = y - glyph->info.y; 149803b705cfSriastradh x2 = x1 + glyph->info.width; 149903b705cfSriastradh y2 = y1 + glyph->info.height; 150003b705cfSriastradh 150103b705cfSriastradh if (first) { 150203b705cfSriastradh extents.x1 = x1; 150303b705cfSriastradh extents.y1 = y1; 150403b705cfSriastradh extents.x2 = x2; 150503b705cfSriastradh extents.y2 = y2; 150603b705cfSriastradh first = false; 150703b705cfSriastradh } else { 150803b705cfSriastradh /* Potential overlap? 150903b705cfSriastradh * We cheat and ignore the boundary pixels, as 151003b705cfSriastradh * the likelihood of an actual overlap of 151103b705cfSriastradh * inkedk pixels being noticeable in the 151203b705cfSriastradh * boundary is small, yet glyphs frequently 151303b705cfSriastradh * overlap on the boundaries. 151403b705cfSriastradh */ 151542542f5fSchristos if (x1 < extents.x2-GLYPH_TOLERANCE && 151642542f5fSchristos x2 > extents.x1+GLYPH_TOLERANCE && 151742542f5fSchristos y1 < extents.y2-GLYPH_TOLERANCE && 151842542f5fSchristos y2 > extents.y1+GLYPH_TOLERANCE) { 151942542f5fSchristos DBG(("%s: overlapping glyph inside line, current bbox (%d, %d), (%d, %d), glyph (%d, %d), (%d, %d)\n", 152042542f5fSchristos __FUNCTION__, 152142542f5fSchristos extents.x1, extents.y1, extents.x2, extents.y2, 152242542f5fSchristos x1, y1, x2, y2)); 152303b705cfSriastradh format = NULL; 152403b705cfSriastradh goto out; 152503b705cfSriastradh } 152603b705cfSriastradh 152703b705cfSriastradh if (x1 < extents.x1) 152803b705cfSriastradh extents.x1 = x1; 152903b705cfSriastradh if (x2 > extents.x2) 153003b705cfSriastradh extents.x2 = x2; 153103b705cfSriastradh if (y1 < extents.y1) 153203b705cfSriastradh extents.y1 = y1; 153303b705cfSriastradh if (y2 > extents.y2) 153403b705cfSriastradh extents.y2 = y2; 153503b705cfSriastradh } 153603b705cfSriastradhskip_glyph: 153703b705cfSriastradh x += glyph->info.xOff; 153803b705cfSriastradh y += glyph->info.yOff; 153903b705cfSriastradh } 154003b705cfSriastradh 154103b705cfSriastradh /* Incrementally building a region is expensive. We expect 154203b705cfSriastradh * the number of lists to be small, so just keep a list 154303b705cfSriastradh * of the previous boxes and walk those. 154403b705cfSriastradh */ 154542542f5fSchristos if (!first) { 154642542f5fSchristos for (j = 0; j < i; j++) { 154742542f5fSchristos if (extents.x1 < list_extents[j].x2-GLYPH_TOLERANCE && 154842542f5fSchristos extents.x2 > list_extents[j].x1+GLYPH_TOLERANCE && 154942542f5fSchristos extents.y1 < list_extents[j].y2-GLYPH_TOLERANCE && 155042542f5fSchristos extents.y2 > list_extents[j].y1+GLYPH_TOLERANCE) { 155142542f5fSchristos DBG(("%s: overlapping lines, current bbox (%d, %d), (%d, %d), previous line (%d, %d), (%d, %d)\n", 155242542f5fSchristos __FUNCTION__, 155342542f5fSchristos extents.x1, extents.y1, extents.x2, extents.y2, 155442542f5fSchristos list_extents[j].x1, list_extents[j].y1, 155542542f5fSchristos list_extents[j].x2, list_extents[j].y2)); 155642542f5fSchristos format = NULL; 155742542f5fSchristos goto out; 155842542f5fSchristos } 155903b705cfSriastradh } 156042542f5fSchristos list_extents[i++] = extents; 156103b705cfSriastradh } 156203b705cfSriastradh } 156303b705cfSriastradh 156403b705cfSriastradhout: 156503b705cfSriastradh if (list_extents != stack_extents) 156603b705cfSriastradh free(list_extents); 156703b705cfSriastradh return format; 156803b705cfSriastradh} 156903b705cfSriastradh 157003b705cfSriastradhstatic bool can_discard_mask(uint8_t op, PicturePtr src, PictFormatPtr mask, 157103b705cfSriastradh int nlist, GlyphListPtr list, GlyphPtr *glyphs) 157203b705cfSriastradh{ 157303b705cfSriastradh PictFormatPtr g; 157403b705cfSriastradh uint32_t color; 157503b705cfSriastradh 157603b705cfSriastradh if (NO_DISCARD_MASK) 157703b705cfSriastradh return false; 157803b705cfSriastradh 157942542f5fSchristos DBG(("%s: nlist=%d, mask=%08x, depth %d, op=%d (bounded? %d)\n", 158042542f5fSchristos __FUNCTION__, nlist, 158142542f5fSchristos mask ? (unsigned)mask->format : 0, mask ? mask->depth : 0, 158242542f5fSchristos op, op_is_bounded(op))); 158342542f5fSchristos 158403b705cfSriastradh if (nlist == 1 && list->len == 1) 158503b705cfSriastradh return true; 158603b705cfSriastradh 158703b705cfSriastradh if (!op_is_bounded(op)) 158803b705cfSriastradh return false; 158903b705cfSriastradh 159003b705cfSriastradh /* No glyphs overlap and we are not performing a mask conversion. */ 159103b705cfSriastradh g = glyphs_format(nlist, list, glyphs); 159203b705cfSriastradh if (mask == g) 159303b705cfSriastradh return true; 159403b705cfSriastradh 159542542f5fSchristos DBG(("%s: preferred mask format %08x, depth %d\n", 159642542f5fSchristos __FUNCTION__, g ? (unsigned)g->format : 0, g ? g->depth : 0)); 159742542f5fSchristos 159803b705cfSriastradh /* Otherwise if the glyphs are all bitmaps and we have an 159903b705cfSriastradh * opaque source we can also render directly to the dst. 160003b705cfSriastradh */ 160103b705cfSriastradh if (g == NULL) { 160203b705cfSriastradh while (nlist--) { 160303b705cfSriastradh if (list->format->depth != 1) 160403b705cfSriastradh return false; 160503b705cfSriastradh 160603b705cfSriastradh list++; 160703b705cfSriastradh } 160803b705cfSriastradh } else { 160903b705cfSriastradh if (PICT_FORMAT_A(mask->format) >= PICT_FORMAT_A(g->format)) 161003b705cfSriastradh return true; 161103b705cfSriastradh 161203b705cfSriastradh if (g->depth != 1) 161303b705cfSriastradh return false; 161403b705cfSriastradh } 161503b705cfSriastradh 161603b705cfSriastradh if (!sna_picture_is_solid(src, &color)) 161703b705cfSriastradh return false; 161803b705cfSriastradh 161903b705cfSriastradh return color >> 24 == 0xff; 162003b705cfSriastradh} 162103b705cfSriastradh 162203b705cfSriastradhstatic void 162303b705cfSriastradhglyphs_fallback(CARD8 op, 162403b705cfSriastradh PicturePtr src, 162503b705cfSriastradh PicturePtr dst, 162603b705cfSriastradh PictFormatPtr mask_format, 162703b705cfSriastradh int src_x, int src_y, 162803b705cfSriastradh int nlist, GlyphListPtr list, GlyphPtr *glyphs) 162903b705cfSriastradh{ 163003b705cfSriastradh struct sna *sna = to_sna_from_drawable(dst->pDrawable); 163103b705cfSriastradh pixman_image_t *src_image, *dst_image; 163203b705cfSriastradh int src_dx, src_dy; 163303b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 163403b705cfSriastradh RegionRec region; 163503b705cfSriastradh int x, y, n; 163603b705cfSriastradh 163703b705cfSriastradh glyph_extents(nlist, list, glyphs, ®ion.extents); 163842542f5fSchristos DBG(("%s: nlist=%d, count=%d, extents (%d, %d), (%d, %d)\n", __FUNCTION__, 163942542f5fSchristos nlist, glyph_count(nlist, list), 164042542f5fSchristos region.extents.x1, region.extents.y1, 164142542f5fSchristos region.extents.x2, region.extents.y2)); 164242542f5fSchristos 164303b705cfSriastradh if (region.extents.x2 <= region.extents.x1 || 164403b705cfSriastradh region.extents.y2 <= region.extents.y1) 164503b705cfSriastradh return; 164603b705cfSriastradh 164703b705cfSriastradh region.data = NULL; 164803b705cfSriastradh RegionTranslate(®ion, dst->pDrawable->x, dst->pDrawable->y); 164942542f5fSchristos RegionIntersect(®ion, ®ion, dst->pCompositeClip); 165003b705cfSriastradh DBG(("%s: clipped extents (%d, %d), (%d, %d)\n", 165103b705cfSriastradh __FUNCTION__, 165203b705cfSriastradh RegionExtents(®ion)->x1, RegionExtents(®ion)->y1, 165303b705cfSriastradh RegionExtents(®ion)->x2, RegionExtents(®ion)->y2)); 165403b705cfSriastradh if (RegionNil(®ion)) 165503b705cfSriastradh return; 165603b705cfSriastradh 165703b705cfSriastradh if (!sna_drawable_move_region_to_cpu(dst->pDrawable, ®ion, 165803b705cfSriastradh MOVE_READ | MOVE_WRITE)) 165903b705cfSriastradh return; 166003b705cfSriastradh if (dst->alphaMap && 166103b705cfSriastradh !sna_drawable_move_to_cpu(dst->alphaMap->pDrawable, 166203b705cfSriastradh MOVE_READ | MOVE_WRITE)) 166303b705cfSriastradh return; 166403b705cfSriastradh 166503b705cfSriastradh if (src->pDrawable) { 166603b705cfSriastradh if (!sna_drawable_move_to_cpu(src->pDrawable, 166703b705cfSriastradh MOVE_READ)) 166803b705cfSriastradh return; 166903b705cfSriastradh 167003b705cfSriastradh if (src->alphaMap && 167103b705cfSriastradh !sna_drawable_move_to_cpu(src->alphaMap->pDrawable, 167203b705cfSriastradh MOVE_READ)) 167303b705cfSriastradh return; 167403b705cfSriastradh } 167503b705cfSriastradh RegionTranslate(®ion, -dst->pDrawable->x, -dst->pDrawable->y); 167603b705cfSriastradh 167703b705cfSriastradh if (mask_format && 167803b705cfSriastradh can_discard_mask(op, src, mask_format, nlist, list, glyphs)) { 167903b705cfSriastradh DBG(("%s: discarding mask\n", __FUNCTION__)); 168003b705cfSriastradh mask_format = NULL; 168103b705cfSriastradh } 168203b705cfSriastradh 168303b705cfSriastradh#if HAS_PIXMAN_GLYPHS 168442542f5fSchristos if (__global_glyph_cache) { 168503b705cfSriastradh pixman_glyph_t stack_glyphs[N_STACK_GLYPHS]; 168603b705cfSriastradh pixman_glyph_t *pglyphs = stack_glyphs; 168703b705cfSriastradh int dst_x = list->xOff, dst_y = list->yOff; 168803b705cfSriastradh int dst_dx, dst_dy, count; 168903b705cfSriastradh 169042542f5fSchristos pixman_glyph_cache_freeze(__global_glyph_cache); 169103b705cfSriastradh 169203b705cfSriastradh count = 0; 169303b705cfSriastradh for (n = 0; n < nlist; ++n) 169403b705cfSriastradh count += list[n].len; 169503b705cfSriastradh if (count > N_STACK_GLYPHS) { 169642542f5fSchristos pglyphs = malloc(count * sizeof(pixman_glyph_t)); 169703b705cfSriastradh if (pglyphs == NULL) 169803b705cfSriastradh goto out; 169903b705cfSriastradh } 170003b705cfSriastradh 170103b705cfSriastradh count = 0; 170203b705cfSriastradh x = y = 0; 170303b705cfSriastradh while (nlist--) { 170403b705cfSriastradh n = list->len; 170503b705cfSriastradh x += list->xOff; 170603b705cfSriastradh y += list->yOff; 170703b705cfSriastradh while (n--) { 170803b705cfSriastradh GlyphPtr g = *glyphs++; 170903b705cfSriastradh const void *ptr; 171003b705cfSriastradh 171103b705cfSriastradh if (!glyph_valid(g)) 171203b705cfSriastradh goto next; 171303b705cfSriastradh 171442542f5fSchristos ptr = pixman_glyph_cache_lookup(__global_glyph_cache, g, NULL); 171503b705cfSriastradh if (ptr == NULL) { 171603b705cfSriastradh pixman_image_t *glyph_image; 171703b705cfSriastradh 171803b705cfSriastradh glyph_image = sna_glyph_get_image(g, screen); 171903b705cfSriastradh if (glyph_image == NULL) 172003b705cfSriastradh goto next; 172103b705cfSriastradh 172242542f5fSchristos DBG(("%s: inserting glyph %p into pixman cache\n", __FUNCTION__, g)); 172342542f5fSchristos ptr = pixman_glyph_cache_insert(__global_glyph_cache, g, NULL, 172403b705cfSriastradh g->info.x, 172503b705cfSriastradh g->info.y, 172603b705cfSriastradh glyph_image); 172703b705cfSriastradh if (ptr == NULL) 172842542f5fSchristos goto next; 172903b705cfSriastradh } 173003b705cfSriastradh 173142542f5fSchristos assert(sna_glyph_get_image(g, screen) != NULL); 173242542f5fSchristos 173303b705cfSriastradh pglyphs[count].x = x; 173403b705cfSriastradh pglyphs[count].y = y; 173503b705cfSriastradh pglyphs[count].glyph = ptr; 173603b705cfSriastradh count++; 173703b705cfSriastradh 173803b705cfSriastradhnext: 173903b705cfSriastradh x += g->info.xOff; 174003b705cfSriastradh y += g->info.yOff; 174103b705cfSriastradh } 174203b705cfSriastradh list++; 174303b705cfSriastradh } 174403b705cfSriastradh 174542542f5fSchristos if (count == 0) 174642542f5fSchristos goto out; 174742542f5fSchristos 174803b705cfSriastradh src_image = image_from_pict(src, FALSE, &src_dx, &src_dy); 174903b705cfSriastradh if (src_image == NULL) 175003b705cfSriastradh goto out; 175103b705cfSriastradh 175203b705cfSriastradh dst_image = image_from_pict(dst, TRUE, &dst_dx, &dst_dy); 175303b705cfSriastradh if (dst_image == NULL) 175403b705cfSriastradh goto out_free_src; 175503b705cfSriastradh 175642542f5fSchristos if (sigtrap_get() == 0) { 175742542f5fSchristos if (mask_format) { 175842542f5fSchristos pixman_composite_glyphs(op, src_image, dst_image, 175942542f5fSchristos mask_format->format | (mask_format->depth << 24), 176042542f5fSchristos src_x + src_dx + region.extents.x1 - dst_x, 176142542f5fSchristos src_y + src_dy + region.extents.y1 - dst_y, 176242542f5fSchristos region.extents.x1, region.extents.y1, 176342542f5fSchristos region.extents.x1 + dst_dx, region.extents.y1 + dst_dy, 176442542f5fSchristos region.extents.x2 - region.extents.x1, 176542542f5fSchristos region.extents.y2 - region.extents.y1, 176642542f5fSchristos __global_glyph_cache, count, pglyphs); 176742542f5fSchristos } else { 176842542f5fSchristos pixman_composite_glyphs_no_mask(op, src_image, dst_image, 176942542f5fSchristos src_x + src_dx - dst_x, src_y + src_dy - dst_y, 177042542f5fSchristos dst_dx, dst_dy, 177142542f5fSchristos __global_glyph_cache, count, pglyphs); 177242542f5fSchristos } 177342542f5fSchristos sigtrap_put(); 177403b705cfSriastradh } 177503b705cfSriastradh 177603b705cfSriastradh free_pixman_pict(dst, dst_image); 177703b705cfSriastradh 177803b705cfSriastradhout_free_src: 177903b705cfSriastradh free_pixman_pict(src, src_image); 178003b705cfSriastradh 178103b705cfSriastradhout: 178242542f5fSchristos pixman_glyph_cache_thaw(__global_glyph_cache); 178303b705cfSriastradh if (pglyphs != stack_glyphs) 178403b705cfSriastradh free(pglyphs); 178503b705cfSriastradh } else 178603b705cfSriastradh#endif 178703b705cfSriastradh { 178803b705cfSriastradh pixman_image_t *mask_image; 178903b705cfSriastradh 179003b705cfSriastradh dst_image = image_from_pict(dst, TRUE, &x, &y); 179103b705cfSriastradh if (dst_image == NULL) 179203b705cfSriastradh goto cleanup_region; 179303b705cfSriastradh DBG(("%s: dst offset (%d, %d)\n", __FUNCTION__, x, y)); 179403b705cfSriastradh if (x | y) { 179503b705cfSriastradh region.extents.x1 += x; 179603b705cfSriastradh region.extents.x2 += x; 179703b705cfSriastradh region.extents.y1 += y; 179803b705cfSriastradh region.extents.y2 += y; 179903b705cfSriastradh } 180003b705cfSriastradh 180103b705cfSriastradh src_image = image_from_pict(src, FALSE, &src_dx, &src_dy); 180203b705cfSriastradh if (src_image == NULL) 180303b705cfSriastradh goto cleanup_dst; 180403b705cfSriastradh DBG(("%s: src offset (%d, %d)\n", __FUNCTION__, src_dx, src_dy)); 180503b705cfSriastradh src_x += src_dx - list->xOff; 180603b705cfSriastradh src_y += src_dy - list->yOff; 180703b705cfSriastradh 180803b705cfSriastradh if (mask_format) { 180903b705cfSriastradh DBG(("%s: create mask (%d, %d)x(%d,%d) + (%d,%d) + (%d,%d), depth=%d, format=%lx [%lx], ca? %d\n", 181003b705cfSriastradh __FUNCTION__, 181103b705cfSriastradh region.extents.x1, region.extents.y1, 181203b705cfSriastradh region.extents.x2 - region.extents.x1, 181303b705cfSriastradh region.extents.y2 - region.extents.y1, 181403b705cfSriastradh dst->pDrawable->x, dst->pDrawable->y, 181503b705cfSriastradh x, y, 181603b705cfSriastradh mask_format->depth, 181703b705cfSriastradh (long)mask_format->format, 181803b705cfSriastradh (long)(mask_format->depth << 24 | mask_format->format), 181903b705cfSriastradh NeedsComponent(mask_format->format))); 182003b705cfSriastradh mask_image = 182103b705cfSriastradh pixman_image_create_bits(mask_format->depth << 24 | mask_format->format, 182203b705cfSriastradh region.extents.x2 - region.extents.x1, 182303b705cfSriastradh region.extents.y2 - region.extents.y1, 182403b705cfSriastradh NULL, 0); 182503b705cfSriastradh if (mask_image == NULL) 182603b705cfSriastradh goto cleanup_src; 182703b705cfSriastradh if (NeedsComponent(mask_format->format)) 182803b705cfSriastradh pixman_image_set_component_alpha(mask_image, TRUE); 182903b705cfSriastradh 183003b705cfSriastradh x -= region.extents.x1; 183103b705cfSriastradh y -= region.extents.y1; 183203b705cfSriastradh } else { 183303b705cfSriastradh mask_image = dst_image; 183403b705cfSriastradh src_x -= x - dst->pDrawable->x; 183503b705cfSriastradh src_y -= y - dst->pDrawable->y; 183603b705cfSriastradh } 183703b705cfSriastradh 183842542f5fSchristos if (sigtrap_get() == 0) { 183942542f5fSchristos do { 184042542f5fSchristos n = list->len; 184142542f5fSchristos x += list->xOff; 184242542f5fSchristos y += list->yOff; 184342542f5fSchristos while (n--) { 184442542f5fSchristos GlyphPtr g = *glyphs++; 184542542f5fSchristos pixman_image_t *glyph_image; 184603b705cfSriastradh 184742542f5fSchristos if (!glyph_valid(g)) 184842542f5fSchristos goto next_glyph; 184903b705cfSriastradh 185042542f5fSchristos glyph_image = sna_glyph_get_image(g, screen); 185142542f5fSchristos if (glyph_image == NULL) 185242542f5fSchristos goto next_glyph; 185303b705cfSriastradh 185442542f5fSchristos if (mask_format) { 185542542f5fSchristos DBG(("%s: glyph to mask (%d, %d)x(%d, %d)\n", 185642542f5fSchristos __FUNCTION__, 185742542f5fSchristos x - g->info.x, 185842542f5fSchristos y - g->info.y, 185942542f5fSchristos g->info.width, 186042542f5fSchristos g->info.height)); 186142542f5fSchristos 186242542f5fSchristos if (list->format == mask_format) { 186342542f5fSchristos assert(pixman_image_get_format(glyph_image) == pixman_image_get_format(mask_image)); 186442542f5fSchristos pixman_image_composite(PictOpAdd, 186542542f5fSchristos glyph_image, 186642542f5fSchristos NULL, 186742542f5fSchristos mask_image, 186842542f5fSchristos 0, 0, 186942542f5fSchristos 0, 0, 187042542f5fSchristos x - g->info.x, 187142542f5fSchristos y - g->info.y, 187242542f5fSchristos g->info.width, 187342542f5fSchristos g->info.height); 187442542f5fSchristos } else { 187542542f5fSchristos pixman_image_composite(PictOpAdd, 187642542f5fSchristos sna->render.white_image, 187742542f5fSchristos glyph_image, 187842542f5fSchristos mask_image, 187942542f5fSchristos 0, 0, 188042542f5fSchristos 0, 0, 188142542f5fSchristos x - g->info.x, 188242542f5fSchristos y - g->info.y, 188342542f5fSchristos g->info.width, 188442542f5fSchristos g->info.height); 188542542f5fSchristos } 188603b705cfSriastradh } else { 188742542f5fSchristos int xi = x - g->info.x; 188842542f5fSchristos int yi = y - g->info.y; 188942542f5fSchristos 189042542f5fSchristos DBG(("%s: glyph to dst (%d, %d)x(%d, %d)/[(%d, %d)x(%d, %d)], src (%d, %d) [op=%d]\n", 189142542f5fSchristos __FUNCTION__, 189242542f5fSchristos xi, yi, 189342542f5fSchristos g->info.width, g->info.height, 189442542f5fSchristos dst->pDrawable->x, 189542542f5fSchristos dst->pDrawable->y, 189642542f5fSchristos dst->pDrawable->width, 189742542f5fSchristos dst->pDrawable->height, 189842542f5fSchristos src_x + xi, 189942542f5fSchristos src_y + yi, 190042542f5fSchristos op)); 190142542f5fSchristos 190242542f5fSchristos pixman_image_composite(op, 190342542f5fSchristos src_image, 190403b705cfSriastradh glyph_image, 190542542f5fSchristos dst_image, 190642542f5fSchristos src_x + xi, 190742542f5fSchristos src_y + yi, 190803b705cfSriastradh 0, 0, 190942542f5fSchristos xi, yi, 191003b705cfSriastradh g->info.width, 191103b705cfSriastradh g->info.height); 191203b705cfSriastradh } 191303b705cfSriastradhnext_glyph: 191442542f5fSchristos x += g->info.xOff; 191542542f5fSchristos y += g->info.yOff; 191642542f5fSchristos } 191742542f5fSchristos list++; 191842542f5fSchristos } while (--nlist); 191942542f5fSchristos sigtrap_put(); 192042542f5fSchristos } 192103b705cfSriastradh 192203b705cfSriastradh if (mask_format) { 192303b705cfSriastradh DBG(("%s: glyph mask composite src=(%d+%d,%d+%d) dst=(%d, %d)x(%d, %d)\n", 192403b705cfSriastradh __FUNCTION__, 192503b705cfSriastradh src_x, region.extents.x1, src_y, region.extents.y1, 192603b705cfSriastradh region.extents.x1, region.extents.y1, 192703b705cfSriastradh region.extents.x2 - region.extents.x1, 192803b705cfSriastradh region.extents.y2 - region.extents.y1)); 192903b705cfSriastradh pixman_image_composite(op, src_image, mask_image, dst_image, 193003b705cfSriastradh src_x, src_y, 193103b705cfSriastradh 0, 0, 193203b705cfSriastradh region.extents.x1, region.extents.y1, 193303b705cfSriastradh region.extents.x2 - region.extents.x1, 193403b705cfSriastradh region.extents.y2 - region.extents.y1); 193503b705cfSriastradh pixman_image_unref(mask_image); 193603b705cfSriastradh } 193703b705cfSriastradh 193803b705cfSriastradhcleanup_src: 193903b705cfSriastradh free_pixman_pict(src, src_image); 194003b705cfSriastradhcleanup_dst: 194103b705cfSriastradh free_pixman_pict(dst, dst_image); 194203b705cfSriastradh } 194303b705cfSriastradh 194403b705cfSriastradhcleanup_region: 194503b705cfSriastradh RegionUninit(®ion); 194603b705cfSriastradh} 194703b705cfSriastradh 194803b705cfSriastradhvoid 194903b705cfSriastradhsna_glyphs(CARD8 op, 195003b705cfSriastradh PicturePtr src, 195103b705cfSriastradh PicturePtr dst, 195203b705cfSriastradh PictFormatPtr mask, 195303b705cfSriastradh INT16 src_x, INT16 src_y, 195403b705cfSriastradh int nlist, GlyphListPtr list, GlyphPtr *glyphs) 195503b705cfSriastradh{ 195603b705cfSriastradh PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable); 195703b705cfSriastradh struct sna *sna = to_sna_from_pixmap(pixmap); 195803b705cfSriastradh struct sna_pixmap *priv; 195903b705cfSriastradh 196003b705cfSriastradh DBG(("%s(op=%d, nlist=%d, src=(%d, %d))\n", 196103b705cfSriastradh __FUNCTION__, op, nlist, src_x, src_y)); 196203b705cfSriastradh 196342542f5fSchristos if (RegionNil(dst->pCompositeClip)) 196403b705cfSriastradh return; 196503b705cfSriastradh 196603b705cfSriastradh if (FALLBACK) 196703b705cfSriastradh goto fallback; 196803b705cfSriastradh 196903b705cfSriastradh if (!can_render(sna)) { 197003b705cfSriastradh DBG(("%s: wedged\n", __FUNCTION__)); 197103b705cfSriastradh goto fallback; 197203b705cfSriastradh } 197303b705cfSriastradh 197413496ba1Ssnj if (!can_render_to_picture(dst)) { 197513496ba1Ssnj DBG(("%s: fallback -- dst incompatible picture\n", __FUNCTION__)); 197603b705cfSriastradh goto fallback; 197703b705cfSriastradh } 197803b705cfSriastradh 197903b705cfSriastradh priv = sna_pixmap(pixmap); 198003b705cfSriastradh if (priv == NULL) { 198103b705cfSriastradh DBG(("%s: fallback -- destination unattached\n", __FUNCTION__)); 198203b705cfSriastradh goto fallback; 198303b705cfSriastradh } 198403b705cfSriastradh 198542542f5fSchristos if (!is_gpu_dst(priv) && !picture_is_gpu(sna, src, 0)) { 198603b705cfSriastradh DBG(("%s: fallback -- too small (%dx%d)\n", 198703b705cfSriastradh __FUNCTION__, dst->pDrawable->width, dst->pDrawable->height)); 198803b705cfSriastradh goto fallback; 198903b705cfSriastradh } 199003b705cfSriastradh 199103b705cfSriastradh /* Try to discard the mask for non-overlapping glyphs */ 199242542f5fSchristos if (FORCE_GLYPHS_TO_DST || 199342542f5fSchristos mask == NULL || 199403b705cfSriastradh (dst->pCompositeClip->data == NULL && 199503b705cfSriastradh can_discard_mask(op, src, mask, nlist, list, glyphs))) { 199603b705cfSriastradh DBG(("%s: discarding mask\n", __FUNCTION__)); 199703b705cfSriastradh if (can_use_glyph0()) { 199803b705cfSriastradh if (glyphs0_to_dst(sna, op, 199903b705cfSriastradh src, dst, 200003b705cfSriastradh src_x, src_y, 200103b705cfSriastradh nlist, list, glyphs)) 200203b705cfSriastradh return; 200303b705cfSriastradh } else { 200403b705cfSriastradh if (glyphs_to_dst(sna, op, 200503b705cfSriastradh src, dst, 200603b705cfSriastradh src_x, src_y, 200703b705cfSriastradh nlist, list, glyphs)) 200803b705cfSriastradh return; 200903b705cfSriastradh } 201003b705cfSriastradh } 201103b705cfSriastradh 201203b705cfSriastradh /* Otherwise see if we can substitute a mask */ 201303b705cfSriastradh if (!mask) { 201403b705cfSriastradh mask = glyphs_format(nlist, list, glyphs); 201503b705cfSriastradh DBG(("%s: substituting mask? %d\n", __FUNCTION__, mask!=NULL)); 201603b705cfSriastradh } 201703b705cfSriastradh if (mask) { 201803b705cfSriastradh if (glyphs_via_mask(sna, op, 201903b705cfSriastradh src, dst, mask, 202003b705cfSriastradh src_x, src_y, 202103b705cfSriastradh nlist, list, glyphs)) 202203b705cfSriastradh return; 202303b705cfSriastradh } else { 202403b705cfSriastradh if (glyphs_slow(sna, op, 202503b705cfSriastradh src, dst, 202603b705cfSriastradh src_x, src_y, 202703b705cfSriastradh nlist, list, glyphs)) 202803b705cfSriastradh return; 202903b705cfSriastradh } 203003b705cfSriastradh 203103b705cfSriastradhfallback: 203203b705cfSriastradh glyphs_fallback(op, src, dst, mask, src_x, src_y, nlist, list, glyphs); 203303b705cfSriastradh} 203403b705cfSriastradh 203503b705cfSriastradhstatic bool 203603b705cfSriastradhglyphs_via_image(struct sna *sna, 203703b705cfSriastradh CARD8 op, 203803b705cfSriastradh PicturePtr src, 203903b705cfSriastradh PicturePtr dst, 204003b705cfSriastradh PictFormatPtr format, 204103b705cfSriastradh INT16 src_x, INT16 src_y, 204203b705cfSriastradh int nlist, GlyphListPtr list, GlyphPtr *glyphs) 204303b705cfSriastradh{ 204403b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 204503b705cfSriastradh CARD32 component_alpha; 204603b705cfSriastradh PixmapPtr pixmap; 204703b705cfSriastradh PicturePtr mask; 204803b705cfSriastradh int16_t x, y, width, height; 204903b705cfSriastradh pixman_image_t *mask_image; 205003b705cfSriastradh int error; 205103b705cfSriastradh bool ret = false; 205203b705cfSriastradh BoxRec box; 205303b705cfSriastradh 205403b705cfSriastradh if (NO_GLYPHS_VIA_MASK) 205503b705cfSriastradh return false; 205603b705cfSriastradh 205703b705cfSriastradh DBG(("%s(op=%d, src=(%d, %d), nlist=%d, dst=(%d, %d)+(%d, %d))\n", 205803b705cfSriastradh __FUNCTION__, op, src_x, src_y, nlist, 205903b705cfSriastradh list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y)); 206003b705cfSriastradh 206103b705cfSriastradh glyph_extents(nlist, list, glyphs, &box); 206203b705cfSriastradh if (box.x2 <= box.x1 || box.y2 <= box.y1) 206303b705cfSriastradh return true; 206403b705cfSriastradh 206542542f5fSchristos DBG(("%s: nlist=%d, count=%d, bounds=((%d, %d), (%d, %d))\n", __FUNCTION__, 206642542f5fSchristos nlist, glyph_count(nlist, list), box.x1, box.y1, box.x2, box.y2)); 206703b705cfSriastradh 206803b705cfSriastradh if (!sna_compute_composite_extents(&box, 206903b705cfSriastradh src, NULL, dst, 207003b705cfSriastradh src_x, src_y, 207103b705cfSriastradh 0, 0, 207203b705cfSriastradh box.x1, box.y1, 207303b705cfSriastradh box.x2 - box.x1, 207403b705cfSriastradh box.y2 - box.y1)) 207503b705cfSriastradh return true; 207603b705cfSriastradh 207703b705cfSriastradh DBG(("%s: extents=((%d, %d), (%d, %d))\n", __FUNCTION__, 207803b705cfSriastradh box.x1, box.y1, box.x2, box.y2)); 207903b705cfSriastradh 208003b705cfSriastradh width = box.x2 - box.x1; 208103b705cfSriastradh height = box.y2 - box.y1; 208203b705cfSriastradh box.x1 -= dst->pDrawable->x; 208303b705cfSriastradh box.y1 -= dst->pDrawable->y; 208403b705cfSriastradh x = -box.x1; 208503b705cfSriastradh y = -box.y1; 208603b705cfSriastradh src_x += box.x1 - list->xOff; 208703b705cfSriastradh src_y += box.y1 - list->yOff; 208803b705cfSriastradh 208903b705cfSriastradh if (format->depth < 8) { 209003b705cfSriastradh format = PictureMatchFormat(screen, 8, PICT_a8); 209103b705cfSriastradh if (!format) 209203b705cfSriastradh return false; 209303b705cfSriastradh } 209403b705cfSriastradh 209503b705cfSriastradh DBG(("%s: small mask [format=%lx, depth=%d, size=%d], rendering glyphs to upload buffer\n", 209603b705cfSriastradh __FUNCTION__, (unsigned long)format->format, 209703b705cfSriastradh format->depth, (uint32_t)width*height*format->depth)); 209803b705cfSriastradh 209903b705cfSriastradh pixmap = sna_pixmap_create_upload(screen, 210003b705cfSriastradh width, height, 210103b705cfSriastradh format->depth, 210203b705cfSriastradh KGEM_BUFFER_WRITE); 210303b705cfSriastradh if (!pixmap) 210403b705cfSriastradh return false; 210503b705cfSriastradh 210603b705cfSriastradh mask_image = 210703b705cfSriastradh pixman_image_create_bits(format->depth << 24 | format->format, 210803b705cfSriastradh width, height, 210903b705cfSriastradh pixmap->devPrivate.ptr, 211003b705cfSriastradh pixmap->devKind); 211103b705cfSriastradh if (mask_image == NULL) 211203b705cfSriastradh goto err_pixmap; 211303b705cfSriastradh 211442542f5fSchristos if (sigtrap_get()) { 211542542f5fSchristos pixman_image_unref(mask_image); 211642542f5fSchristos goto err_pixmap; 211742542f5fSchristos } 211842542f5fSchristos 211903b705cfSriastradh memset(pixmap->devPrivate.ptr, 0, pixmap->devKind*height); 212003b705cfSriastradh#if HAS_PIXMAN_GLYPHS 212142542f5fSchristos if (__global_glyph_cache) { 212203b705cfSriastradh pixman_glyph_t stack_glyphs[N_STACK_GLYPHS]; 212303b705cfSriastradh pixman_glyph_t *pglyphs = stack_glyphs; 212403b705cfSriastradh int count, n; 212503b705cfSriastradh 212603b705cfSriastradh count = 0; 212703b705cfSriastradh for (n = 0; n < nlist; ++n) 212803b705cfSriastradh count += list[n].len; 212903b705cfSriastradh if (count > N_STACK_GLYPHS) { 213042542f5fSchristos pglyphs = malloc(count * sizeof(pixman_glyph_t)); 213103b705cfSriastradh if (pglyphs == NULL) 213203b705cfSriastradh goto err_pixmap; 213303b705cfSriastradh } 213403b705cfSriastradh 213542542f5fSchristos pixman_glyph_cache_freeze(__global_glyph_cache); 213603b705cfSriastradh count = 0; 213703b705cfSriastradh do { 213803b705cfSriastradh n = list->len; 213903b705cfSriastradh x += list->xOff; 214003b705cfSriastradh y += list->yOff; 214103b705cfSriastradh while (n--) { 214203b705cfSriastradh GlyphPtr g = *glyphs++; 214303b705cfSriastradh const void *ptr; 214403b705cfSriastradh 214503b705cfSriastradh if (!glyph_valid(g)) 214603b705cfSriastradh goto next_pglyph; 214703b705cfSriastradh 214842542f5fSchristos ptr = pixman_glyph_cache_lookup(__global_glyph_cache, g, NULL); 214903b705cfSriastradh if (ptr == NULL) { 215003b705cfSriastradh pixman_image_t *glyph_image; 215103b705cfSriastradh 215203b705cfSriastradh glyph_image = sna_glyph_get_image(g, screen); 215303b705cfSriastradh if (glyph_image == NULL) 215403b705cfSriastradh goto next_pglyph; 215503b705cfSriastradh 215642542f5fSchristos DBG(("%s: inserting glyph %p into pixman cache\n", __FUNCTION__, g)); 215742542f5fSchristos ptr = pixman_glyph_cache_insert(__global_glyph_cache, g, NULL, 215803b705cfSriastradh g->info.x, 215903b705cfSriastradh g->info.y, 216003b705cfSriastradh glyph_image); 216103b705cfSriastradh if (ptr == NULL) 216203b705cfSriastradh goto next_pglyph; 216303b705cfSriastradh } 216403b705cfSriastradh 216542542f5fSchristos assert(sna_glyph_get_image(g, screen) != NULL); 216642542f5fSchristos 216703b705cfSriastradh pglyphs[count].x = x; 216803b705cfSriastradh pglyphs[count].y = y; 216903b705cfSriastradh pglyphs[count].glyph = ptr; 217003b705cfSriastradh count++; 217103b705cfSriastradh 217203b705cfSriastradhnext_pglyph: 217303b705cfSriastradh x += g->info.xOff; 217403b705cfSriastradh y += g->info.yOff; 217503b705cfSriastradh } 217603b705cfSriastradh list++; 217703b705cfSriastradh } while (--nlist); 217803b705cfSriastradh 217903b705cfSriastradh pixman_composite_glyphs_no_mask(PIXMAN_OP_ADD, 218003b705cfSriastradh sna->render.white_image, 218103b705cfSriastradh mask_image, 218203b705cfSriastradh 0, 0, 218303b705cfSriastradh 0, 0, 218442542f5fSchristos __global_glyph_cache, count, pglyphs); 218542542f5fSchristos pixman_glyph_cache_thaw(__global_glyph_cache); 218603b705cfSriastradh if (pglyphs != stack_glyphs) 218703b705cfSriastradh free(pglyphs); 218803b705cfSriastradh } else 218903b705cfSriastradh#endif 219003b705cfSriastradh do { 219103b705cfSriastradh int n = list->len; 219203b705cfSriastradh x += list->xOff; 219303b705cfSriastradh y += list->yOff; 219403b705cfSriastradh while (n--) { 219503b705cfSriastradh GlyphPtr g = *glyphs++; 219603b705cfSriastradh pixman_image_t *glyph_image; 219703b705cfSriastradh int16_t xi, yi; 219803b705cfSriastradh 219903b705cfSriastradh if (!glyph_valid(g)) 220003b705cfSriastradh goto next_image; 220103b705cfSriastradh 220203b705cfSriastradh /* If the mask has been cropped, it is likely 220303b705cfSriastradh * that some of the glyphs fall outside. 220403b705cfSriastradh */ 220503b705cfSriastradh xi = x - g->info.x; 220603b705cfSriastradh yi = y - g->info.y; 220703b705cfSriastradh if (xi >= width || yi >= height) 220803b705cfSriastradh goto next_image; 220903b705cfSriastradh if (xi + g->info.width <= 0 || 221003b705cfSriastradh yi + g->info.height <= 0) 221103b705cfSriastradh goto next_image; 221203b705cfSriastradh 221342542f5fSchristos glyph_image = sna_glyph_get_image(g, screen); 221403b705cfSriastradh if (glyph_image == NULL) 221503b705cfSriastradh goto next_image; 221603b705cfSriastradh 221703b705cfSriastradh DBG(("%s: glyph to mask (%d, %d)x(%d, %d)\n", 221803b705cfSriastradh __FUNCTION__, 221903b705cfSriastradh xi, yi, 222003b705cfSriastradh g->info.width, 222103b705cfSriastradh g->info.height)); 222203b705cfSriastradh 222303b705cfSriastradh if (list->format == format) { 222403b705cfSriastradh assert(pixman_image_get_format(glyph_image) == pixman_image_get_format(mask_image)); 222503b705cfSriastradh pixman_image_composite(PictOpAdd, 222603b705cfSriastradh glyph_image, 222703b705cfSriastradh NULL, 222803b705cfSriastradh mask_image, 222903b705cfSriastradh 0, 0, 223003b705cfSriastradh 0, 0, 223103b705cfSriastradh xi, yi, 223203b705cfSriastradh g->info.width, 223303b705cfSriastradh g->info.height); 223403b705cfSriastradh } else { 223503b705cfSriastradh pixman_image_composite(PictOpAdd, 223603b705cfSriastradh sna->render.white_image, 223703b705cfSriastradh glyph_image, 223803b705cfSriastradh mask_image, 223903b705cfSriastradh 0, 0, 224003b705cfSriastradh 0, 0, 224103b705cfSriastradh xi, yi, 224203b705cfSriastradh g->info.width, 224303b705cfSriastradh g->info.height); 224403b705cfSriastradh } 224503b705cfSriastradh 224603b705cfSriastradhnext_image: 224703b705cfSriastradh x += g->info.xOff; 224803b705cfSriastradh y += g->info.yOff; 224903b705cfSriastradh } 225003b705cfSriastradh list++; 225103b705cfSriastradh } while (--nlist); 225203b705cfSriastradh pixman_image_unref(mask_image); 225342542f5fSchristos sigtrap_put(); 225403b705cfSriastradh 225503b705cfSriastradh component_alpha = NeedsComponent(format->format); 225603b705cfSriastradh 225703b705cfSriastradh mask = CreatePicture(0, &pixmap->drawable, 225803b705cfSriastradh format, CPComponentAlpha, 225903b705cfSriastradh &component_alpha, serverClient, &error); 226003b705cfSriastradh if (!mask) 226103b705cfSriastradh goto err_pixmap; 226203b705cfSriastradh 226303b705cfSriastradh ValidatePicture(mask); 226403b705cfSriastradh 226503b705cfSriastradh sna_composite(op, 226603b705cfSriastradh src, mask, dst, 226703b705cfSriastradh src_x, src_y, 226803b705cfSriastradh 0, 0, 226903b705cfSriastradh box.x1, box.y1, 227003b705cfSriastradh width, height); 227103b705cfSriastradh FreePicture(mask, 0); 227203b705cfSriastradh ret = true; 227303b705cfSriastradherr_pixmap: 227403b705cfSriastradh sna_pixmap_destroy(pixmap); 227503b705cfSriastradh return ret; 227603b705cfSriastradh} 227703b705cfSriastradh 227803b705cfSriastradhvoid 227903b705cfSriastradhsna_glyphs__shared(CARD8 op, 228003b705cfSriastradh PicturePtr src, 228103b705cfSriastradh PicturePtr dst, 228203b705cfSriastradh PictFormatPtr mask, 228303b705cfSriastradh INT16 src_x, INT16 src_y, 228403b705cfSriastradh int nlist, GlyphListPtr list, GlyphPtr *glyphs) 228503b705cfSriastradh{ 228603b705cfSriastradh PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable); 228703b705cfSriastradh struct sna *sna = to_sna_from_pixmap(pixmap); 228803b705cfSriastradh struct sna_pixmap *priv; 228903b705cfSriastradh 229003b705cfSriastradh DBG(("%s(op=%d, nlist=%d, src=(%d, %d))\n", 229103b705cfSriastradh __FUNCTION__, op, nlist, src_x, src_y)); 229203b705cfSriastradh 229342542f5fSchristos if (RegionNil(dst->pCompositeClip)) 229403b705cfSriastradh return; 229503b705cfSriastradh 229603b705cfSriastradh if (FALLBACK) 229703b705cfSriastradh goto fallback; 229803b705cfSriastradh 229903b705cfSriastradh if (!can_render(sna)) { 230003b705cfSriastradh DBG(("%s: wedged\n", __FUNCTION__)); 230103b705cfSriastradh goto fallback; 230203b705cfSriastradh } 230303b705cfSriastradh 230413496ba1Ssnj if (!can_render_to_picture(dst)) { 230513496ba1Ssnj DBG(("%s: fallback -- incompatible picture\n", __FUNCTION__)); 230603b705cfSriastradh goto fallback; 230703b705cfSriastradh } 230803b705cfSriastradh 230903b705cfSriastradh priv = sna_pixmap(pixmap); 231003b705cfSriastradh if (priv == NULL) { 231103b705cfSriastradh DBG(("%s: fallback -- destination unattached\n", __FUNCTION__)); 231203b705cfSriastradh goto fallback; 231303b705cfSriastradh } 231403b705cfSriastradh 231542542f5fSchristos if (!is_gpu_dst(priv) && !picture_is_gpu(sna, src, 0)) { 231603b705cfSriastradh DBG(("%s: fallback -- too small (%dx%d)\n", 231703b705cfSriastradh __FUNCTION__, dst->pDrawable->width, dst->pDrawable->height)); 231803b705cfSriastradh goto fallback; 231903b705cfSriastradh } 232003b705cfSriastradh 232103b705cfSriastradh if (!mask) { 232203b705cfSriastradh mask = glyphs_format(nlist, list, glyphs); 232303b705cfSriastradh DBG(("%s: substituting mask? %d\n", __FUNCTION__, mask!=NULL)); 232403b705cfSriastradh } 232503b705cfSriastradh if (mask) { 232603b705cfSriastradh if (glyphs_via_image(sna, op, 232703b705cfSriastradh src, dst, mask, 232803b705cfSriastradh src_x, src_y, 232903b705cfSriastradh nlist, list, glyphs)) 233003b705cfSriastradh return; 233103b705cfSriastradh } 233203b705cfSriastradh 233303b705cfSriastradhfallback: 233403b705cfSriastradh glyphs_fallback(op, src, dst, mask, src_x, src_y, nlist, list, glyphs); 233503b705cfSriastradh} 233603b705cfSriastradh 233703b705cfSriastradhvoid 233803b705cfSriastradhsna_glyph_unrealize(ScreenPtr screen, GlyphPtr glyph) 233903b705cfSriastradh{ 234003b705cfSriastradh struct sna_glyph *p = sna_glyph(glyph); 234103b705cfSriastradh 234242542f5fSchristos DBG(("%s: screen=%d, glyph=%p (image?=%d, atlas?=%d)\n", 234342542f5fSchristos __FUNCTION__, screen->myNum, glyph, !!p->image, 234442542f5fSchristos p->atlas && p->atlas != GetGlyphPicture(glyph, screen))); 234503b705cfSriastradh 234603b705cfSriastradh if (p->image) { 234703b705cfSriastradh#if HAS_PIXMAN_GLYPHS 234842542f5fSchristos if (__global_glyph_cache) { 234942542f5fSchristos DBG(("%s: removing glyph %p from pixman cache\n", 235042542f5fSchristos __FUNCTION__, glyph)); 235142542f5fSchristos pixman_glyph_cache_remove(__global_glyph_cache, 235203b705cfSriastradh glyph, NULL); 235342542f5fSchristos } 235403b705cfSriastradh#endif 235503b705cfSriastradh pixman_image_unref(p->image); 235603b705cfSriastradh p->image = NULL; 235703b705cfSriastradh } 235803b705cfSriastradh 235903b705cfSriastradh if (p->atlas && p->atlas != GetGlyphPicture(glyph, screen)) { 236003b705cfSriastradh struct sna *sna = to_sna_from_screen(screen); 236103b705cfSriastradh struct sna_glyph_cache *cache = &sna->render.glyph[p->pos&1]; 236203b705cfSriastradh DBG(("%s: releasing glyph pos %d from cache %d\n", 236303b705cfSriastradh __FUNCTION__, p->pos >> 1, p->pos & 1)); 236403b705cfSriastradh assert(cache->glyphs[p->pos >> 1] == p); 236503b705cfSriastradh cache->glyphs[p->pos >> 1] = NULL; 236603b705cfSriastradh p->atlas = NULL; 236703b705cfSriastradh } 236842542f5fSchristos 236942542f5fSchristos#if HAS_PIXMAN_GLYPHS 237042542f5fSchristos assert(__global_glyph_cache == NULL || 237142542f5fSchristos pixman_glyph_cache_lookup(__global_glyph_cache, glyph, NULL) == NULL); 237242542f5fSchristos#endif 237303b705cfSriastradh} 2374