1/* 2 * Copyright © 2008 Red Hat, Inc. 3 * Partly based on code Copyright © 2000 SuSE, Inc. 4 * 5 * Permission to use, copy, modify, distribute, and sell this software and its 6 * documentation for any purpose is hereby granted without fee, provided that 7 * the above copyright notice appear in all copies and that both that 8 * copyright notice and this permission notice appear in supporting 9 * documentation, and that the name of Red Hat not be used in advertising or 10 * publicity pertaining to distribution of the software without specific, 11 * written prior permission. Red Hat makes no representations about the 12 * suitability of this software for any purpose. It is provided "as is" 13 * without express or implied warranty. 14 * 15 * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat 17 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 19 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 * 22 * Permission to use, copy, modify, distribute, and sell this software and its 23 * documentation for any purpose is hereby granted without fee, provided that 24 * the above copyright notice appear in all copies and that both that 25 * copyright notice and this permission notice appear in supporting 26 * documentation, and that the name of SuSE not be used in advertising or 27 * publicity pertaining to distribution of the software without specific, 28 * written prior permission. SuSE makes no representations about the 29 * suitability of this software for any purpose. It is provided "as is" 30 * without express or implied warranty. 31 * 32 * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 33 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE 34 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 35 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 36 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 37 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 38 * 39 * Author: Owen Taylor <otaylor@fishsoup.net> 40 * Based on code by: Keith Packard 41 */ 42 43#ifdef HAVE_DIX_CONFIG_H 44#include <dix-config.h> 45#endif 46 47#include <stdlib.h> 48 49#include "exa_priv.h" 50 51#include "mipict.h" 52 53#if DEBUG_GLYPH_CACHE 54#define DBG_GLYPH_CACHE(a) ErrorF a 55#else 56#define DBG_GLYPH_CACHE(a) 57#endif 58 59/* Width of the pixmaps we use for the caches; this should be less than 60 * max texture size of the driver; this may need to actually come from 61 * the driver. 62 */ 63#define CACHE_PICTURE_WIDTH 1024 64 65/* Maximum number of glyphs we buffer on the stack before flushing 66 * rendering to the mask or destination surface. 67 */ 68#define GLYPH_BUFFER_SIZE 256 69 70typedef struct { 71 PicturePtr mask; 72 ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE]; 73 int count; 74} ExaGlyphBuffer, *ExaGlyphBufferPtr; 75 76typedef enum { 77 ExaGlyphSuccess, /* Glyph added to render buffer */ 78 ExaGlyphFail, /* out of memory, etc */ 79 ExaGlyphNeedFlush, /* would evict a glyph already in the buffer */ 80} ExaGlyphCacheResult; 81 82void 83exaGlyphsInit(ScreenPtr pScreen) 84{ 85 ExaScreenPriv(pScreen); 86 int i = 0; 87 88 memset(pExaScr->glyphCaches, 0, sizeof(pExaScr->glyphCaches)); 89 90 pExaScr->glyphCaches[i].format = PICT_a8; 91 pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16; 92 i++; 93 pExaScr->glyphCaches[i].format = PICT_a8; 94 pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32; 95 i++; 96 pExaScr->glyphCaches[i].format = PICT_a8r8g8b8; 97 pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16; 98 i++; 99 pExaScr->glyphCaches[i].format = PICT_a8r8g8b8; 100 pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32; 101 i++; 102 103 assert(i == EXA_NUM_GLYPH_CACHES); 104 105 for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { 106 pExaScr->glyphCaches[i].columns = CACHE_PICTURE_WIDTH / pExaScr->glyphCaches[i].glyphWidth; 107 pExaScr->glyphCaches[i].size = 256; 108 pExaScr->glyphCaches[i].hashSize = 557; 109 } 110} 111 112static void 113exaUnrealizeGlyphCaches(ScreenPtr pScreen, 114 unsigned int format) 115{ 116 ExaScreenPriv(pScreen); 117 int i; 118 119 for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { 120 ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; 121 122 if (cache->format != format) 123 continue; 124 125 if (cache->picture) { 126 FreePicture ((pointer) cache->picture, (XID) 0); 127 cache->picture = NULL; 128 } 129 130 free(cache->hashEntries); 131 cache->hashEntries = NULL; 132 133 free(cache->glyphs); 134 cache->glyphs = NULL; 135 cache->glyphCount = 0; 136 } 137} 138 139#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) 140 141/* All caches for a single format share a single pixmap for glyph storage, 142 * allowing mixing glyphs of different sizes without paying a penalty 143 * for switching between mask pixmaps. (Note that for a size of font 144 * right at the border between two sizes, we might be switching for almost 145 * every glyph.) 146 * 147 * This function allocates the storage pixmap, and then fills in the 148 * rest of the allocated structures for all caches with the given format. 149 */ 150static Bool 151exaRealizeGlyphCaches(ScreenPtr pScreen, 152 unsigned int format) 153{ 154 ExaScreenPriv(pScreen); 155 156 int depth = PIXMAN_FORMAT_DEPTH(format); 157 PictFormatPtr pPictFormat; 158 PixmapPtr pPixmap; 159 PicturePtr pPicture; 160 CARD32 component_alpha; 161 int height; 162 int i; 163 int error; 164 165 pPictFormat = PictureMatchFormat(pScreen, depth, format); 166 if (!pPictFormat) 167 return FALSE; 168 169 /* Compute the total vertical size needed for the format */ 170 171 height = 0; 172 for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { 173 ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; 174 int rows; 175 176 if (cache->format != format) 177 continue; 178 179 cache->yOffset = height; 180 181 rows = (cache->size + cache->columns - 1) / cache->columns; 182 height += rows * cache->glyphHeight; 183 } 184 185 /* Now allocate the pixmap and picture */ 186 pPixmap = (*pScreen->CreatePixmap) (pScreen, 187 CACHE_PICTURE_WIDTH, 188 height, depth, 0); 189 if (!pPixmap) 190 return FALSE; 191 192 component_alpha = NeedsComponent(pPictFormat->format); 193 pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, 194 CPComponentAlpha, &component_alpha, serverClient, 195 &error); 196 197 (*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */ 198 199 if (!pPicture) 200 return FALSE; 201 202 /* And store the picture in all the caches for the format */ 203 for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { 204 ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; 205 int j; 206 207 if (cache->format != format) 208 continue; 209 210 cache->picture = pPicture; 211 cache->picture->refcnt++; 212 cache->hashEntries = malloc(sizeof(int) * cache->hashSize); 213 cache->glyphs = malloc(sizeof(ExaCachedGlyphRec) * cache->size); 214 cache->glyphCount = 0; 215 216 if (!cache->hashEntries || !cache->glyphs) 217 goto bail; 218 219 for (j = 0; j < cache->hashSize; j++) 220 cache->hashEntries[j] = -1; 221 222 cache->evictionPosition = rand() % cache->size; 223 } 224 225 /* Each cache references the picture individually */ 226 FreePicture ((pointer) pPicture, (XID) 0); 227 return TRUE; 228 229bail: 230 exaUnrealizeGlyphCaches(pScreen, format); 231 return FALSE; 232} 233 234void 235exaGlyphsFini (ScreenPtr pScreen) 236{ 237 ExaScreenPriv(pScreen); 238 int i; 239 240 for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { 241 ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; 242 243 if (cache->picture) 244 exaUnrealizeGlyphCaches(pScreen, cache->format); 245 } 246} 247 248static int 249exaGlyphCacheHashLookup(ExaGlyphCachePtr cache, 250 GlyphPtr pGlyph) 251{ 252 int slot; 253 254 slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; 255 256 while (TRUE) { /* hash table can never be full */ 257 int entryPos = cache->hashEntries[slot]; 258 if (entryPos == -1) 259 return -1; 260 261 if (memcmp(pGlyph->sha1, cache->glyphs[entryPos].sha1, sizeof(pGlyph->sha1)) == 0){ 262 return entryPos; 263 } 264 265 slot--; 266 if (slot < 0) 267 slot = cache->hashSize - 1; 268 } 269} 270 271static void 272exaGlyphCacheHashInsert(ExaGlyphCachePtr cache, 273 GlyphPtr pGlyph, 274 int pos) 275{ 276 int slot; 277 278 memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1)); 279 280 slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; 281 282 while (TRUE) { /* hash table can never be full */ 283 if (cache->hashEntries[slot] == -1) { 284 cache->hashEntries[slot] = pos; 285 return; 286 } 287 288 slot--; 289 if (slot < 0) 290 slot = cache->hashSize - 1; 291 } 292} 293 294static void 295exaGlyphCacheHashRemove(ExaGlyphCachePtr cache, 296 int pos) 297{ 298 int slot; 299 int emptiedSlot = -1; 300 301 slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize; 302 303 while (TRUE) { /* hash table can never be full */ 304 int entryPos = cache->hashEntries[slot]; 305 306 if (entryPos == -1) 307 return; 308 309 if (entryPos == pos) { 310 cache->hashEntries[slot] = -1; 311 emptiedSlot = slot; 312 } else if (emptiedSlot != -1) { 313 /* See if we can move this entry into the emptied slot, we can't 314 * do that if if entry would have hashed between the current position 315 * and the emptied slot. (taking wrapping into account). Bad positions 316 * are: 317 * 318 * | XXXXXXXXXX | 319 * i j 320 * 321 * |XXX XXXX| 322 * j i 323 * 324 * i - slot, j - emptiedSlot 325 * 326 * (Knuth 6.4R) 327 */ 328 329 int entrySlot = (*(CARD32 *) cache->glyphs[entryPos].sha1) % cache->hashSize; 330 331 if (!((entrySlot >= slot && entrySlot < emptiedSlot) || 332 (emptiedSlot < slot && (entrySlot < emptiedSlot || entrySlot >= slot)))) 333 { 334 cache->hashEntries[emptiedSlot] = entryPos; 335 cache->hashEntries[slot] = -1; 336 emptiedSlot = slot; 337 } 338 } 339 340 slot--; 341 if (slot < 0) 342 slot = cache->hashSize - 1; 343 } 344} 345 346#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth) 347#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight) 348 349/* The most efficient thing to way to upload the glyph to the screen 350 * is to use the UploadToScreen() driver hook; this allows us to 351 * pipeline glyph uploads and to avoid creating gpu backed pixmaps for 352 * glyphs that we'll never use again. 353 * 354 * If we can't do it with UploadToScreen (because the glyph has a gpu copy, 355 * etc), we fall back to CompositePicture. 356 * 357 * We need to damage the cache pixmap manually in either case because the damage 358 * layer unwrapped the picture screen before calling exaGlyphs. 359 */ 360static void 361exaGlyphCacheUploadGlyph(ScreenPtr pScreen, 362 ExaGlyphCachePtr cache, 363 int x, 364 int y, 365 GlyphPtr pGlyph) 366{ 367 ExaScreenPriv(pScreen); 368 PicturePtr pGlyphPicture = GlyphPicture(pGlyph)[pScreen->myNum]; 369 PixmapPtr pGlyphPixmap = (PixmapPtr)pGlyphPicture->pDrawable; 370 ExaPixmapPriv(pGlyphPixmap); 371 PixmapPtr pCachePixmap = (PixmapPtr)cache->picture->pDrawable; 372 373 if (!pExaScr->info->UploadToScreen || pExaScr->swappedOut || pExaPixmap->accel_blocked) 374 goto composite; 375 376 /* If the glyph pixmap is already uploaded, no point in doing 377 * things this way */ 378 if (exaPixmapHasGpuCopy(pGlyphPixmap)) 379 goto composite; 380 381 /* UploadToScreen only works if bpp match */ 382 if (pGlyphPixmap->drawable.bitsPerPixel != pCachePixmap->drawable.bitsPerPixel) 383 goto composite; 384 385 if (pExaScr->do_migration) { 386 ExaMigrationRec pixmaps[1]; 387 388 /* cache pixmap must have a gpu copy. */ 389 pixmaps[0].as_dst = TRUE; 390 pixmaps[0].as_src = FALSE; 391 pixmaps[0].pPix = pCachePixmap; 392 pixmaps[0].pReg = NULL; 393 exaDoMigration (pixmaps, 1, TRUE); 394 } 395 396 if (!exaPixmapHasGpuCopy(pCachePixmap)) 397 goto composite; 398 399 /* x,y are in pixmap coordinates, no need for cache{X,Y}off */ 400 if (pExaScr->info->UploadToScreen(pCachePixmap, 401 x, 402 y, 403 pGlyph->info.width, 404 pGlyph->info.height, 405 (char *)pExaPixmap->sys_ptr, 406 pExaPixmap->sys_pitch)) 407 goto damage; 408 409composite: 410 CompositePicture (PictOpSrc, 411 pGlyphPicture, 412 None, 413 cache->picture, 414 0, 0, 415 0, 0, 416 x, 417 y, 418 pGlyph->info.width, 419 pGlyph->info.height); 420 421damage: 422 /* The cache pixmap isn't a window, so no need to offset coordinates. */ 423 exaPixmapDirty (pCachePixmap, 424 x, 425 y, 426 x + cache->glyphWidth, 427 y + cache->glyphHeight); 428} 429 430static ExaGlyphCacheResult 431exaGlyphCacheBufferGlyph(ScreenPtr pScreen, 432 ExaGlyphCachePtr cache, 433 ExaGlyphBufferPtr buffer, 434 GlyphPtr pGlyph, 435 PicturePtr pSrc, 436 PicturePtr pDst, 437 INT16 xSrc, 438 INT16 ySrc, 439 INT16 xMask, 440 INT16 yMask, 441 INT16 xDst, 442 INT16 yDst) 443{ 444 ExaCompositeRectPtr rect; 445 int pos; 446 int x, y; 447 448 if (buffer->mask && buffer->mask != cache->picture) 449 return ExaGlyphNeedFlush; 450 451 if (!cache->picture) { 452 if (!exaRealizeGlyphCaches(pScreen, cache->format)) 453 return ExaGlyphFail; 454 } 455 456 DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n", 457 cache->glyphWidth, cache->glyphHeight, cache->format == PICT_a8 ? "A" : "ARGB", 458 (long)*(CARD32 *) pGlyph->sha1)); 459 460 pos = exaGlyphCacheHashLookup(cache, pGlyph); 461 if (pos != -1) { 462 DBG_GLYPH_CACHE((" found existing glyph at %d\n", pos)); 463 x = CACHE_X(pos); 464 y = CACHE_Y(pos); 465 } else { 466 if (cache->glyphCount < cache->size) { 467 /* Space remaining; we fill from the start */ 468 pos = cache->glyphCount; 469 x = CACHE_X(pos); 470 y = CACHE_Y(pos); 471 cache->glyphCount++; 472 DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos)); 473 474 exaGlyphCacheHashInsert(cache, pGlyph, pos); 475 476 } else { 477 /* Need to evict an entry. We have to see if any glyphs 478 * already in the output buffer were at this position in 479 * the cache 480 */ 481 pos = cache->evictionPosition; 482 x = CACHE_X(pos); 483 y = CACHE_Y(pos); 484 DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos)); 485 if (buffer->count) { 486 int i; 487 488 for (i = 0; i < buffer->count; i++) { 489 if (pSrc ? 490 (buffer->rects[i].xMask == x && buffer->rects[i].yMask == y) : 491 (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y)) { 492 DBG_GLYPH_CACHE((" must flush buffer\n")); 493 return ExaGlyphNeedFlush; 494 } 495 } 496 } 497 498 /* OK, we're all set, swap in the new glyph */ 499 exaGlyphCacheHashRemove(cache, pos); 500 exaGlyphCacheHashInsert(cache, pGlyph, pos); 501 502 /* And pick a new eviction position */ 503 cache->evictionPosition = rand() % cache->size; 504 } 505 506 exaGlyphCacheUploadGlyph(pScreen, cache, x, y, pGlyph); 507 } 508 509 buffer->mask = cache->picture; 510 511 rect = &buffer->rects[buffer->count]; 512 513 if (pSrc) 514 { 515 rect->xSrc = xSrc; 516 rect->ySrc = ySrc; 517 rect->xMask = x; 518 rect->yMask = y; 519 } 520 else 521 { 522 rect->xSrc = x; 523 rect->ySrc = y; 524 rect->xMask = 0; 525 rect->yMask = 0; 526 } 527 528 rect->pDst = pDst; 529 rect->xDst = xDst; 530 rect->yDst = yDst; 531 rect->width = pGlyph->info.width; 532 rect->height = pGlyph->info.height; 533 534 buffer->count++; 535 536 return ExaGlyphSuccess; 537} 538 539#undef CACHE_X 540#undef CACHE_Y 541 542static ExaGlyphCacheResult 543exaBufferGlyph(ScreenPtr pScreen, 544 ExaGlyphBufferPtr buffer, 545 GlyphPtr pGlyph, 546 PicturePtr pSrc, 547 PicturePtr pDst, 548 INT16 xSrc, 549 INT16 ySrc, 550 INT16 xMask, 551 INT16 yMask, 552 INT16 xDst, 553 INT16 yDst) 554{ 555 ExaScreenPriv(pScreen); 556 unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format; 557 int width = pGlyph->info.width; 558 int height = pGlyph->info.height; 559 ExaCompositeRectPtr rect; 560 PicturePtr mask; 561 int i; 562 563 if (buffer->count == GLYPH_BUFFER_SIZE) 564 return ExaGlyphNeedFlush; 565 566 if (PICT_FORMAT_BPP(format) == 1) 567 format = PICT_a8; 568 569 for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { 570 ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; 571 572 if (format == cache->format && 573 width <= cache->glyphWidth && 574 height <= cache->glyphHeight) { 575 ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen, 576 &pExaScr->glyphCaches[i], 577 buffer, 578 pGlyph, 579 pSrc, 580 pDst, 581 xSrc, ySrc, 582 xMask, yMask, 583 xDst, yDst); 584 switch (result) { 585 case ExaGlyphFail: 586 break; 587 case ExaGlyphSuccess: 588 case ExaGlyphNeedFlush: 589 return result; 590 } 591 } 592 } 593 594 /* Couldn't find the glyph in the cache, use the glyph picture directly */ 595 596 mask = GlyphPicture(pGlyph)[pScreen->myNum]; 597 if (buffer->mask && buffer->mask != mask) 598 return ExaGlyphNeedFlush; 599 600 buffer->mask = mask; 601 602 rect = &buffer->rects[buffer->count]; 603 rect->xSrc = xSrc; 604 rect->ySrc = ySrc; 605 rect->xMask = xMask; 606 rect->yMask = yMask; 607 rect->xDst = xDst; 608 rect->yDst = yDst; 609 rect->width = width; 610 rect->height = height; 611 612 buffer->count++; 613 614 return ExaGlyphSuccess; 615} 616 617static void 618exaGlyphsToMask(PicturePtr pMask, 619 ExaGlyphBufferPtr buffer) 620{ 621 exaCompositeRects(PictOpAdd, buffer->mask, NULL, pMask, 622 buffer->count, buffer->rects); 623 624 buffer->count = 0; 625 buffer->mask = NULL; 626} 627 628static void 629exaGlyphsToDst(PicturePtr pSrc, 630 PicturePtr pDst, 631 ExaGlyphBufferPtr buffer) 632{ 633 exaCompositeRects(PictOpOver, pSrc, buffer->mask, pDst, buffer->count, 634 buffer->rects); 635 636 buffer->count = 0; 637 buffer->mask = NULL; 638} 639 640/* Cut and paste from render/glyph.c - probably should export it instead */ 641static void 642GlyphExtents (int nlist, 643 GlyphListPtr list, 644 GlyphPtr *glyphs, 645 BoxPtr extents) 646{ 647 int x1, x2, y1, y2; 648 int n; 649 GlyphPtr glyph; 650 int x, y; 651 652 x = 0; 653 y = 0; 654 extents->x1 = MAXSHORT; 655 extents->x2 = MINSHORT; 656 extents->y1 = MAXSHORT; 657 extents->y2 = MINSHORT; 658 while (nlist--) 659 { 660 x += list->xOff; 661 y += list->yOff; 662 n = list->len; 663 list++; 664 while (n--) 665 { 666 glyph = *glyphs++; 667 x1 = x - glyph->info.x; 668 if (x1 < MINSHORT) 669 x1 = MINSHORT; 670 y1 = y - glyph->info.y; 671 if (y1 < MINSHORT) 672 y1 = MINSHORT; 673 x2 = x1 + glyph->info.width; 674 if (x2 > MAXSHORT) 675 x2 = MAXSHORT; 676 y2 = y1 + glyph->info.height; 677 if (y2 > MAXSHORT) 678 y2 = MAXSHORT; 679 if (x1 < extents->x1) 680 extents->x1 = x1; 681 if (x2 > extents->x2) 682 extents->x2 = x2; 683 if (y1 < extents->y1) 684 extents->y1 = y1; 685 if (y2 > extents->y2) 686 extents->y2 = y2; 687 x += glyph->info.xOff; 688 y += glyph->info.yOff; 689 } 690 } 691} 692 693void 694exaGlyphs (CARD8 op, 695 PicturePtr pSrc, 696 PicturePtr pDst, 697 PictFormatPtr maskFormat, 698 INT16 xSrc, 699 INT16 ySrc, 700 int nlist, 701 GlyphListPtr list, 702 GlyphPtr *glyphs) 703{ 704 PixmapPtr pMaskPixmap = 0; 705 PicturePtr pMask = NULL; 706 ScreenPtr pScreen = pDst->pDrawable->pScreen; 707 int width = 0, height = 0; 708 int x, y; 709 int first_xOff = list->xOff, first_yOff = list->yOff; 710 int n; 711 GlyphPtr glyph; 712 int error; 713 BoxRec extents = {0, 0, 0, 0}; 714 CARD32 component_alpha; 715 ExaGlyphBuffer buffer; 716 717 if (maskFormat) 718 { 719 ExaScreenPriv(pScreen); 720 GCPtr pGC; 721 xRectangle rect; 722 723 GlyphExtents (nlist, list, glyphs, &extents); 724 725 if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) 726 return; 727 width = extents.x2 - extents.x1; 728 height = extents.y2 - extents.y1; 729 730 if (maskFormat->depth == 1) { 731 PictFormatPtr a8Format = PictureMatchFormat (pScreen, 8, PICT_a8); 732 733 if (a8Format) 734 maskFormat = a8Format; 735 } 736 737 pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 738 maskFormat->depth, 739 CREATE_PIXMAP_USAGE_SCRATCH); 740 if (!pMaskPixmap) 741 return; 742 component_alpha = NeedsComponent(maskFormat->format); 743 pMask = CreatePicture (0, &pMaskPixmap->drawable, 744 maskFormat, CPComponentAlpha, &component_alpha, 745 serverClient, &error); 746 if (!pMask || 747 (!component_alpha && pExaScr->info->CheckComposite && 748 !(*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, NULL, pMask))) 749 { 750 PictFormatPtr argbFormat; 751 752 (*pScreen->DestroyPixmap) (pMaskPixmap); 753 754 if (!pMask) 755 return; 756 757 /* The driver can't seem to composite to a8, let's try argb (but 758 * without component-alpha) */ 759 FreePicture ((pointer) pMask, (XID) 0); 760 761 argbFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8); 762 763 if (argbFormat) 764 maskFormat = argbFormat; 765 766 pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 767 maskFormat->depth, 768 CREATE_PIXMAP_USAGE_SCRATCH); 769 if (!pMaskPixmap) 770 return; 771 772 pMask = CreatePicture (0, &pMaskPixmap->drawable, maskFormat, 0, 0, 773 serverClient, &error); 774 if (!pMask) { 775 (*pScreen->DestroyPixmap) (pMaskPixmap); 776 return; 777 } 778 } 779 pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen); 780 ValidateGC (&pMaskPixmap->drawable, pGC); 781 rect.x = 0; 782 rect.y = 0; 783 rect.width = width; 784 rect.height = height; 785 (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect); 786 FreeScratchGC (pGC); 787 x = -extents.x1; 788 y = -extents.y1; 789 } 790 else 791 { 792 x = 0; 793 y = 0; 794 } 795 buffer.count = 0; 796 buffer.mask = NULL; 797 while (nlist--) 798 { 799 x += list->xOff; 800 y += list->yOff; 801 n = list->len; 802 while (n--) 803 { 804 glyph = *glyphs++; 805 806 if (glyph->info.width > 0 && glyph->info.height > 0) 807 { 808 /* pGlyph->info.{x,y} compensate for empty space in the glyph. */ 809 if (maskFormat) 810 { 811 if (exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask, 812 0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y) == ExaGlyphNeedFlush) 813 { 814 exaGlyphsToMask(pMask, &buffer); 815 exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask, 816 0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y); 817 } 818 } 819 else 820 { 821 if (exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst, 822 xSrc + (x - glyph->info.x) - first_xOff, ySrc + (y - glyph->info.y) - first_yOff, 823 0, 0, x - glyph->info.x, y - glyph->info.y) 824 == ExaGlyphNeedFlush) 825 { 826 exaGlyphsToDst(pSrc, pDst, &buffer); 827 exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst, 828 xSrc + (x - glyph->info.x) - first_xOff, ySrc + (y - glyph->info.y) - first_yOff, 829 0, 0, x - glyph->info.x, y - glyph->info.y); 830 } 831 } 832 } 833 834 x += glyph->info.xOff; 835 y += glyph->info.yOff; 836 } 837 list++; 838 } 839 840 if (buffer.count) { 841 if (maskFormat) 842 exaGlyphsToMask(pMask, &buffer); 843 else 844 exaGlyphsToDst(pSrc, pDst, &buffer); 845 } 846 847 if (maskFormat) 848 { 849 x = extents.x1; 850 y = extents.y1; 851 CompositePicture (op, 852 pSrc, 853 pMask, 854 pDst, 855 xSrc + x - first_xOff, 856 ySrc + y - first_yOff, 857 0, 0, 858 x, y, 859 width, height); 860 FreePicture ((pointer) pMask, (XID) 0); 861 (*pScreen->DestroyPixmap) (pMaskPixmap); 862 } 863} 864