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