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