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