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