sna_glyphs.c revision 03b705cf
1/* 2 * Copyright © 2010 Intel Corporation 3 * Partly based on code Copyright © 2008 Red Hat, Inc. 4 * Partly based on code Copyright © 2000 SuSE, Inc. 5 * 6 * Permission to use, copy, modify, distribute, and sell this software and its 7 * documentation for any purpose is hereby granted without fee, provided that 8 * the above copyright notice appear in all copies and that both that 9 * copyright notice and this permission notice appear in supporting 10 * documentation, and that the name of Intel not be used in advertising or 11 * publicity pertaining to distribution of the software without specific, 12 * written prior permission. Intel makes no representations about the 13 * suitability of this software for any purpose. It is provided "as is" 14 * without express or implied warranty. 15 * 16 * INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INTEL 18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 * 23 * Permission to use, copy, modify, distribute, and sell this software and its 24 * documentation for any purpose is hereby granted without fee, provided that 25 * the above copyright notice appear in all copies and that both that 26 * copyright notice and this permission notice appear in supporting 27 * documentation, and that the name of Red Hat not be used in advertising or 28 * publicity pertaining to distribution of the software without specific, 29 * written prior permission. Red Hat makes no representations about the 30 * suitability of this software for any purpose. It is provided "as is" 31 * without express or implied warranty. 32 * 33 * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat 35 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 36 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 37 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 38 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 39 * 40 * Permission to use, copy, modify, distribute, and sell this software and its 41 * documentation for any purpose is hereby granted without fee, provided that 42 * the above copyright notice appear in all copies and that both that 43 * copyright notice and this permission notice appear in supporting 44 * documentation, and that the name of SuSE not be used in advertising or 45 * publicity pertaining to distribution of the software without specific, 46 * written prior permission. SuSE makes no representations about the 47 * suitability of this software for any purpose. It is provided "as is" 48 * without express or implied warranty. 49 * 50 * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE 52 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 53 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 54 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 55 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 56 * 57 * Author: Chris Wilson <chris@chris-wilson.co.uk> 58 * Based on code by: Keith Packard <keithp@keithp.com> and Owen Taylor <otaylor@fishsoup.net> 59 */ 60 61#ifdef HAVE_CONFIG_H 62#include "config.h" 63#endif 64 65#include "sna.h" 66#include "sna_render.h" 67#include "sna_render_inline.h" 68#include "fb/fbpict.h" 69 70#include <mipict.h> 71 72#define FALLBACK 0 73#define NO_GLYPH_CACHE 0 74#define NO_GLYPHS_TO_DST 0 75#define NO_GLYPHS_VIA_MASK 0 76#define NO_SMALL_MASK 0 77#define NO_GLYPHS_SLOW 0 78#define NO_DISCARD_MASK 0 79 80#define CACHE_PICTURE_SIZE 1024 81#define GLYPH_MIN_SIZE 8 82#define GLYPH_MAX_SIZE 64 83#define GLYPH_CACHE_SIZE (CACHE_PICTURE_SIZE * CACHE_PICTURE_SIZE / (GLYPH_MIN_SIZE * GLYPH_MIN_SIZE)) 84 85#define N_STACK_GLYPHS 512 86 87#define glyph_valid(g) *((uint32_t *)&(g)->info.width) 88#define glyph_copy_size(r, g) *(uint32_t *)&(r)->width = *(uint32_t *)&g->info.width 89 90#if HAS_DEBUG_FULL 91static void _assert_pixmap_contains_box(PixmapPtr pixmap, BoxPtr box, const char *function) 92{ 93 if (box->x1 < 0 || box->y1 < 0 || 94 box->x2 > pixmap->drawable.width || 95 box->y2 > pixmap->drawable.height) 96 { 97 ErrorF("%s: damage box is beyond the pixmap: box=(%d, %d), (%d, %d), pixmap=(%d, %d)\n", 98 __FUNCTION__, 99 box->x1, box->y1, box->x2, box->y2, 100 pixmap->drawable.width, 101 pixmap->drawable.height); 102 assert(0); 103 } 104} 105#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__) 106#else 107#define assert_pixmap_contains_box(p, b) 108#endif 109 110extern DevPrivateKeyRec sna_glyph_key; 111 112static inline struct sna_glyph *sna_glyph(GlyphPtr glyph) 113{ 114 return __get_private(glyph, sna_glyph_key); 115} 116 117static inline struct sna_glyph *sna_glyph0(GlyphPtr glyph) 118{ 119 return (struct sna_glyph *)glyph->devPrivates; 120} 121 122static inline bool can_use_glyph0(void) 123{ 124#if HAS_DEVPRIVATEKEYREC 125 return sna_glyph_key.offset == 0; 126#else 127 return 0; 128#endif 129} 130 131#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) 132 133static bool op_is_bounded(uint8_t op) 134{ 135 switch (op) { 136 case PictOpOver: 137 case PictOpOutReverse: 138 case PictOpAdd: 139 case PictOpXor: 140 return true; 141 default: 142 return false; 143 } 144} 145 146void sna_glyphs_close(struct sna *sna) 147{ 148 struct sna_render *render = &sna->render; 149 unsigned int i; 150 151 DBG(("%s\n", __FUNCTION__)); 152 153 for (i = 0; i < ARRAY_SIZE(render->glyph); i++) { 154 struct sna_glyph_cache *cache = &render->glyph[i]; 155 156 if (cache->picture) 157 FreePicture(cache->picture, 0); 158 159 free(cache->glyphs); 160 } 161 memset(render->glyph, 0, sizeof(render->glyph)); 162 163 if (render->white_image) { 164 pixman_image_unref(render->white_image); 165 render->white_image = NULL; 166 } 167 if (render->white_picture) { 168 FreePicture(render->white_picture, 0); 169 render->white_picture = NULL; 170 } 171#if HAS_PIXMAN_GLYPHS 172 if (render->glyph_cache) { 173 pixman_glyph_cache_destroy(render->glyph_cache); 174 render->glyph_cache = NULL; 175 } 176#endif 177} 178 179/* All caches for a single format share a single pixmap for glyph storage, 180 * allowing mixing glyphs of different sizes without paying a penalty 181 * for switching between source pixmaps. (Note that for a size of font 182 * right at the border between two sizes, we might be switching for almost 183 * every glyph.) 184 * 185 * This function allocates the storage pixmap, and then fills in the 186 * rest of the allocated structures for all caches with the given format. 187 */ 188bool sna_glyphs_create(struct sna *sna) 189{ 190 ScreenPtr screen = sna->scrn->pScreen; 191 pixman_color_t white = { 0xffff, 0xffff, 0xffff, 0xffff }; 192 unsigned int formats[] = { 193 PIXMAN_a8, 194 PIXMAN_a8r8g8b8, 195 }; 196 unsigned int i; 197 int error; 198 199 DBG(("%s\n", __FUNCTION__)); 200 201#if HAS_PIXMAN_GLYPHS 202 sna->render.glyph_cache = pixman_glyph_cache_create(); 203 if (sna->render.glyph_cache == NULL) 204 goto bail; 205#endif 206 207 sna->render.white_image = pixman_image_create_solid_fill(&white); 208 if (sna->render.white_image == NULL) 209 goto bail; 210 211 if (!can_render(sna)) { 212 DBG(("%s: no render acceleration, no render glyph caches\n", 213 __FUNCTION__)); 214 return true; 215 } 216 217 if (xf86IsEntityShared(sna->scrn->entityList[0])) { 218 DBG(("%s: shared GlyphPictures, no render glyph caches\n", 219 __FUNCTION__)); 220 return true; 221 } 222 223 for (i = 0; i < ARRAY_SIZE(formats); i++) { 224 struct sna_glyph_cache *cache = &sna->render.glyph[i]; 225 struct sna_pixmap *priv; 226 PixmapPtr pixmap; 227 PicturePtr picture = NULL; 228 PictFormatPtr pPictFormat; 229 CARD32 component_alpha; 230 int depth = PIXMAN_FORMAT_DEPTH(formats[i]); 231 232 pPictFormat = PictureMatchFormat(screen, depth, formats[i]); 233 if (!pPictFormat) 234 goto bail; 235 236 /* Now allocate the pixmap and picture */ 237 pixmap = screen->CreatePixmap(screen, 238 CACHE_PICTURE_SIZE, 239 CACHE_PICTURE_SIZE, 240 depth, 241 SNA_CREATE_GLYPHS); 242 if (!pixmap) { 243 DBG(("%s: failed to allocate pixmap for Glyph cache\n", 244 __FUNCTION__)); 245 goto bail; 246 } 247 248 priv = sna_pixmap(pixmap); 249 if (priv != NULL) { 250 /* Prevent the cache from ever being paged out */ 251 priv->pinned = PIN_SCANOUT; 252 253 component_alpha = NeedsComponent(pPictFormat->format); 254 picture = CreatePicture(0, &pixmap->drawable, pPictFormat, 255 CPComponentAlpha, &component_alpha, 256 serverClient, &error); 257 } 258 259 screen->DestroyPixmap(pixmap); 260 if (!picture) 261 goto bail; 262 263 ValidatePicture(picture); 264 assert(picture->pDrawable == &pixmap->drawable); 265 266 cache->count = cache->evict = 0; 267 cache->picture = picture; 268 cache->glyphs = calloc(sizeof(struct sna_glyph *), 269 GLYPH_CACHE_SIZE); 270 if (!cache->glyphs) 271 goto bail; 272 273 cache->evict = rand() % GLYPH_CACHE_SIZE; 274 } 275 276 sna->render.white_picture = 277 CreateSolidPicture(0, (xRenderColor *)&white, &error); 278 if (sna->render.white_picture == NULL) 279 goto bail; 280 281 return true; 282 283bail: 284 sna_glyphs_close(sna); 285 return false; 286} 287 288static void 289glyph_cache_upload(struct sna_glyph_cache *cache, 290 GlyphPtr glyph, PicturePtr glyph_picture, 291 int16_t x, int16_t y) 292{ 293 DBG(("%s: upload glyph %p to cache (%d, %d)x(%d, %d)\n", 294 __FUNCTION__, 295 glyph, x, y, 296 glyph_picture->pDrawable->width, 297 glyph_picture->pDrawable->height)); 298 sna_composite(PictOpSrc, 299 glyph_picture, 0, cache->picture, 300 0, 0, 301 0, 0, 302 x, y, 303 glyph_picture->pDrawable->width, 304 glyph_picture->pDrawable->height); 305} 306 307static void 308glyph_extents(int nlist, 309 GlyphListPtr list, 310 GlyphPtr *glyphs, 311 BoxPtr extents) 312{ 313 int16_t x1, x2, y1, y2; 314 int16_t x, y; 315 316 x1 = y1 = MAXSHORT; 317 x2 = y2 = MINSHORT; 318 x = y = 0; 319 while (nlist--) { 320 int n = list->len; 321 x += list->xOff; 322 y += list->yOff; 323 list++; 324 while (n--) { 325 GlyphPtr glyph = *glyphs++; 326 327 if (glyph_valid(glyph)) { 328 int v; 329 330 v = x - glyph->info.x; 331 if (v < x1) 332 x1 = v; 333 v += glyph->info.width; 334 if (v > x2) 335 x2 = v; 336 337 v = y - glyph->info.y; 338 if (v < y1) 339 y1 = v; 340 v += glyph->info.height; 341 if (v > y2) 342 y2 = v; 343 } 344 345 x += glyph->info.xOff; 346 y += glyph->info.yOff; 347 } 348 } 349 350 extents->x1 = x1; 351 extents->x2 = x2; 352 extents->y1 = y1; 353 extents->y2 = y2; 354} 355 356static inline unsigned int 357glyph_size_to_count(int size) 358{ 359 size /= GLYPH_MIN_SIZE; 360 return size * size; 361} 362 363static inline unsigned int 364glyph_count_to_mask(int count) 365{ 366 return ~(count - 1); 367} 368 369static inline unsigned int 370glyph_size_to_mask(int size) 371{ 372 return glyph_count_to_mask(glyph_size_to_count(size)); 373} 374 375static int 376glyph_cache(ScreenPtr screen, 377 struct sna_render *render, 378 GlyphPtr glyph) 379{ 380 PicturePtr glyph_picture; 381 struct sna_glyph_cache *cache; 382 struct sna_glyph *p; 383 int size, mask, pos, s; 384 385 if (NO_GLYPH_CACHE) 386 return false; 387 388 glyph_picture = GetGlyphPicture(glyph, screen); 389 if (unlikely(glyph_picture == NULL)) { 390 glyph->info.width = glyph->info.height = 0; 391 return false; 392 } 393 394 if (glyph->info.width > GLYPH_MAX_SIZE || 395 glyph->info.height > GLYPH_MAX_SIZE) { 396 PixmapPtr pixmap = (PixmapPtr)glyph_picture->pDrawable; 397 assert(glyph_picture->pDrawable->type == DRAWABLE_PIXMAP); 398 if (pixmap->drawable.depth >= 8) { 399 pixmap->usage_hint = 0; 400 sna_pixmap_force_to_gpu(pixmap, MOVE_READ); 401 } 402 return false; 403 } 404 405 for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2) 406 if (glyph->info.width <= size && glyph->info.height <= size) 407 break; 408 409 cache = &render->glyph[PICT_FORMAT_RGB(glyph_picture->format) != 0]; 410 s = glyph_size_to_count(size); 411 mask = glyph_count_to_mask(s); 412 pos = (cache->count + s - 1) & mask; 413 if (pos < GLYPH_CACHE_SIZE) { 414 cache->count = pos + s; 415 } else { 416 p = NULL; 417 for (s = size; s <= GLYPH_MAX_SIZE; s *= 2) { 418 int i = cache->evict & glyph_size_to_mask(s); 419 p = cache->glyphs[i]; 420 if (p == NULL) 421 continue; 422 423 if (p->size >= s) { 424 cache->glyphs[i] = NULL; 425 p->atlas = NULL; 426 pos = i; 427 } else 428 p = NULL; 429 break; 430 } 431 if (p == NULL) { 432 int count = glyph_size_to_count(size); 433 pos = cache->evict & glyph_count_to_mask(count); 434 for (s = 0; s < count; s++) { 435 p = cache->glyphs[pos + s]; 436 if (p != NULL) { 437 p->atlas =NULL; 438 cache->glyphs[pos + s] = NULL; 439 } 440 } 441 } 442 443 /* And pick a new eviction position */ 444 cache->evict = rand() % GLYPH_CACHE_SIZE; 445 } 446 assert(cache->glyphs[pos] == NULL); 447 448 p = sna_glyph(glyph); 449 DBG(("%s(%d): adding glyph to cache %d, pos %d\n", 450 __FUNCTION__, screen->myNum, 451 PICT_FORMAT_RGB(glyph_picture->format) != 0, pos)); 452 cache->glyphs[pos] = p; 453 p->atlas = cache->picture; 454 p->size = size; 455 p->pos = pos << 1 | (PICT_FORMAT_RGB(glyph_picture->format) != 0); 456 s = pos / ((GLYPH_MAX_SIZE / GLYPH_MIN_SIZE) * (GLYPH_MAX_SIZE / GLYPH_MIN_SIZE)); 457 p->coordinate.x = s % (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE) * GLYPH_MAX_SIZE; 458 p->coordinate.y = (s / (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE)) * GLYPH_MAX_SIZE; 459 for (s = GLYPH_MIN_SIZE; s < GLYPH_MAX_SIZE; s *= 2) { 460 if (pos & 1) 461 p->coordinate.x += s; 462 if (pos & 2) 463 p->coordinate.y += s; 464 pos >>= 2; 465 } 466 467 glyph_cache_upload(cache, glyph, glyph_picture, 468 p->coordinate.x, p->coordinate.y); 469 470 return true; 471} 472 473static void apply_damage(struct sna_composite_op *op, 474 const struct sna_composite_rectangles *r) 475{ 476 BoxRec box; 477 478 if (op->damage == NULL) 479 return; 480 481 box.x1 = r->dst.x + op->dst.x; 482 box.y1 = r->dst.y + op->dst.y; 483 box.x2 = box.x1 + r->width; 484 box.y2 = box.y1 + r->height; 485 486 assert_pixmap_contains_box(op->dst.pixmap, &box); 487 sna_damage_add_box(op->damage, &box); 488} 489 490static void apply_damage_clipped_to_dst(struct sna_composite_op *op, 491 const struct sna_composite_rectangles *r, 492 DrawablePtr dst) 493{ 494 BoxRec box; 495 496 if (op->damage == NULL) 497 return; 498 499 box.x1 = r->dst.x + op->dst.x; 500 box.y1 = r->dst.y + op->dst.y; 501 box.x2 = box.x1 + r->width; 502 box.y2 = box.y1 + r->height; 503 504 if (box.x1 < dst->x) 505 box.x1 = dst->x; 506 507 if (box.x2 > op->dst.width) 508 box.x2 = op->dst.width; 509 510 if (box.y1 < dst->y) 511 box.y1 = dst->y; 512 513 if (box.y2 > op->dst.height) 514 box.y2 = op->dst.height; 515 516 assert_pixmap_contains_box(op->dst.pixmap, &box); 517 sna_damage_add_box(op->damage, &box); 518} 519 520flatten static bool 521glyphs_to_dst(struct sna *sna, 522 CARD8 op, 523 PicturePtr src, 524 PicturePtr dst, 525 INT16 src_x, INT16 src_y, 526 int nlist, GlyphListPtr list, GlyphPtr *glyphs) 527{ 528 struct sna_composite_op tmp; 529 ScreenPtr screen = dst->pDrawable->pScreen; 530 PicturePtr glyph_atlas; 531 BoxPtr rects; 532 int nrect; 533 int16_t x, y; 534 535 if (NO_GLYPHS_TO_DST) 536 return false; 537 538 memset(&tmp, 0, sizeof(tmp)); 539 540 DBG(("%s(op=%d, src=(%d, %d), nlist=%d, dst=(%d, %d)+(%d, %d))\n", 541 __FUNCTION__, op, src_x, src_y, nlist, 542 list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y)); 543 544 if (is_clipped(dst->pCompositeClip, dst->pDrawable)) { 545 rects = REGION_RECTS(dst->pCompositeClip); 546 nrect = REGION_NUM_RECTS(dst->pCompositeClip); 547 } else 548 nrect = 0; 549 550 x = dst->pDrawable->x; 551 y = dst->pDrawable->y; 552 src_x -= list->xOff + x; 553 src_y -= list->yOff + y; 554 555 glyph_atlas = NULL; 556 while (nlist--) { 557 int n = list->len; 558 x += list->xOff; 559 y += list->yOff; 560 while (n--) { 561 GlyphPtr glyph = *glyphs++; 562 struct sna_glyph *p; 563 int i; 564 565 p = sna_glyph(glyph); 566 if (unlikely(p->atlas == NULL)) { 567 if (unlikely(!glyph_valid(glyph))) 568 goto next_glyph; 569 570 if (glyph_atlas) { 571 tmp.done(sna, &tmp); 572 glyph_atlas = NULL; 573 } 574 if (!glyph_cache(screen, &sna->render, glyph)) { 575 /* no cache for this glyph */ 576 p->atlas = GetGlyphPicture(glyph, screen); 577 if (unlikely(p->atlas == NULL)) { 578 glyph->info.width = glyph->info.height = 0; 579 goto next_glyph; 580 } 581 p->coordinate.x = p->coordinate.y = 0; 582 } 583 } 584 585 if (p->atlas != glyph_atlas) { 586 if (glyph_atlas) 587 tmp.done(sna, &tmp); 588 589 if (!sna->render.composite(sna, 590 op, src, p->atlas, dst, 591 0, 0, 0, 0, 0, 0, 592 0, 0, 593 &tmp)) 594 return false; 595 596 glyph_atlas = p->atlas; 597 } 598 599 if (nrect) { 600 for (i = 0; i < nrect; i++) { 601 struct sna_composite_rectangles r; 602 int16_t dx, dy; 603 int16_t x2, y2; 604 605 r.dst.x = x - glyph->info.x; 606 r.dst.y = y - glyph->info.y; 607 x2 = r.dst.x + glyph->info.width; 608 y2 = r.dst.y + glyph->info.height; 609 dx = dy = 0; 610 611 DBG(("%s: glyph=(%d, %d), (%d, %d), clip=(%d, %d), (%d, %d)\n", 612 __FUNCTION__, 613 r.dst.x, r.dst.y, x2, y2, 614 rects[i].x1, rects[i].y1, 615 rects[i].x2, rects[i].y2)); 616 if (rects[i].y1 >= y2) 617 break; 618 619 if (r.dst.x < rects[i].x1) 620 dx = rects[i].x1 - r.dst.x, r.dst.x = rects[i].x1; 621 if (x2 > rects[i].x2) 622 x2 = rects[i].x2; 623 if (r.dst.y < rects[i].y1) 624 dy = rects[i].y1 - r.dst.y, r.dst.y = rects[i].y1; 625 if (y2 > rects[i].y2) 626 y2 = rects[i].y2; 627 628 if (r.dst.x < x2 && r.dst.y < y2) { 629 DBG(("%s: blt=(%d, %d), (%d, %d)\n", 630 __FUNCTION__, r.dst.x, r.dst.y, x2, y2)); 631 632 r.src.x = r.dst.x + src_x; 633 r.src.y = r.dst.y + src_y; 634 r.mask.x = dx + p->coordinate.x; 635 r.mask.y = dy + p->coordinate.y; 636 r.width = x2 - r.dst.x; 637 r.height = y2 - r.dst.y; 638 tmp.blt(sna, &tmp, &r); 639 apply_damage(&tmp, &r); 640 } 641 } 642 } else { 643 struct sna_composite_rectangles r; 644 645 r.dst.x = x - glyph->info.x; 646 r.dst.y = y - glyph->info.y; 647 r.src.x = r.dst.x + src_x; 648 r.src.y = r.dst.y + src_y; 649 r.mask = p->coordinate; 650 glyph_copy_size(&r, glyph); 651 652 DBG(("%s: glyph=(%d, %d)x(%d, %d), unclipped\n", 653 __FUNCTION__, 654 r.dst.x, r.dst.y, 655 r.width, r.height)); 656 657 tmp.blt(sna, &tmp, &r); 658 apply_damage_clipped_to_dst(&tmp, &r, dst->pDrawable); 659 } 660 661next_glyph: 662 x += glyph->info.xOff; 663 y += glyph->info.yOff; 664 } 665 list++; 666 } 667 if (glyph_atlas) 668 tmp.done(sna, &tmp); 669 670 return true; 671} 672 673flatten static bool 674glyphs0_to_dst(struct sna *sna, 675 CARD8 op, 676 PicturePtr src, 677 PicturePtr dst, 678 INT16 src_x, INT16 src_y, 679 int nlist, GlyphListPtr list, GlyphPtr *glyphs) 680{ 681 struct sna_composite_op tmp; 682 ScreenPtr screen = dst->pDrawable->pScreen; 683 PicturePtr glyph_atlas; 684 BoxPtr rects; 685 int nrect; 686 int16_t x, y; 687 688 if (NO_GLYPHS_TO_DST) 689 return false; 690 691 memset(&tmp, 0, sizeof(tmp)); 692 693 DBG(("%s(op=%d, src=(%d, %d), nlist=%d, dst=(%d, %d)+(%d, %d))\n", 694 __FUNCTION__, op, src_x, src_y, nlist, 695 list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y)); 696 697 if (is_clipped(dst->pCompositeClip, dst->pDrawable)) { 698 rects = REGION_RECTS(dst->pCompositeClip); 699 nrect = REGION_NUM_RECTS(dst->pCompositeClip); 700 } else 701 nrect = 0; 702 703 x = dst->pDrawable->x; 704 y = dst->pDrawable->y; 705 src_x -= list->xOff + x; 706 src_y -= list->yOff + y; 707 708 glyph_atlas = NULL; 709 while (nlist--) { 710 int n = list->len; 711 x += list->xOff; 712 y += list->yOff; 713 while (n--) { 714 GlyphPtr glyph = *glyphs++; 715 struct sna_glyph *p; 716 int i; 717 718 p = sna_glyph0(glyph); 719 if (unlikely(p->atlas == NULL)) { 720 if (unlikely(!glyph_valid(glyph))) 721 goto next_glyph; 722 723 if (glyph_atlas) { 724 tmp.done(sna, &tmp); 725 glyph_atlas = NULL; 726 } 727 if (!glyph_cache(screen, &sna->render, glyph)) { 728 /* no cache for this glyph */ 729 p->atlas = GetGlyphPicture(glyph, screen); 730 if (unlikely(p->atlas == NULL)) { 731 glyph->info.width = glyph->info.height = 0; 732 goto next_glyph; 733 } 734 p->coordinate.x = p->coordinate.y = 0; 735 } 736 } 737 738 if (p->atlas != glyph_atlas) { 739 if (glyph_atlas) 740 tmp.done(sna, &tmp); 741 742 if (!sna->render.composite(sna, 743 op, src, p->atlas, dst, 744 0, 0, 0, 0, 0, 0, 745 0, 0, 746 &tmp)) 747 return false; 748 749 glyph_atlas = p->atlas; 750 } 751 752 if (nrect) { 753 for (i = 0; i < nrect; i++) { 754 struct sna_composite_rectangles r; 755 int16_t dx, dy; 756 int16_t x2, y2; 757 758 r.dst.x = x - glyph->info.x; 759 r.dst.y = y - glyph->info.y; 760 x2 = r.dst.x + glyph->info.width; 761 y2 = r.dst.y + glyph->info.height; 762 dx = dy = 0; 763 764 DBG(("%s: glyph=(%d, %d), (%d, %d), clip=(%d, %d), (%d, %d)\n", 765 __FUNCTION__, 766 r.dst.x, r.dst.y, x2, y2, 767 rects[i].x1, rects[i].y1, 768 rects[i].x2, rects[i].y2)); 769 if (rects[i].y1 >= y2) 770 break; 771 772 if (r.dst.x < rects[i].x1) 773 dx = rects[i].x1 - r.dst.x, r.dst.x = rects[i].x1; 774 if (x2 > rects[i].x2) 775 x2 = rects[i].x2; 776 if (r.dst.y < rects[i].y1) 777 dy = rects[i].y1 - r.dst.y, r.dst.y = rects[i].y1; 778 if (y2 > rects[i].y2) 779 y2 = rects[i].y2; 780 781 if (r.dst.x < x2 && r.dst.y < y2) { 782 DBG(("%s: blt=(%d, %d), (%d, %d)\n", 783 __FUNCTION__, r.dst.x, r.dst.y, x2, y2)); 784 785 r.src.x = r.dst.x + src_x; 786 r.src.y = r.dst.y + src_y; 787 r.mask.x = dx + p->coordinate.x; 788 r.mask.y = dy + p->coordinate.y; 789 r.width = x2 - r.dst.x; 790 r.height = y2 - r.dst.y; 791 tmp.blt(sna, &tmp, &r); 792 apply_damage(&tmp, &r); 793 } 794 } 795 } else { 796 struct sna_composite_rectangles r; 797 798 r.dst.x = x - glyph->info.x; 799 r.dst.y = y - glyph->info.y; 800 r.src.x = r.dst.x + src_x; 801 r.src.y = r.dst.y + src_y; 802 r.mask = p->coordinate; 803 glyph_copy_size(&r, glyph); 804 805 DBG(("%s: glyph=(%d, %d)x(%d, %d), unclipped\n", 806 __FUNCTION__, 807 r.dst.x, r.dst.y, 808 r.width, r.height)); 809 810 tmp.blt(sna, &tmp, &r); 811 apply_damage_clipped_to_dst(&tmp, &r, dst->pDrawable); 812 } 813 814next_glyph: 815 x += glyph->info.xOff; 816 y += glyph->info.yOff; 817 } 818 list++; 819 } 820 if (glyph_atlas) 821 tmp.done(sna, &tmp); 822 823 return true; 824} 825 826static bool 827glyphs_slow(struct sna *sna, 828 CARD8 op, 829 PicturePtr src, 830 PicturePtr dst, 831 INT16 src_x, INT16 src_y, 832 int nlist, GlyphListPtr list, GlyphPtr *glyphs) 833{ 834 struct sna_composite_op tmp; 835 ScreenPtr screen = dst->pDrawable->pScreen; 836 int16_t x, y; 837 838 if (NO_GLYPHS_SLOW) 839 return false; 840 841 DBG(("%s(op=%d, src=(%d, %d), nlist=%d, dst=(%d, %d)+(%d, %d))\n", 842 __FUNCTION__, op, src_x, src_y, nlist, 843 list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y)); 844 845 x = dst->pDrawable->x; 846 y = dst->pDrawable->y; 847 src_x -= list->xOff + x; 848 src_y -= list->yOff + y; 849 850 while (nlist--) { 851 int n = list->len; 852 x += list->xOff; 853 y += list->yOff; 854 while (n--) { 855 GlyphPtr glyph = *glyphs++; 856 struct sna_glyph *p; 857 BoxPtr rects; 858 BoxRec box; 859 int nrect; 860 861 box.x1 = x - glyph->info.x; 862 box.y1 = y - glyph->info.y; 863 box.x2 = bound(box.x1, glyph->info.width); 864 box.y2 = bound(box.y1, glyph->info.height); 865 866 if (!box_intersect(&box, 867 &dst->pCompositeClip->extents)) 868 goto next_glyph; 869 870 p = sna_glyph(glyph); 871 if (unlikely(p->atlas == NULL)) { 872 if (unlikely(!glyph_valid(glyph))) 873 goto next_glyph; 874 875 if (!glyph_cache(screen, &sna->render, glyph)) { 876 /* no cache for this glyph */ 877 p->atlas = GetGlyphPicture(glyph, screen); 878 if (unlikely(p->atlas == NULL)) { 879 glyph->info.width = glyph->info.height = 0; 880 goto next_glyph; 881 } 882 p->coordinate.x = p->coordinate.y = 0; 883 } 884 } 885 886 DBG(("%s: glyph=(%d, %d)x(%d, %d), src=(%d, %d), mask=(%d, %d)\n", 887 __FUNCTION__, 888 x - glyph->info.x, 889 y - glyph->info.y, 890 glyph->info.width, 891 glyph->info.height, 892 src_x + x - glyph->info.x, 893 src_y + y - glyph->info.y, 894 p->coordinate.x, p->coordinate.y)); 895 896 if (!sna->render.composite(sna, 897 op, src, p->atlas, dst, 898 src_x + x - glyph->info.x, 899 src_y + y - glyph->info.y, 900 p->coordinate.x, p->coordinate.y, 901 x - glyph->info.x, 902 y - glyph->info.y, 903 glyph->info.width, 904 glyph->info.height, 905 memset(&tmp, 0, sizeof(tmp)))) 906 return false; 907 908 rects = REGION_RECTS(dst->pCompositeClip); 909 nrect = REGION_NUM_RECTS(dst->pCompositeClip); 910 do { 911 struct sna_composite_rectangles r; 912 int16_t x2, y2; 913 914 r.dst.x = x - glyph->info.x; 915 r.dst.y = y - glyph->info.y; 916 x2 = r.dst.x + glyph->info.width; 917 y2 = r.dst.y + glyph->info.height; 918 919 DBG(("%s: glyph=(%d, %d), (%d, %d), clip=(%d, %d), (%d, %d)\n", 920 __FUNCTION__, 921 r.dst.x, r.dst.y, x2, y2, 922 rects->x1, rects->y1, 923 rects->x2, rects->y2)); 924 if (rects->y1 >= y2) 925 break; 926 927 if (r.dst.x < rects->x1) 928 r.dst.x = rects->x1; 929 if (x2 > rects->x2) 930 x2 = rects->x2; 931 932 if (r.dst.y < rects->y1) 933 r.dst.y = rects->y1; 934 if (y2 > rects->y2) 935 y2 = rects->y2; 936 937 if (r.dst.x < x2 && r.dst.y < y2) { 938 DBG(("%s: blt=(%d, %d), (%d, %d)\n", 939 __FUNCTION__, r.dst.x, r.dst.y, x2, y2)); 940 r.width = x2 - r.dst.x; 941 r.height = y2 - r.dst.y; 942 r.src = r.mask = r .dst; 943 tmp.blt(sna, &tmp, &r); 944 apply_damage(&tmp, &r); 945 } 946 rects++; 947 } while (--nrect); 948 tmp.done(sna, &tmp); 949 950next_glyph: 951 x += glyph->info.xOff; 952 y += glyph->info.yOff; 953 } 954 list++; 955 } 956 957 return true; 958} 959 960static bool 961clear_pixmap(struct sna *sna, PixmapPtr pixmap) 962{ 963 struct sna_pixmap *priv = sna_pixmap(pixmap); 964 return sna->render.clear(sna, pixmap, priv->gpu_bo); 965} 966 967static bool 968too_large(struct sna *sna, int width, int height) 969{ 970 return (width > sna->render.max_3d_size || 971 height > sna->render.max_3d_size); 972} 973 974static pixman_image_t * 975__sna_glyph_get_image(GlyphPtr g, ScreenPtr s) 976{ 977 pixman_image_t *image; 978 PicturePtr p; 979 int dx, dy; 980 981 p = GetGlyphPicture(g, s); 982 if (unlikely(p == NULL)) 983 return NULL; 984 985 image = image_from_pict(p, FALSE, &dx, &dy); 986 if (!image) 987 return NULL; 988 989 assert(dx == 0 && dy == 0); 990 return sna_glyph(g)->image = image; 991} 992 993static inline pixman_image_t * 994sna_glyph_get_image(GlyphPtr g, ScreenPtr s) 995{ 996 pixman_image_t *image; 997 998 image = sna_glyph(g)->image; 999 if (image == NULL) 1000 image = __sna_glyph_get_image(g, s); 1001 1002 return image; 1003} 1004 1005flatten static bool 1006glyphs_via_mask(struct sna *sna, 1007 CARD8 op, 1008 PicturePtr src, 1009 PicturePtr dst, 1010 PictFormatPtr format, 1011 INT16 src_x, INT16 src_y, 1012 int nlist, GlyphListPtr list, GlyphPtr *glyphs) 1013{ 1014 ScreenPtr screen = dst->pDrawable->pScreen; 1015 struct sna_composite_op tmp; 1016 CARD32 component_alpha; 1017 PixmapPtr pixmap; 1018 PicturePtr glyph_atlas, mask; 1019 int16_t x, y, width, height; 1020 int error; 1021 bool ret = false; 1022 BoxRec box; 1023 1024 if (NO_GLYPHS_VIA_MASK) 1025 return false; 1026 1027 DBG(("%s(op=%d, src=(%d, %d), nlist=%d, dst=(%d, %d)+(%d, %d))\n", 1028 __FUNCTION__, op, src_x, src_y, nlist, 1029 list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y)); 1030 1031 glyph_extents(nlist, list, glyphs, &box); 1032 if (box.x2 <= box.x1 || box.y2 <= box.y1) 1033 return true; 1034 1035 DBG(("%s: bounds=((%d, %d), (%d, %d))\n", __FUNCTION__, 1036 box.x1, box.y1, box.x2, box.y2)); 1037 1038 if (!sna_compute_composite_extents(&box, 1039 src, NULL, dst, 1040 src_x, src_y, 1041 0, 0, 1042 box.x1, box.y1, 1043 box.x2 - box.x1, 1044 box.y2 - box.y1)) 1045 return true; 1046 1047 DBG(("%s: extents=((%d, %d), (%d, %d))\n", __FUNCTION__, 1048 box.x1, box.y1, box.x2, box.y2)); 1049 1050 width = box.x2 - box.x1; 1051 height = box.y2 - box.y1; 1052 box.x1 -= dst->pDrawable->x; 1053 box.y1 -= dst->pDrawable->y; 1054 x = -box.x1; 1055 y = -box.y1; 1056 src_x += box.x1 - list->xOff; 1057 src_y += box.y1 - list->yOff; 1058 1059 if (format->depth < 8) { 1060 format = PictureMatchFormat(screen, 8, PICT_a8); 1061 if (!format) 1062 return false; 1063 } 1064 1065 component_alpha = NeedsComponent(format->format); 1066 if (!NO_SMALL_MASK && 1067 ((uint32_t)width * height * format->depth < 8 * 4096 || 1068 too_large(sna, width, height))) { 1069 pixman_image_t *mask_image; 1070 1071 DBG(("%s: small mask [format=%lx, depth=%d, size=%d], rendering glyphs to upload buffer\n", 1072 __FUNCTION__, (unsigned long)format->format, 1073 format->depth, (uint32_t)width*height*format->depth)); 1074 1075 pixmap = sna_pixmap_create_upload(screen, 1076 width, height, 1077 format->depth, 1078 KGEM_BUFFER_WRITE); 1079 if (!pixmap) 1080 return false; 1081 1082 mask_image = 1083 pixman_image_create_bits(format->depth << 24 | format->format, 1084 width, height, 1085 pixmap->devPrivate.ptr, 1086 pixmap->devKind); 1087 if (mask_image == NULL) 1088 goto err_pixmap; 1089 1090 memset(pixmap->devPrivate.ptr, 0, pixmap->devKind*height); 1091#if HAS_PIXMAN_GLYPHS 1092 if (sna->render.glyph_cache) { 1093 pixman_glyph_t stack_glyphs[N_STACK_GLYPHS]; 1094 pixman_glyph_t *pglyphs = stack_glyphs; 1095 pixman_glyph_cache_t *cache; 1096 int count, n; 1097 1098 cache = sna->render.glyph_cache; 1099 pixman_glyph_cache_freeze(cache); 1100 1101 count = 0; 1102 for (n = 0; n < nlist; ++n) 1103 count += list[n].len; 1104 if (count > N_STACK_GLYPHS) { 1105 pglyphs = malloc (count * sizeof(pixman_glyph_t)); 1106 if (pglyphs == NULL) 1107 goto err_pixmap; 1108 } 1109 1110 count = 0; 1111 do { 1112 n = list->len; 1113 x += list->xOff; 1114 y += list->yOff; 1115 while (n--) { 1116 GlyphPtr g = *glyphs++; 1117 const void *ptr; 1118 1119 if (!glyph_valid(g)) 1120 goto next_pglyph; 1121 1122 ptr = pixman_glyph_cache_lookup(cache, g, NULL); 1123 if (ptr == NULL) { 1124 pixman_image_t *glyph_image; 1125 1126 glyph_image = sna_glyph_get_image(g, screen); 1127 if (glyph_image == NULL) 1128 goto next_pglyph; 1129 1130 ptr = pixman_glyph_cache_insert(cache, g, NULL, 1131 g->info.x, 1132 g->info.y, 1133 glyph_image); 1134 if (ptr == NULL) 1135 goto next_pglyph; 1136 } 1137 1138 pglyphs[count].x = x; 1139 pglyphs[count].y = y; 1140 pglyphs[count].glyph = ptr; 1141 count++; 1142 1143next_pglyph: 1144 x += g->info.xOff; 1145 y += g->info.yOff; 1146 } 1147 list++; 1148 } while (--nlist); 1149 1150 pixman_composite_glyphs_no_mask(PIXMAN_OP_ADD, 1151 sna->render.white_image, 1152 mask_image, 1153 0, 0, 1154 0, 0, 1155 cache, count, pglyphs); 1156 pixman_glyph_cache_thaw(cache); 1157 if (pglyphs != stack_glyphs) 1158 free(pglyphs); 1159 } else 1160#endif 1161 do { 1162 int n = list->len; 1163 x += list->xOff; 1164 y += list->yOff; 1165 while (n--) { 1166 GlyphPtr g = *glyphs++; 1167 pixman_image_t *glyph_image; 1168 int16_t xi, yi; 1169 1170 if (!glyph_valid(g)) 1171 goto next_image; 1172 1173 /* If the mask has been cropped, it is likely 1174 * that some of the glyphs fall outside. 1175 */ 1176 xi = x - g->info.x; 1177 yi = y - g->info.y; 1178 if (xi >= width || yi >= height) 1179 goto next_image; 1180 if (xi + g->info.width <= 0 || 1181 yi + g->info.height <= 0) 1182 goto next_image; 1183 1184 glyph_image = 1185 sna_glyph_get_image(g, dst->pDrawable->pScreen); 1186 if (glyph_image == NULL) 1187 goto next_image; 1188 1189 DBG(("%s: glyph to mask (%d, %d)x(%d, %d)\n", 1190 __FUNCTION__, 1191 xi, yi, 1192 g->info.width, 1193 g->info.height)); 1194 1195 if (list->format == format) { 1196 assert(pixman_image_get_format(glyph_image) == pixman_image_get_format(mask_image)); 1197 pixman_image_composite(PictOpAdd, 1198 glyph_image, 1199 NULL, 1200 mask_image, 1201 0, 0, 1202 0, 0, 1203 xi, yi, 1204 g->info.width, 1205 g->info.height); 1206 } else { 1207 pixman_image_composite(PictOpAdd, 1208 sna->render.white_image, 1209 glyph_image, 1210 mask_image, 1211 0, 0, 1212 0, 0, 1213 xi, yi, 1214 g->info.width, 1215 g->info.height); 1216 } 1217 1218next_image: 1219 x += g->info.xOff; 1220 y += g->info.yOff; 1221 } 1222 list++; 1223 } while (--nlist); 1224 pixman_image_unref(mask_image); 1225 1226 mask = CreatePicture(0, &pixmap->drawable, 1227 format, CPComponentAlpha, 1228 &component_alpha, serverClient, &error); 1229 if (!mask) 1230 goto err_pixmap; 1231 1232 ValidatePicture(mask); 1233 } else { 1234 pixmap = screen->CreatePixmap(screen, 1235 width, height, format->depth, 1236 SNA_CREATE_SCRATCH); 1237 if (!pixmap) 1238 return false; 1239 1240 mask = CreatePicture(0, &pixmap->drawable, 1241 format, CPComponentAlpha, 1242 &component_alpha, serverClient, &error); 1243 if (!mask) 1244 goto err_pixmap; 1245 1246 ValidatePicture(mask); 1247 if (!clear_pixmap(sna, pixmap)) 1248 goto err_mask; 1249 1250 memset(&tmp, 0, sizeof(tmp)); 1251 glyph_atlas = NULL; 1252 do { 1253 int n = list->len; 1254 x += list->xOff; 1255 y += list->yOff; 1256 while (n--) { 1257 GlyphPtr glyph = *glyphs++; 1258 struct sna_glyph *p; 1259 struct sna_composite_rectangles r; 1260 1261 p = sna_glyph(glyph); 1262 if (unlikely(p->atlas == NULL)) { 1263 if (unlikely(!glyph_valid(glyph))) 1264 goto next_glyph; 1265 1266 if (glyph_atlas) { 1267 tmp.done(sna, &tmp); 1268 glyph_atlas = NULL; 1269 } 1270 if (!glyph_cache(screen, &sna->render, glyph)) { 1271 /* no cache for this glyph */ 1272 p->atlas = GetGlyphPicture(glyph, screen); 1273 if (unlikely(p->atlas == NULL)) { 1274 glyph->info.width = glyph->info.height = 0; 1275 goto next_glyph; 1276 } 1277 p->coordinate.x = p->coordinate.y = 0; 1278 } 1279 } 1280 if (p->atlas != glyph_atlas) { 1281 bool ok; 1282 1283 if (glyph_atlas) 1284 tmp.done(sna, &tmp); 1285 1286 DBG(("%s: atlas format=%08x, mask format=%08x\n", 1287 __FUNCTION__, 1288 (int)p->atlas->format, 1289 (int)(format->depth << 24 | format->format))); 1290 if (p->atlas->format == (format->depth << 24 | format->format)) { 1291 ok = sna->render.composite(sna, PictOpAdd, 1292 p->atlas, NULL, mask, 1293 0, 0, 0, 0, 0, 0, 1294 0, 0, 1295 &tmp); 1296 } else { 1297 ok = sna->render.composite(sna, PictOpAdd, 1298 sna->render.white_picture, p->atlas, mask, 1299 0, 0, 0, 0, 0, 0, 1300 0, 0, 1301 &tmp); 1302 } 1303 if (!ok) { 1304 DBG(("%s: fallback -- can not handle PictOpAdd of glyph onto mask!\n", 1305 __FUNCTION__)); 1306 goto err_mask; 1307 } 1308 1309 glyph_atlas = p->atlas; 1310 } 1311 1312 DBG(("%s: blt glyph origin (%d, %d), offset (%d, %d), src (%d, %d), size (%d, %d)\n", 1313 __FUNCTION__, 1314 x, y, 1315 glyph->info.x, glyph->info.y, 1316 p->coordinate.x, p->coordinate.y, 1317 glyph->info.width, glyph->info.height)); 1318 1319 r.mask = r.src = p->coordinate; 1320 r.dst.x = x - glyph->info.x; 1321 r.dst.y = y - glyph->info.y; 1322 glyph_copy_size(&r, glyph); 1323 tmp.blt(sna, &tmp, &r); 1324 1325next_glyph: 1326 x += glyph->info.xOff; 1327 y += glyph->info.yOff; 1328 } 1329 list++; 1330 } while (--nlist); 1331 if (glyph_atlas) 1332 tmp.done(sna, &tmp); 1333 } 1334 1335 sna_composite(op, 1336 src, mask, dst, 1337 src_x, src_y, 1338 0, 0, 1339 box.x1, box.y1, 1340 width, height); 1341 ret = true; 1342err_mask: 1343 FreePicture(mask, 0); 1344err_pixmap: 1345 sna_pixmap_destroy(pixmap); 1346 return ret; 1347} 1348 1349static PictFormatPtr 1350glyphs_format(int nlist, GlyphListPtr list, GlyphPtr * glyphs) 1351{ 1352 PictFormatPtr format = list[0].format; 1353 int16_t x1, x2, y1, y2; 1354 int16_t x, y; 1355 BoxRec stack_extents[64], *list_extents = stack_extents; 1356 int i, j; 1357 1358 if (nlist > ARRAY_SIZE(stack_extents)) { 1359 list_extents = malloc(sizeof(BoxRec) * nlist); 1360 if (list_extents == NULL) 1361 return NULL; 1362 } 1363 1364 x = 0; 1365 y = 0; 1366 for (i = 0; i < nlist; i++) { 1367 BoxRec extents; 1368 bool first = true; 1369 int n = list->len; 1370 1371 /* Check the intersection of each glyph within the list and 1372 * then each list against the previous lists. 1373 * 1374 * If we overlap then we cannot substitute a mask as the 1375 * rendering will be altered. 1376 */ 1377 extents.x1 = 0; 1378 extents.y1 = 0; 1379 extents.x2 = 0; 1380 extents.y2 = 0; 1381 1382 if (format->format != list->format->format) { 1383 format = NULL; 1384 goto out; 1385 } 1386 1387 x += list->xOff; 1388 y += list->yOff; 1389 list++; 1390 while (n--) { 1391 GlyphPtr glyph = *glyphs++; 1392 1393 if (!glyph_valid(glyph)) 1394 goto skip_glyph; 1395 1396 x1 = x - glyph->info.x; 1397 y1 = y - glyph->info.y; 1398 x2 = x1 + glyph->info.width; 1399 y2 = y1 + glyph->info.height; 1400 1401 if (first) { 1402 extents.x1 = x1; 1403 extents.y1 = y1; 1404 extents.x2 = x2; 1405 extents.y2 = y2; 1406 first = false; 1407 } else { 1408 /* Potential overlap? 1409 * We cheat and ignore the boundary pixels, as 1410 * the likelihood of an actual overlap of 1411 * inkedk pixels being noticeable in the 1412 * boundary is small, yet glyphs frequently 1413 * overlap on the boundaries. 1414 */ 1415 if (x1 < extents.x2-1 && x2 > extents.x1+1 && 1416 y1 < extents.y2-1 && y2 > extents.y1+1) { 1417 format = NULL; 1418 goto out; 1419 } 1420 1421 if (x1 < extents.x1) 1422 extents.x1 = x1; 1423 if (x2 > extents.x2) 1424 extents.x2 = x2; 1425 if (y1 < extents.y1) 1426 extents.y1 = y1; 1427 if (y2 > extents.y2) 1428 extents.y2 = y2; 1429 } 1430skip_glyph: 1431 x += glyph->info.xOff; 1432 y += glyph->info.yOff; 1433 } 1434 1435 /* Incrementally building a region is expensive. We expect 1436 * the number of lists to be small, so just keep a list 1437 * of the previous boxes and walk those. 1438 */ 1439 for (j = 0; j < i; j++) { 1440 if (extents.x1 < list_extents[j].x2-1 && 1441 extents.x2 > list_extents[j].x1+1 && 1442 extents.y1 < list_extents[j].y2-1 && 1443 extents.y2 > list_extents[j].y1+1) { 1444 format = NULL; 1445 goto out; 1446 } 1447 } 1448 list_extents[i] = extents; 1449 } 1450 1451out: 1452 if (list_extents != stack_extents) 1453 free(list_extents); 1454 return format; 1455} 1456 1457static bool can_discard_mask(uint8_t op, PicturePtr src, PictFormatPtr mask, 1458 int nlist, GlyphListPtr list, GlyphPtr *glyphs) 1459{ 1460 PictFormatPtr g; 1461 uint32_t color; 1462 1463 if (NO_DISCARD_MASK) 1464 return false; 1465 1466 if (nlist == 1 && list->len == 1) 1467 return true; 1468 1469 if (!op_is_bounded(op)) 1470 return false; 1471 1472 /* No glyphs overlap and we are not performing a mask conversion. */ 1473 g = glyphs_format(nlist, list, glyphs); 1474 if (mask == g) 1475 return true; 1476 1477 /* Otherwise if the glyphs are all bitmaps and we have an 1478 * opaque source we can also render directly to the dst. 1479 */ 1480 if (g == NULL) { 1481 while (nlist--) { 1482 if (list->format->depth != 1) 1483 return false; 1484 1485 list++; 1486 } 1487 } else { 1488 if (PICT_FORMAT_A(mask->format) >= PICT_FORMAT_A(g->format)) 1489 return true; 1490 1491 if (g->depth != 1) 1492 return false; 1493 } 1494 1495 if (!sna_picture_is_solid(src, &color)) 1496 return false; 1497 1498 return color >> 24 == 0xff; 1499} 1500 1501static void 1502glyphs_fallback(CARD8 op, 1503 PicturePtr src, 1504 PicturePtr dst, 1505 PictFormatPtr mask_format, 1506 int src_x, int src_y, 1507 int nlist, GlyphListPtr list, GlyphPtr *glyphs) 1508{ 1509 struct sna *sna = to_sna_from_drawable(dst->pDrawable); 1510 pixman_image_t *src_image, *dst_image; 1511 int src_dx, src_dy; 1512 ScreenPtr screen = dst->pDrawable->pScreen; 1513 RegionRec region; 1514 int x, y, n; 1515 1516 glyph_extents(nlist, list, glyphs, ®ion.extents); 1517 if (region.extents.x2 <= region.extents.x1 || 1518 region.extents.y2 <= region.extents.y1) 1519 return; 1520 1521 DBG(("%s: (%d, %d), (%d, %d)\n", __FUNCTION__, 1522 region.extents.x1, region.extents.y1, 1523 region.extents.x2, region.extents.y2)); 1524 1525 region.data = NULL; 1526 RegionTranslate(®ion, dst->pDrawable->x, dst->pDrawable->y); 1527 if (dst->pCompositeClip) 1528 RegionIntersect(®ion, ®ion, dst->pCompositeClip); 1529 DBG(("%s: clipped extents (%d, %d), (%d, %d)\n", 1530 __FUNCTION__, 1531 RegionExtents(®ion)->x1, RegionExtents(®ion)->y1, 1532 RegionExtents(®ion)->x2, RegionExtents(®ion)->y2)); 1533 if (RegionNil(®ion)) 1534 return; 1535 1536 if (!sna_drawable_move_region_to_cpu(dst->pDrawable, ®ion, 1537 MOVE_READ | MOVE_WRITE)) 1538 return; 1539 if (dst->alphaMap && 1540 !sna_drawable_move_to_cpu(dst->alphaMap->pDrawable, 1541 MOVE_READ | MOVE_WRITE)) 1542 return; 1543 1544 if (src->pDrawable) { 1545 if (!sna_drawable_move_to_cpu(src->pDrawable, 1546 MOVE_READ)) 1547 return; 1548 1549 if (src->alphaMap && 1550 !sna_drawable_move_to_cpu(src->alphaMap->pDrawable, 1551 MOVE_READ)) 1552 return; 1553 } 1554 RegionTranslate(®ion, -dst->pDrawable->x, -dst->pDrawable->y); 1555 1556 if (mask_format && 1557 can_discard_mask(op, src, mask_format, nlist, list, glyphs)) { 1558 DBG(("%s: discarding mask\n", __FUNCTION__)); 1559 mask_format = NULL; 1560 } 1561 1562#if HAS_PIXMAN_GLYPHS 1563 if (sna->render.glyph_cache) { 1564 pixman_glyph_t stack_glyphs[N_STACK_GLYPHS]; 1565 pixman_glyph_t *pglyphs = stack_glyphs; 1566 pixman_glyph_cache_t *cache = sna->render.glyph_cache; 1567 int dst_x = list->xOff, dst_y = list->yOff; 1568 int dst_dx, dst_dy, count; 1569 1570 pixman_glyph_cache_freeze(cache); 1571 1572 count = 0; 1573 for (n = 0; n < nlist; ++n) 1574 count += list[n].len; 1575 if (count > N_STACK_GLYPHS) { 1576 pglyphs = malloc (count * sizeof(pixman_glyph_t)); 1577 if (pglyphs == NULL) 1578 goto out; 1579 } 1580 1581 count = 0; 1582 x = y = 0; 1583 while (nlist--) { 1584 n = list->len; 1585 x += list->xOff; 1586 y += list->yOff; 1587 while (n--) { 1588 GlyphPtr g = *glyphs++; 1589 const void *ptr; 1590 1591 if (!glyph_valid(g)) 1592 goto next; 1593 1594 ptr = pixman_glyph_cache_lookup(cache, g, NULL); 1595 if (ptr == NULL) { 1596 pixman_image_t *glyph_image; 1597 1598 glyph_image = sna_glyph_get_image(g, screen); 1599 if (glyph_image == NULL) 1600 goto next; 1601 1602 ptr = pixman_glyph_cache_insert(cache, g, NULL, 1603 g->info.x, 1604 g->info.y, 1605 glyph_image); 1606 if (ptr == NULL) 1607 goto out; 1608 } 1609 1610 pglyphs[count].x = x; 1611 pglyphs[count].y = y; 1612 pglyphs[count].glyph = ptr; 1613 count++; 1614 1615next: 1616 x += g->info.xOff; 1617 y += g->info.yOff; 1618 } 1619 list++; 1620 } 1621 1622 src_image = image_from_pict(src, FALSE, &src_dx, &src_dy); 1623 if (src_image == NULL) 1624 goto out; 1625 1626 dst_image = image_from_pict(dst, TRUE, &dst_dx, &dst_dy); 1627 if (dst_image == NULL) 1628 goto out_free_src; 1629 1630 if (mask_format) { 1631 pixman_composite_glyphs(op, src_image, dst_image, 1632 mask_format->format | (mask_format->depth << 24), 1633 src_x + src_dx + region.extents.x1 - dst_x, 1634 src_y + src_dy + region.extents.y1 - dst_y, 1635 region.extents.x1, region.extents.y1, 1636 region.extents.x1 + dst_dx, region.extents.y1 + dst_dy, 1637 region.extents.x2 - region.extents.x1, 1638 region.extents.y2 - region.extents.y1, 1639 cache, count, pglyphs); 1640 } else { 1641 pixman_composite_glyphs_no_mask(op, src_image, dst_image, 1642 src_x + src_dx - dst_x, src_y + src_dy - dst_y, 1643 dst_dx, dst_dy, 1644 cache, count, pglyphs); 1645 } 1646 1647 free_pixman_pict(dst, dst_image); 1648 1649out_free_src: 1650 free_pixman_pict(src, src_image); 1651 1652out: 1653 pixman_glyph_cache_thaw(cache); 1654 if (pglyphs != stack_glyphs) 1655 free(pglyphs); 1656 } else 1657#endif 1658 { 1659 pixman_image_t *mask_image; 1660 1661 dst_image = image_from_pict(dst, TRUE, &x, &y); 1662 if (dst_image == NULL) 1663 goto cleanup_region; 1664 DBG(("%s: dst offset (%d, %d)\n", __FUNCTION__, x, y)); 1665 if (x | y) { 1666 region.extents.x1 += x; 1667 region.extents.x2 += x; 1668 region.extents.y1 += y; 1669 region.extents.y2 += y; 1670 } 1671 1672 src_image = image_from_pict(src, FALSE, &src_dx, &src_dy); 1673 if (src_image == NULL) 1674 goto cleanup_dst; 1675 DBG(("%s: src offset (%d, %d)\n", __FUNCTION__, src_dx, src_dy)); 1676 src_x += src_dx - list->xOff; 1677 src_y += src_dy - list->yOff; 1678 1679 if (mask_format) { 1680 DBG(("%s: create mask (%d, %d)x(%d,%d) + (%d,%d) + (%d,%d), depth=%d, format=%lx [%lx], ca? %d\n", 1681 __FUNCTION__, 1682 region.extents.x1, region.extents.y1, 1683 region.extents.x2 - region.extents.x1, 1684 region.extents.y2 - region.extents.y1, 1685 dst->pDrawable->x, dst->pDrawable->y, 1686 x, y, 1687 mask_format->depth, 1688 (long)mask_format->format, 1689 (long)(mask_format->depth << 24 | mask_format->format), 1690 NeedsComponent(mask_format->format))); 1691 mask_image = 1692 pixman_image_create_bits(mask_format->depth << 24 | mask_format->format, 1693 region.extents.x2 - region.extents.x1, 1694 region.extents.y2 - region.extents.y1, 1695 NULL, 0); 1696 if (mask_image == NULL) 1697 goto cleanup_src; 1698 if (NeedsComponent(mask_format->format)) 1699 pixman_image_set_component_alpha(mask_image, TRUE); 1700 1701 x -= region.extents.x1; 1702 y -= region.extents.y1; 1703 } else { 1704 mask_image = dst_image; 1705 src_x -= x - dst->pDrawable->x; 1706 src_y -= y - dst->pDrawable->y; 1707 } 1708 1709 do { 1710 n = list->len; 1711 x += list->xOff; 1712 y += list->yOff; 1713 while (n--) { 1714 GlyphPtr g = *glyphs++; 1715 pixman_image_t *glyph_image; 1716 1717 if (!glyph_valid(g)) 1718 goto next_glyph; 1719 1720 glyph_image = sna_glyph_get_image(g, screen); 1721 if (glyph_image == NULL) 1722 goto next_glyph; 1723 1724 if (mask_format) { 1725 DBG(("%s: glyph to mask (%d, %d)x(%d, %d)\n", 1726 __FUNCTION__, 1727 x - g->info.x, 1728 y - g->info.y, 1729 g->info.width, 1730 g->info.height)); 1731 1732 if (list->format == mask_format) { 1733 assert(pixman_image_get_format(glyph_image) == pixman_image_get_format(mask_image)); 1734 pixman_image_composite(PictOpAdd, 1735 glyph_image, 1736 NULL, 1737 mask_image, 1738 0, 0, 1739 0, 0, 1740 x - g->info.x, 1741 y - g->info.y, 1742 g->info.width, 1743 g->info.height); 1744 } else { 1745 pixman_image_composite(PictOpAdd, 1746 sna->render.white_image, 1747 glyph_image, 1748 mask_image, 1749 0, 0, 1750 0, 0, 1751 x - g->info.x, 1752 y - g->info.y, 1753 g->info.width, 1754 g->info.height); 1755 } 1756 } else { 1757 int xi = x - g->info.x; 1758 int yi = y - g->info.y; 1759 1760 DBG(("%s: glyph to dst (%d, %d)x(%d, %d)/[(%d, %d)x(%d, %d)], src (%d, %d) [op=%d]\n", 1761 __FUNCTION__, 1762 xi, yi, 1763 g->info.width, g->info.height, 1764 dst->pDrawable->x, 1765 dst->pDrawable->y, 1766 dst->pDrawable->width, 1767 dst->pDrawable->height, 1768 src_x + xi, 1769 src_y + yi, 1770 op)); 1771 1772 pixman_image_composite(op, 1773 src_image, 1774 glyph_image, 1775 dst_image, 1776 src_x + xi, 1777 src_y + yi, 1778 0, 0, 1779 xi, yi, 1780 g->info.width, 1781 g->info.height); 1782 } 1783next_glyph: 1784 x += g->info.xOff; 1785 y += g->info.yOff; 1786 } 1787 list++; 1788 } while (--nlist); 1789 1790 if (mask_format) { 1791 DBG(("%s: glyph mask composite src=(%d+%d,%d+%d) dst=(%d, %d)x(%d, %d)\n", 1792 __FUNCTION__, 1793 src_x, region.extents.x1, src_y, region.extents.y1, 1794 region.extents.x1, region.extents.y1, 1795 region.extents.x2 - region.extents.x1, 1796 region.extents.y2 - region.extents.y1)); 1797 pixman_image_composite(op, src_image, mask_image, dst_image, 1798 src_x, src_y, 1799 0, 0, 1800 region.extents.x1, region.extents.y1, 1801 region.extents.x2 - region.extents.x1, 1802 region.extents.y2 - region.extents.y1); 1803 pixman_image_unref(mask_image); 1804 } 1805 1806cleanup_src: 1807 free_pixman_pict(src, src_image); 1808cleanup_dst: 1809 free_pixman_pict(dst, dst_image); 1810 } 1811 1812cleanup_region: 1813 RegionUninit(®ion); 1814} 1815 1816void 1817sna_glyphs(CARD8 op, 1818 PicturePtr src, 1819 PicturePtr dst, 1820 PictFormatPtr mask, 1821 INT16 src_x, INT16 src_y, 1822 int nlist, GlyphListPtr list, GlyphPtr *glyphs) 1823{ 1824 PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable); 1825 struct sna *sna = to_sna_from_pixmap(pixmap); 1826 struct sna_pixmap *priv; 1827 1828 DBG(("%s(op=%d, nlist=%d, src=(%d, %d))\n", 1829 __FUNCTION__, op, nlist, src_x, src_y)); 1830 1831 if (REGION_NUM_RECTS(dst->pCompositeClip) == 0) 1832 return; 1833 1834 if (FALLBACK) 1835 goto fallback; 1836 1837 if (!can_render(sna)) { 1838 DBG(("%s: wedged\n", __FUNCTION__)); 1839 goto fallback; 1840 } 1841 1842 if (dst->alphaMap) { 1843 DBG(("%s: fallback -- dst alpha map\n", __FUNCTION__)); 1844 goto fallback; 1845 } 1846 1847 priv = sna_pixmap(pixmap); 1848 if (priv == NULL) { 1849 DBG(("%s: fallback -- destination unattached\n", __FUNCTION__)); 1850 goto fallback; 1851 } 1852 1853 if ((too_small(priv) || DAMAGE_IS_ALL(priv->cpu_damage)) && 1854 !picture_is_gpu(sna, src)) { 1855 DBG(("%s: fallback -- too small (%dx%d)\n", 1856 __FUNCTION__, dst->pDrawable->width, dst->pDrawable->height)); 1857 goto fallback; 1858 } 1859 1860 /* Try to discard the mask for non-overlapping glyphs */ 1861 if (mask == NULL || 1862 (dst->pCompositeClip->data == NULL && 1863 can_discard_mask(op, src, mask, nlist, list, glyphs))) { 1864 DBG(("%s: discarding mask\n", __FUNCTION__)); 1865 if (can_use_glyph0()) { 1866 if (glyphs0_to_dst(sna, op, 1867 src, dst, 1868 src_x, src_y, 1869 nlist, list, glyphs)) 1870 return; 1871 } else { 1872 if (glyphs_to_dst(sna, op, 1873 src, dst, 1874 src_x, src_y, 1875 nlist, list, glyphs)) 1876 return; 1877 } 1878 } 1879 1880 /* Otherwise see if we can substitute a mask */ 1881 if (!mask) { 1882 mask = glyphs_format(nlist, list, glyphs); 1883 DBG(("%s: substituting mask? %d\n", __FUNCTION__, mask!=NULL)); 1884 } 1885 if (mask) { 1886 if (glyphs_via_mask(sna, op, 1887 src, dst, mask, 1888 src_x, src_y, 1889 nlist, list, glyphs)) 1890 return; 1891 } else { 1892 if (glyphs_slow(sna, op, 1893 src, dst, 1894 src_x, src_y, 1895 nlist, list, glyphs)) 1896 return; 1897 } 1898 1899fallback: 1900 glyphs_fallback(op, src, dst, mask, src_x, src_y, nlist, list, glyphs); 1901} 1902 1903static bool 1904glyphs_via_image(struct sna *sna, 1905 CARD8 op, 1906 PicturePtr src, 1907 PicturePtr dst, 1908 PictFormatPtr format, 1909 INT16 src_x, INT16 src_y, 1910 int nlist, GlyphListPtr list, GlyphPtr *glyphs) 1911{ 1912 ScreenPtr screen = dst->pDrawable->pScreen; 1913 CARD32 component_alpha; 1914 PixmapPtr pixmap; 1915 PicturePtr mask; 1916 int16_t x, y, width, height; 1917 pixman_image_t *mask_image; 1918 int error; 1919 bool ret = false; 1920 BoxRec box; 1921 1922 if (NO_GLYPHS_VIA_MASK) 1923 return false; 1924 1925 DBG(("%s(op=%d, src=(%d, %d), nlist=%d, dst=(%d, %d)+(%d, %d))\n", 1926 __FUNCTION__, op, src_x, src_y, nlist, 1927 list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y)); 1928 1929 glyph_extents(nlist, list, glyphs, &box); 1930 if (box.x2 <= box.x1 || box.y2 <= box.y1) 1931 return true; 1932 1933 DBG(("%s: bounds=((%d, %d), (%d, %d))\n", __FUNCTION__, 1934 box.x1, box.y1, box.x2, box.y2)); 1935 1936 if (!sna_compute_composite_extents(&box, 1937 src, NULL, dst, 1938 src_x, src_y, 1939 0, 0, 1940 box.x1, box.y1, 1941 box.x2 - box.x1, 1942 box.y2 - box.y1)) 1943 return true; 1944 1945 DBG(("%s: extents=((%d, %d), (%d, %d))\n", __FUNCTION__, 1946 box.x1, box.y1, box.x2, box.y2)); 1947 1948 width = box.x2 - box.x1; 1949 height = box.y2 - box.y1; 1950 box.x1 -= dst->pDrawable->x; 1951 box.y1 -= dst->pDrawable->y; 1952 x = -box.x1; 1953 y = -box.y1; 1954 src_x += box.x1 - list->xOff; 1955 src_y += box.y1 - list->yOff; 1956 1957 if (format->depth < 8) { 1958 format = PictureMatchFormat(screen, 8, PICT_a8); 1959 if (!format) 1960 return false; 1961 } 1962 1963 DBG(("%s: small mask [format=%lx, depth=%d, size=%d], rendering glyphs to upload buffer\n", 1964 __FUNCTION__, (unsigned long)format->format, 1965 format->depth, (uint32_t)width*height*format->depth)); 1966 1967 pixmap = sna_pixmap_create_upload(screen, 1968 width, height, 1969 format->depth, 1970 KGEM_BUFFER_WRITE); 1971 if (!pixmap) 1972 return false; 1973 1974 mask_image = 1975 pixman_image_create_bits(format->depth << 24 | format->format, 1976 width, height, 1977 pixmap->devPrivate.ptr, 1978 pixmap->devKind); 1979 if (mask_image == NULL) 1980 goto err_pixmap; 1981 1982 memset(pixmap->devPrivate.ptr, 0, pixmap->devKind*height); 1983#if HAS_PIXMAN_GLYPHS 1984 if (sna->render.glyph_cache) { 1985 pixman_glyph_t stack_glyphs[N_STACK_GLYPHS]; 1986 pixman_glyph_t *pglyphs = stack_glyphs; 1987 pixman_glyph_cache_t *cache; 1988 int count, n; 1989 1990 cache = sna->render.glyph_cache; 1991 pixman_glyph_cache_freeze(cache); 1992 1993 count = 0; 1994 for (n = 0; n < nlist; ++n) 1995 count += list[n].len; 1996 if (count > N_STACK_GLYPHS) { 1997 pglyphs = malloc (count * sizeof(pixman_glyph_t)); 1998 if (pglyphs == NULL) 1999 goto err_pixmap; 2000 } 2001 2002 count = 0; 2003 do { 2004 n = list->len; 2005 x += list->xOff; 2006 y += list->yOff; 2007 while (n--) { 2008 GlyphPtr g = *glyphs++; 2009 const void *ptr; 2010 2011 if (!glyph_valid(g)) 2012 goto next_pglyph; 2013 2014 ptr = pixman_glyph_cache_lookup(cache, g, NULL); 2015 if (ptr == NULL) { 2016 pixman_image_t *glyph_image; 2017 2018 glyph_image = sna_glyph_get_image(g, screen); 2019 if (glyph_image == NULL) 2020 goto next_pglyph; 2021 2022 ptr = pixman_glyph_cache_insert(cache, g, NULL, 2023 g->info.x, 2024 g->info.y, 2025 glyph_image); 2026 if (ptr == NULL) 2027 goto next_pglyph; 2028 } 2029 2030 pglyphs[count].x = x; 2031 pglyphs[count].y = y; 2032 pglyphs[count].glyph = ptr; 2033 count++; 2034 2035next_pglyph: 2036 x += g->info.xOff; 2037 y += g->info.yOff; 2038 } 2039 list++; 2040 } while (--nlist); 2041 2042 pixman_composite_glyphs_no_mask(PIXMAN_OP_ADD, 2043 sna->render.white_image, 2044 mask_image, 2045 0, 0, 2046 0, 0, 2047 cache, count, pglyphs); 2048 pixman_glyph_cache_thaw(cache); 2049 if (pglyphs != stack_glyphs) 2050 free(pglyphs); 2051 } else 2052#endif 2053 do { 2054 int n = list->len; 2055 x += list->xOff; 2056 y += list->yOff; 2057 while (n--) { 2058 GlyphPtr g = *glyphs++; 2059 pixman_image_t *glyph_image; 2060 int16_t xi, yi; 2061 2062 if (!glyph_valid(g)) 2063 goto next_image; 2064 2065 /* If the mask has been cropped, it is likely 2066 * that some of the glyphs fall outside. 2067 */ 2068 xi = x - g->info.x; 2069 yi = y - g->info.y; 2070 if (xi >= width || yi >= height) 2071 goto next_image; 2072 if (xi + g->info.width <= 0 || 2073 yi + g->info.height <= 0) 2074 goto next_image; 2075 2076 glyph_image = 2077 sna_glyph_get_image(g, dst->pDrawable->pScreen); 2078 if (glyph_image == NULL) 2079 goto next_image; 2080 2081 DBG(("%s: glyph to mask (%d, %d)x(%d, %d)\n", 2082 __FUNCTION__, 2083 xi, yi, 2084 g->info.width, 2085 g->info.height)); 2086 2087 if (list->format == format) { 2088 assert(pixman_image_get_format(glyph_image) == pixman_image_get_format(mask_image)); 2089 pixman_image_composite(PictOpAdd, 2090 glyph_image, 2091 NULL, 2092 mask_image, 2093 0, 0, 2094 0, 0, 2095 xi, yi, 2096 g->info.width, 2097 g->info.height); 2098 } else { 2099 pixman_image_composite(PictOpAdd, 2100 sna->render.white_image, 2101 glyph_image, 2102 mask_image, 2103 0, 0, 2104 0, 0, 2105 xi, yi, 2106 g->info.width, 2107 g->info.height); 2108 } 2109 2110next_image: 2111 x += g->info.xOff; 2112 y += g->info.yOff; 2113 } 2114 list++; 2115 } while (--nlist); 2116 pixman_image_unref(mask_image); 2117 2118 component_alpha = NeedsComponent(format->format); 2119 2120 mask = CreatePicture(0, &pixmap->drawable, 2121 format, CPComponentAlpha, 2122 &component_alpha, serverClient, &error); 2123 if (!mask) 2124 goto err_pixmap; 2125 2126 ValidatePicture(mask); 2127 2128 sna_composite(op, 2129 src, mask, dst, 2130 src_x, src_y, 2131 0, 0, 2132 box.x1, box.y1, 2133 width, height); 2134 FreePicture(mask, 0); 2135 ret = true; 2136err_pixmap: 2137 sna_pixmap_destroy(pixmap); 2138 return ret; 2139} 2140 2141void 2142sna_glyphs__shared(CARD8 op, 2143 PicturePtr src, 2144 PicturePtr dst, 2145 PictFormatPtr mask, 2146 INT16 src_x, INT16 src_y, 2147 int nlist, GlyphListPtr list, GlyphPtr *glyphs) 2148{ 2149 PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable); 2150 struct sna *sna = to_sna_from_pixmap(pixmap); 2151 struct sna_pixmap *priv; 2152 2153 DBG(("%s(op=%d, nlist=%d, src=(%d, %d))\n", 2154 __FUNCTION__, op, nlist, src_x, src_y)); 2155 2156 if (REGION_NUM_RECTS(dst->pCompositeClip) == 0) 2157 return; 2158 2159 if (FALLBACK) 2160 goto fallback; 2161 2162 if (!can_render(sna)) { 2163 DBG(("%s: wedged\n", __FUNCTION__)); 2164 goto fallback; 2165 } 2166 2167 if (dst->alphaMap) { 2168 DBG(("%s: fallback -- dst alpha map\n", __FUNCTION__)); 2169 goto fallback; 2170 } 2171 2172 priv = sna_pixmap(pixmap); 2173 if (priv == NULL) { 2174 DBG(("%s: fallback -- destination unattached\n", __FUNCTION__)); 2175 goto fallback; 2176 } 2177 2178 if ((too_small(priv) || DAMAGE_IS_ALL(priv->cpu_damage)) && 2179 !picture_is_gpu(sna, src)) { 2180 DBG(("%s: fallback -- too small (%dx%d)\n", 2181 __FUNCTION__, dst->pDrawable->width, dst->pDrawable->height)); 2182 goto fallback; 2183 } 2184 2185 if (!mask) { 2186 mask = glyphs_format(nlist, list, glyphs); 2187 DBG(("%s: substituting mask? %d\n", __FUNCTION__, mask!=NULL)); 2188 } 2189 if (mask) { 2190 if (glyphs_via_image(sna, op, 2191 src, dst, mask, 2192 src_x, src_y, 2193 nlist, list, glyphs)) 2194 return; 2195 } 2196 2197fallback: 2198 glyphs_fallback(op, src, dst, mask, src_x, src_y, nlist, list, glyphs); 2199} 2200 2201void 2202sna_glyph_unrealize(ScreenPtr screen, GlyphPtr glyph) 2203{ 2204 struct sna_glyph *p = sna_glyph(glyph); 2205 2206 DBG(("%s: screen=%d, glyph(image?=%d, atlas?=%d)\n", 2207 __FUNCTION__, screen->myNum, !!p->image, !!p->atlas)); 2208 2209 if (p->image) { 2210#if HAS_PIXMAN_GLYPHS 2211 struct sna *sna = to_sna_from_screen(screen); 2212 if (sna->render.glyph_cache) 2213 pixman_glyph_cache_remove(sna->render.glyph_cache, 2214 glyph, NULL); 2215#endif 2216 pixman_image_unref(p->image); 2217 p->image = NULL; 2218 } 2219 2220 if (p->atlas && p->atlas != GetGlyphPicture(glyph, screen)) { 2221 struct sna *sna = to_sna_from_screen(screen); 2222 struct sna_glyph_cache *cache = &sna->render.glyph[p->pos&1]; 2223 DBG(("%s: releasing glyph pos %d from cache %d\n", 2224 __FUNCTION__, p->pos >> 1, p->pos & 1)); 2225 assert(cache->glyphs[p->pos >> 1] == p); 2226 cache->glyphs[p->pos >> 1] = NULL; 2227 p->atlas = NULL; 2228 } 2229} 2230