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_DIX_CONFIG_H 62#include <dix-config.h> 63#endif 64 65#include <stdlib.h> 66 67#include "uxa-priv.h" 68#include "common.h" 69 70/* Width of the pixmaps we use for the caches; this should be less than 71 * max texture size of the driver; this may need to actually come from 72 * the driver. 73 */ 74#define CACHE_PICTURE_SIZE 1024 75#define GLYPH_MIN_SIZE 8 76#define GLYPH_MAX_SIZE 64 77#define GLYPH_CACHE_SIZE (CACHE_PICTURE_SIZE * CACHE_PICTURE_SIZE / (GLYPH_MIN_SIZE * GLYPH_MIN_SIZE)) 78 79struct uxa_glyph { 80 uxa_glyph_cache_t *cache; 81 uint16_t x, y; 82 uint16_t size, pos; 83}; 84 85#if HAS_DEVPRIVATEKEYREC 86static DevPrivateKeyRec uxa_glyph_key; 87#else 88static int uxa_glyph_key; 89#endif 90 91static inline struct uxa_glyph *uxa_glyph_get_private(GlyphPtr glyph) 92{ 93#if HAS_DEVPRIVATEKEYREC 94 return dixGetPrivate(&glyph->devPrivates, &uxa_glyph_key); 95#else 96 return dixLookupPrivate(&glyph->devPrivates, &uxa_glyph_key); 97#endif 98} 99 100static inline void uxa_glyph_set_private(GlyphPtr glyph, struct uxa_glyph *priv) 101{ 102 dixSetPrivate(&glyph->devPrivates, &uxa_glyph_key, priv); 103} 104 105#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) 106 107static void uxa_unrealize_glyph_caches(ScreenPtr pScreen) 108{ 109 uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); 110 int i; 111 112 if (!uxa_screen->glyph_cache_initialized) 113 return; 114 115 for (i = 0; i < UXA_NUM_GLYPH_CACHE_FORMATS; i++) { 116 uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; 117 118 if (cache->picture) 119 FreePicture(cache->picture, 0); 120 121 if (cache->glyphs) 122 free(cache->glyphs); 123 } 124 uxa_screen->glyph_cache_initialized = FALSE; 125} 126 127void uxa_glyphs_fini(ScreenPtr pScreen) 128{ 129 uxa_unrealize_glyph_caches(pScreen); 130} 131 132/* All caches for a single format share a single pixmap for glyph storage, 133 * allowing mixing glyphs of different sizes without paying a penalty 134 * for switching between source pixmaps. (Note that for a size of font 135 * right at the border between two sizes, we might be switching for almost 136 * every glyph.) 137 * 138 * This function allocates the storage pixmap, and then fills in the 139 * rest of the allocated structures for all caches with the given format. 140 */ 141static Bool uxa_realize_glyph_caches(ScreenPtr pScreen) 142{ 143 uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); 144 unsigned int formats[] = { 145 PIXMAN_a8, 146 PIXMAN_a8r8g8b8, 147 }; 148 unsigned i; 149 150 if (uxa_screen->glyph_cache_initialized) 151 return TRUE; 152 153 uxa_screen->glyph_cache_initialized = TRUE; 154 memset(uxa_screen->glyphCaches, 0, sizeof(uxa_screen->glyphCaches)); 155 156 for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) { 157 uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; 158 PixmapPtr pixmap; 159 PicturePtr picture; 160 CARD32 component_alpha; 161 int depth = PIXMAN_FORMAT_DEPTH(formats[i]); 162 int error; 163 PictFormatPtr pPictFormat = PictureMatchFormat(pScreen, depth, formats[i]); 164 if (!pPictFormat) 165 goto bail; 166 167 /* Now allocate the pixmap and picture */ 168 pixmap = pScreen->CreatePixmap(pScreen, 169 CACHE_PICTURE_SIZE, CACHE_PICTURE_SIZE, depth, 170 INTEL_CREATE_PIXMAP_TILING_X); 171 if (!pixmap) 172 goto bail; 173 if (!uxa_pixmap_is_offscreen(pixmap)) { 174 /* Presume shadow is in-effect */ 175 pScreen->DestroyPixmap(pixmap); 176 uxa_unrealize_glyph_caches(pScreen); 177 return TRUE; 178 } 179 180 component_alpha = NeedsComponent(pPictFormat->format); 181 picture = CreatePicture(0, &pixmap->drawable, pPictFormat, 182 CPComponentAlpha, &component_alpha, 183 serverClient, &error); 184 185 pScreen->DestroyPixmap(pixmap); 186 187 if (!picture) 188 goto bail; 189 190 ValidatePicture(picture); 191 192 cache->picture = picture; 193 cache->glyphs = calloc(sizeof(GlyphPtr), GLYPH_CACHE_SIZE); 194 if (!cache->glyphs) 195 goto bail; 196 197 cache->evict = rand() % GLYPH_CACHE_SIZE; 198 } 199 assert(i == UXA_NUM_GLYPH_CACHE_FORMATS); 200 201 return TRUE; 202 203bail: 204 uxa_unrealize_glyph_caches(pScreen); 205 return FALSE; 206} 207 208 209Bool uxa_glyphs_init(ScreenPtr pScreen) 210{ 211 212#if HAS_DIXREGISTERPRIVATEKEY 213 if (!dixRegisterPrivateKey(&uxa_glyph_key, PRIVATE_GLYPH, 0)) 214 return FALSE; 215#else 216 if (!dixRequestPrivate(&uxa_glyph_key, 0)) 217 return FALSE; 218#endif 219 220 /* Skip pixmap creation if we don't intend to use it. */ 221 if (uxa_get_screen(pScreen)->force_fallback) 222 return TRUE; 223 224 return uxa_realize_glyph_caches(pScreen); 225} 226 227/* The most efficient thing to way to upload the glyph to the screen 228 * is to use CopyArea; uxa pixmaps are always offscreen. 229 */ 230static void 231uxa_glyph_cache_upload_glyph(ScreenPtr screen, 232 uxa_glyph_cache_t * cache, 233 GlyphPtr glyph, 234 int x, int y) 235{ 236 PicturePtr pGlyphPicture = GetGlyphPicture(glyph, screen); 237 PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable; 238 PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable; 239 PixmapPtr scratch; 240 GCPtr gc; 241 242 gc = GetScratchGC(pCachePixmap->drawable.depth, screen); 243 if (!gc) 244 return; 245 246 ValidateGC(&pCachePixmap->drawable, gc); 247 248 scratch = pGlyphPixmap; 249 /* Create a temporary bo to stream the updates to the cache */ 250 if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth || 251 !uxa_pixmap_is_offscreen(scratch)) { 252 scratch = screen->CreatePixmap(screen, 253 glyph->info.width, 254 glyph->info.height, 255 pCachePixmap->drawable.depth, 256 UXA_CREATE_PIXMAP_FOR_MAP); 257 if (scratch) { 258 if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth) { 259 PicturePtr picture; 260 int error; 261 262 picture = CreatePicture(0, &scratch->drawable, 263 PictureMatchFormat(screen, 264 pCachePixmap->drawable.depth, 265 cache->picture->format), 266 0, NULL, 267 serverClient, &error); 268 if (picture) { 269 ValidatePicture(picture); 270 uxa_composite(PictOpSrc, pGlyphPicture, NULL, picture, 271 0, 0, 272 0, 0, 273 0, 0, 274 glyph->info.width, glyph->info.height); 275 FreePicture(picture, 0); 276 } 277 } else { 278 uxa_copy_area(&pGlyphPixmap->drawable, 279 &scratch->drawable, 280 gc, 281 0, 0, 282 glyph->info.width, glyph->info.height, 283 0, 0); 284 } 285 } else { 286 scratch = pGlyphPixmap; 287 } 288 } 289 290 uxa_copy_area(&scratch->drawable, &pCachePixmap->drawable, gc, 291 0, 0, 292 glyph->info.width, glyph->info.height, 293 x, y); 294 295 if (scratch != pGlyphPixmap) 296 screen->DestroyPixmap(scratch); 297 298 FreeScratchGC(gc); 299} 300 301void 302uxa_glyph_unrealize(ScreenPtr screen, 303 GlyphPtr glyph) 304{ 305 struct uxa_glyph *priv; 306 307 /* Use Lookup in case we have not attached to this glyph. */ 308 priv = dixLookupPrivate(&glyph->devPrivates, &uxa_glyph_key); 309 if (priv == NULL) 310 return; 311 312 priv->cache->glyphs[priv->pos] = NULL; 313 314 uxa_glyph_set_private(glyph, NULL); 315 free(priv); 316} 317 318/* Cut and paste from render/glyph.c - probably should export it instead */ 319static void 320uxa_glyph_extents(int nlist, 321 GlyphListPtr list, GlyphPtr * glyphs, BoxPtr extents) 322{ 323 int x1, x2, y1, y2; 324 int x, y, n; 325 326 x1 = y1 = MAXSHORT; 327 x2 = y2 = MINSHORT; 328 x = y = 0; 329 while (nlist--) { 330 x += list->xOff; 331 y += list->yOff; 332 n = list->len; 333 list++; 334 while (n--) { 335 GlyphPtr glyph = *glyphs++; 336 int v; 337 338 v = x - glyph->info.x; 339 if (v < x1) 340 x1 = v; 341 v += glyph->info.width; 342 if (v > x2) 343 x2 = v; 344 345 v = y - glyph->info.y; 346 if (v < y1) 347 y1 = v; 348 v += glyph->info.height; 349 if (v > y2) 350 y2 = v; 351 352 x += glyph->info.xOff; 353 y += glyph->info.yOff; 354 } 355 } 356 357 extents->x1 = x1 < MINSHORT ? MINSHORT : x1; 358 extents->x2 = x2 > MAXSHORT ? MAXSHORT : x2; 359 extents->y1 = y1 < MINSHORT ? MINSHORT : y1; 360 extents->y2 = y2 > MAXSHORT ? MAXSHORT : y2; 361} 362 363/** 364 * Returns TRUE if the glyphs in the lists intersect. Only checks based on 365 * bounding box, which appears to be good enough to catch most cases at least. 366 */ 367static Bool 368uxa_glyphs_intersect(int nlist, GlyphListPtr list, GlyphPtr * glyphs) 369{ 370 int x1, x2, y1, y2; 371 int n; 372 int x, y; 373 BoxRec extents; 374 Bool first = TRUE; 375 376 x = 0; 377 y = 0; 378 extents.x1 = 0; 379 extents.y1 = 0; 380 extents.x2 = 0; 381 extents.y2 = 0; 382 while (nlist--) { 383 x += list->xOff; 384 y += list->yOff; 385 n = list->len; 386 list++; 387 while (n--) { 388 GlyphPtr glyph = *glyphs++; 389 390 if (glyph->info.width == 0 || glyph->info.height == 0) { 391 x += glyph->info.xOff; 392 y += glyph->info.yOff; 393 continue; 394 } 395 396 x1 = x - glyph->info.x; 397 if (x1 < MINSHORT) 398 x1 = MINSHORT; 399 y1 = y - glyph->info.y; 400 if (y1 < MINSHORT) 401 y1 = MINSHORT; 402 x2 = x1 + glyph->info.width; 403 if (x2 > MAXSHORT) 404 x2 = MAXSHORT; 405 y2 = y1 + glyph->info.height; 406 if (y2 > MAXSHORT) 407 y2 = MAXSHORT; 408 409 if (first) { 410 extents.x1 = x1; 411 extents.y1 = y1; 412 extents.x2 = x2; 413 extents.y2 = y2; 414 first = FALSE; 415 } else { 416 if (x1 < extents.x2 && x2 > extents.x1 && 417 y1 < extents.y2 && y2 > extents.y1) { 418 return TRUE; 419 } 420 421 if (x1 < extents.x1) 422 extents.x1 = x1; 423 if (x2 > extents.x2) 424 extents.x2 = x2; 425 if (y1 < extents.y1) 426 extents.y1 = y1; 427 if (y2 > extents.y2) 428 extents.y2 = y2; 429 } 430 x += glyph->info.xOff; 431 y += glyph->info.yOff; 432 } 433 } 434 435 return FALSE; 436} 437 438static void 439uxa_check_glyphs(CARD8 op, 440 PicturePtr src, 441 PicturePtr dst, 442 PictFormatPtr maskFormat, 443 INT16 xSrc, 444 INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs) 445{ 446 pixman_image_t *image; 447 PixmapPtr scratch; 448 PicturePtr mask, mask_src = NULL, mask_dst = NULL, white = NULL; 449 int width = 0, height = 0; 450 int x, y, n; 451 int xDst = list->xOff, yDst = list->yOff; 452 BoxRec extents = { 0, 0, 0, 0 }; 453 CARD8 mask_op = 0; 454 455 if (maskFormat) { 456 pixman_format_code_t format; 457 CARD32 component_alpha; 458 xRenderColor color; 459 int error; 460 461 uxa_glyph_extents(nlist, list, glyphs, &extents); 462 if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) 463 return; 464 465 width = extents.x2 - extents.x1; 466 height = extents.y2 - extents.y1; 467 468 format = maskFormat->format | 469 (BitsPerPixel(maskFormat->depth) << 24); 470 image = 471 pixman_image_create_bits(format, width, height, NULL, 0); 472 if (!image) 473 return; 474 475 scratch = GetScratchPixmapHeader(dst->pDrawable->pScreen, width, height, 476 PIXMAN_FORMAT_DEPTH(format), 477 PIXMAN_FORMAT_BPP(format), 478 pixman_image_get_stride(image), 479 pixman_image_get_data(image)); 480 481 if (!scratch) { 482 pixman_image_unref(image); 483 return; 484 } 485 486 component_alpha = NeedsComponent(maskFormat->format); 487 mask = CreatePicture(0, &scratch->drawable, 488 maskFormat, CPComponentAlpha, 489 &component_alpha, serverClient, &error); 490 if (!mask) { 491 FreeScratchPixmapHeader(scratch); 492 pixman_image_unref(image); 493 return; 494 } 495 ValidatePicture(mask); 496 497 x = -extents.x1; 498 y = -extents.y1; 499 500 color.red = color.green = color.blue = color.alpha = 0xffff; 501 white = CreateSolidPicture(0, &color, &error); 502 503 mask_op = op; 504 op = PictOpAdd; 505 506 mask_src = src; 507 src = white; 508 509 mask_dst = dst; 510 dst = mask; 511 } else { 512 mask = dst; 513 x = 0; 514 y = 0; 515 } 516 517 while (nlist--) { 518 x += list->xOff; 519 y += list->yOff; 520 n = list->len; 521 while (n--) { 522 GlyphPtr glyph = *glyphs++; 523 PicturePtr g = GetGlyphPicture(glyph, dst->pDrawable->pScreen); 524 if (g) { 525 CompositePicture(op, src, g, dst, 526 xSrc + (x - glyph->info.x) - xDst, 527 ySrc + (y - glyph->info.y) - yDst, 528 0, 0, 529 x - glyph->info.x, 530 y - glyph->info.y, 531 glyph->info.width, 532 glyph->info.height); 533 } 534 535 x += glyph->info.xOff; 536 y += glyph->info.yOff; 537 } 538 list++; 539 } 540 541 if (white) 542 FreePicture(white, 0); 543 544 if (maskFormat) { 545 x = extents.x1; 546 y = extents.y1; 547 CompositePicture(mask_op, mask_src, mask, mask_dst, 548 xSrc + x - xDst, 549 ySrc + y - yDst, 550 0, 0, 551 x, y, 552 width, height); 553 FreePicture(mask, 0); 554 FreeScratchPixmapHeader(scratch); 555 pixman_image_unref(image); 556 } 557} 558 559static inline unsigned int 560uxa_glyph_size_to_count(int size) 561{ 562 size /= GLYPH_MIN_SIZE; 563 return size * size; 564} 565 566static inline unsigned int 567uxa_glyph_count_to_mask(int count) 568{ 569 return ~(count - 1); 570} 571 572static inline unsigned int 573uxa_glyph_size_to_mask(int size) 574{ 575 return uxa_glyph_count_to_mask(uxa_glyph_size_to_count(size)); 576} 577 578static PicturePtr 579uxa_glyph_cache(ScreenPtr screen, GlyphPtr glyph, int *out_x, int *out_y) 580{ 581 uxa_screen_t *uxa_screen = uxa_get_screen(screen); 582 PicturePtr glyph_picture = GetGlyphPicture(glyph, screen); 583 uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[PICT_FORMAT_RGB(glyph_picture->format) != 0]; 584 struct uxa_glyph *priv = NULL; 585 int size, mask, pos, s; 586 587 if (glyph->info.width > GLYPH_MAX_SIZE || glyph->info.height > GLYPH_MAX_SIZE) 588 return NULL; 589 590 for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2) 591 if (glyph->info.width <= size && glyph->info.height <= size) 592 break; 593 594 s = uxa_glyph_size_to_count(size); 595 mask = uxa_glyph_count_to_mask(s); 596 pos = (cache->count + s - 1) & mask; 597 if (pos < GLYPH_CACHE_SIZE) { 598 cache->count = pos + s; 599 } else { 600 for (s = size; s <= GLYPH_MAX_SIZE; s *= 2) { 601 int i = cache->evict & uxa_glyph_size_to_mask(s); 602 GlyphPtr evicted = cache->glyphs[i]; 603 if (evicted == NULL) 604 continue; 605 606 priv = uxa_glyph_get_private(evicted); 607 if (priv->size >= s) { 608 cache->glyphs[i] = NULL; 609 uxa_glyph_set_private(evicted, NULL); 610 pos = cache->evict & uxa_glyph_size_to_mask(size); 611 } else 612 priv = NULL; 613 break; 614 } 615 if (priv == NULL) { 616 int count = uxa_glyph_size_to_count(size); 617 mask = uxa_glyph_count_to_mask(count); 618 pos = cache->evict & mask; 619 for (s = 0; s < count; s++) { 620 GlyphPtr evicted = cache->glyphs[pos + s]; 621 if (evicted != NULL) { 622 if (priv != NULL) 623 free(priv); 624 625 priv = uxa_glyph_get_private(evicted); 626 uxa_glyph_set_private(evicted, NULL); 627 cache->glyphs[pos + s] = NULL; 628 } 629 } 630 } 631 632 /* And pick a new eviction position */ 633 cache->evict = rand() % GLYPH_CACHE_SIZE; 634 } 635 636 if (priv == NULL) { 637 priv = malloc(sizeof(struct uxa_glyph)); 638 if (priv == NULL) 639 return NULL; 640 } 641 642 uxa_glyph_set_private(glyph, priv); 643 cache->glyphs[pos] = glyph; 644 645 priv->cache = cache; 646 priv->size = size; 647 priv->pos = pos; 648 s = pos / ((GLYPH_MAX_SIZE / GLYPH_MIN_SIZE) * (GLYPH_MAX_SIZE / GLYPH_MIN_SIZE)); 649 priv->x = s % (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE) * GLYPH_MAX_SIZE; 650 priv->y = (s / (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE)) * GLYPH_MAX_SIZE; 651 for (s = GLYPH_MIN_SIZE; s < GLYPH_MAX_SIZE; s *= 2) { 652 if (pos & 1) 653 priv->x += s; 654 if (pos & 2) 655 priv->y += s; 656 pos >>= 2; 657 } 658 659 uxa_glyph_cache_upload_glyph(screen, cache, glyph, priv->x, priv->y); 660 661 *out_x = priv->x; 662 *out_y = priv->y; 663 return cache->picture; 664} 665 666static void 667uxa_clear_pixmap(ScreenPtr screen, 668 uxa_screen_t *uxa_screen, 669 PixmapPtr pixmap) 670{ 671 if (uxa_screen->info->check_solid && 672 !uxa_screen->info->check_solid(&pixmap->drawable, GXcopy, FB_ALLONES)) 673 goto fallback; 674 675 if (!uxa_screen->info->prepare_solid(pixmap, GXcopy, FB_ALLONES, 0)) 676 goto fallback; 677 678 uxa_screen->info->solid(pixmap, 679 0, 0, 680 pixmap->drawable.width, 681 pixmap->drawable.height); 682 683 uxa_screen->info->done_solid(pixmap); 684 return; 685 686fallback: 687 { 688 GCPtr gc; 689 690 gc = GetScratchGC(pixmap->drawable.depth, screen); 691 if (gc) { 692 xRectangle rect; 693 694 ValidateGC(&pixmap->drawable, gc); 695 696 rect.x = 0; 697 rect.y = 0; 698 rect.width = pixmap->drawable.width; 699 rect.height = pixmap->drawable.height; 700 gc->ops->PolyFillRect(&pixmap->drawable, gc, 1, &rect); 701 702 FreeScratchGC(gc); 703 } 704 } 705} 706 707static PicturePtr 708create_white_solid(ScreenPtr screen) 709{ 710 PicturePtr white, ret = NULL; 711 xRenderColor color; 712 int error; 713 714 color.red = color.green = color.blue = color.alpha = 0xffff; 715 white = CreateSolidPicture(0, &color, &error); 716 if (white) { 717 ret = uxa_acquire_solid(screen, white->pSourcePict); 718 FreePicture(white, 0); 719 } 720 721 return ret; 722} 723 724static int 725uxa_glyphs_via_mask(CARD8 op, 726 PicturePtr pSrc, 727 PicturePtr pDst, 728 PictFormatPtr maskFormat, 729 INT16 xSrc, INT16 ySrc, 730 int nlist, GlyphListPtr list, GlyphPtr * glyphs) 731{ 732 ScreenPtr screen = pDst->pDrawable->pScreen; 733 uxa_screen_t *uxa_screen = uxa_get_screen(screen); 734 CARD32 component_alpha; 735 PixmapPtr pixmap, white_pixmap; 736 PicturePtr glyph_atlas, mask, white; 737 int xDst = list->xOff, yDst = list->yOff; 738 int x, y, width, height; 739 int dst_off_x, dst_off_y; 740 int n, error; 741 BoxRec box; 742 743 uxa_glyph_extents(nlist, list, glyphs, &box); 744 if (box.x2 <= box.x1 || box.y2 <= box.y1) 745 return 0; 746 747 dst_off_x = box.x1; 748 dst_off_y = box.y1; 749 750 width = box.x2 - box.x1; 751 height = box.y2 - box.y1; 752 x = -box.x1; 753 y = -box.y1; 754 755 if (maskFormat->depth == 1) { 756 PictFormatPtr a8Format = 757 PictureMatchFormat(screen, 8, PICT_a8); 758 759 if (!a8Format) 760 return -1; 761 762 maskFormat = a8Format; 763 } 764 765 pixmap = screen->CreatePixmap(screen, width, height, 766 maskFormat->depth, 767 CREATE_PIXMAP_USAGE_SCRATCH); 768 if (!pixmap) 769 return 1; 770 771 if (!uxa_pixmap_is_offscreen(pixmap)) { 772 screen->DestroyPixmap(pixmap); 773 return -1; 774 } 775 776 white_pixmap = NULL; 777 white = create_white_solid(screen); 778 if (white) 779 white_pixmap = uxa_get_drawable_pixmap(white->pDrawable); 780 if (!white_pixmap) { 781 if (white) 782 FreePicture(white, 0); 783 screen->DestroyPixmap(pixmap); 784 return -1; 785 } 786 787 uxa_clear_pixmap(screen, uxa_screen, pixmap); 788 789 component_alpha = NeedsComponent(maskFormat->format); 790 mask = CreatePicture(0, &pixmap->drawable, 791 maskFormat, CPComponentAlpha, 792 &component_alpha, serverClient, &error); 793 screen->DestroyPixmap(pixmap); 794 795 if (!mask) { 796 FreePicture(white, 0); 797 return 1; 798 } 799 800 ValidatePicture(mask); 801 802 glyph_atlas = NULL; 803 while (nlist--) { 804 x += list->xOff; 805 y += list->yOff; 806 n = list->len; 807 while (n--) { 808 GlyphPtr glyph = *glyphs++; 809 PicturePtr this_atlas; 810 int glyph_x, glyph_y; 811 struct uxa_glyph *priv; 812 813 if (glyph->info.width == 0 || glyph->info.height == 0) 814 goto next_glyph; 815 816 priv = uxa_glyph_get_private(glyph); 817 if (priv != NULL) { 818 glyph_x = priv->x; 819 glyph_y = priv->y; 820 this_atlas = priv->cache->picture; 821 } else { 822 if (glyph_atlas) { 823 uxa_screen->info->done_composite(pixmap); 824 glyph_atlas = NULL; 825 } 826 this_atlas = uxa_glyph_cache(screen, glyph, &glyph_x, &glyph_y); 827 if (this_atlas == NULL) { 828 /* no cache for this glyph */ 829 this_atlas = GetGlyphPicture(glyph, screen); 830 glyph_x = glyph_y = 0; 831 } 832 } 833 834 if (this_atlas != glyph_atlas) { 835 PixmapPtr glyph_pixmap; 836 837 if (glyph_atlas) 838 uxa_screen->info->done_composite(pixmap); 839 840 glyph_pixmap = 841 uxa_get_drawable_pixmap(this_atlas->pDrawable); 842 if (!uxa_pixmap_is_offscreen(glyph_pixmap) || 843 !uxa_screen->info->prepare_composite(PictOpAdd, 844 white, this_atlas, mask, 845 white_pixmap, glyph_pixmap, pixmap)) { 846 FreePicture(white, 0); 847 FreePicture(mask, 0); 848 return -1; 849 } 850 851 glyph_atlas = this_atlas; 852 } 853 854 uxa_screen->info->composite(pixmap, 855 0, 0, 856 glyph_x, glyph_y, 857 x - glyph->info.x, 858 y - glyph->info.y, 859 glyph->info.width, 860 glyph->info.height); 861 862next_glyph: 863 x += glyph->info.xOff; 864 y += glyph->info.yOff; 865 } 866 list++; 867 } 868 if (glyph_atlas) 869 uxa_screen->info->done_composite(pixmap); 870 871 uxa_composite(op, 872 pSrc, mask, pDst, 873 dst_off_x + xSrc - xDst, 874 dst_off_y + ySrc - yDst, 875 0, 0, 876 dst_off_x, dst_off_y, 877 width, height); 878 879 FreePicture(white, 0); 880 FreePicture(mask, 0); 881 return 0; 882} 883 884static int 885uxa_glyphs_to_dst(CARD8 op, 886 PicturePtr pSrc, 887 PicturePtr pDst, 888 INT16 xSrc, INT16 ySrc, 889 int nlist, GlyphListPtr list, GlyphPtr * glyphs) 890{ 891 ScreenPtr screen = pDst->pDrawable->pScreen; 892 int x, y, n; 893 894 xSrc -= list->xOff; 895 ySrc -= list->yOff; 896 x = y = 0; 897 while (nlist--) { 898 x += list->xOff; 899 y += list->yOff; 900 n = list->len; 901 while (n--) { 902 GlyphPtr glyph = *glyphs++; 903 PicturePtr glyph_atlas; 904 int glyph_x, glyph_y; 905 struct uxa_glyph *priv; 906 907 if (glyph->info.width == 0 || glyph->info.height == 0) 908 goto next_glyph; 909 910 priv = uxa_glyph_get_private(glyph); 911 if (priv != NULL) { 912 glyph_x = priv->x; 913 glyph_y = priv->y; 914 glyph_atlas = priv->cache->picture; 915 } else { 916 glyph_atlas = uxa_glyph_cache(screen, glyph, &glyph_x, &glyph_y); 917 if (glyph_atlas == NULL) { 918 /* no cache for this glyph */ 919 glyph_atlas = GetGlyphPicture(glyph, screen); 920 glyph_x = glyph_y = 0; 921 } 922 } 923 924 uxa_composite(op, 925 pSrc, glyph_atlas, pDst, 926 xSrc + x - glyph->info.x, 927 ySrc + y - glyph->info.y, 928 glyph_x, glyph_y, 929 x - glyph->info.x, 930 y - glyph->info.y, 931 glyph->info.width, glyph->info.height); 932 933next_glyph: 934 x += glyph->info.xOff; 935 y += glyph->info.yOff; 936 } 937 list++; 938 } 939 940 return 0; 941} 942 943static Bool 944is_solid(PicturePtr picture) 945{ 946 if (picture->pSourcePict) { 947 SourcePict *source = picture->pSourcePict; 948 return source->type == SourcePictTypeSolidFill; 949 } else { 950 return (picture->repeat && 951 picture->pDrawable->width == 1 && 952 picture->pDrawable->height == 1); 953 } 954} 955 956void 957uxa_glyphs(CARD8 op, 958 PicturePtr pSrc, 959 PicturePtr pDst, 960 PictFormatPtr maskFormat, 961 INT16 xSrc, INT16 ySrc, 962 int nlist, GlyphListPtr list, GlyphPtr * glyphs) 963{ 964 ScreenPtr screen = pDst->pDrawable->pScreen; 965 uxa_screen_t *uxa_screen = uxa_get_screen(screen); 966 967 if (!uxa_screen->info->prepare_composite || 968 uxa_screen->force_fallback || 969 !uxa_drawable_is_offscreen(pDst->pDrawable) || 970 pDst->alphaMap || pSrc->alphaMap || 971 /* XXX we fail to handle (rare) non-solid sources correctly. */ 972 !is_solid(pSrc)) { 973fallback: 974 uxa_check_glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); 975 return; 976 } 977 978 /* basic sanity check */ 979 if (uxa_screen->info->check_composite && 980 !uxa_screen->info->check_composite(op, pSrc, NULL, pDst, 0, 0)) { 981 goto fallback; 982 } 983 984 ValidatePicture(pSrc); 985 ValidatePicture(pDst); 986 987 if (!maskFormat) { 988 /* If we don't have a mask format but all the glyphs have the same format, 989 * require ComponentAlpha and don't intersect, use the glyph format as mask 990 * format for the full benefits of the glyph cache. 991 */ 992 if (NeedsComponent(list[0].format->format)) { 993 Bool sameFormat = TRUE; 994 int i; 995 996 maskFormat = list[0].format; 997 998 for (i = 0; i < nlist; i++) { 999 if (maskFormat->format != list[i].format->format) { 1000 sameFormat = FALSE; 1001 break; 1002 } 1003 } 1004 1005 if (!sameFormat || 1006 uxa_glyphs_intersect(nlist, list, glyphs)) 1007 maskFormat = NULL; 1008 } 1009 } 1010 1011 if (!maskFormat) { 1012 if (uxa_glyphs_to_dst(op, pSrc, pDst, 1013 xSrc, ySrc, 1014 nlist, list, glyphs)) 1015 goto fallback; 1016 } else { 1017 if (uxa_glyphs_via_mask(op, 1018 pSrc, pDst, maskFormat, 1019 xSrc, ySrc, 1020 nlist, list, glyphs)) 1021 goto fallback; 1022 } 1023} 1024