1/* 2 * Copyright © 2001 Keith Packard 3 * 4 * Partly based on code that is Copyright © The XFree86 Project 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 Keith Packard not be used in 11 * advertising or publicity pertaining to distribution of the software without 12 * specific, written prior permission. Keith Packard makes no 13 * representations about the suitability of this software for any purpose. It 14 * is provided "as is" without express or implied warranty. 15 * 16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22 * PERFORMANCE OF THIS SOFTWARE. 23 */ 24 25#ifdef HAVE_DIX_CONFIG_H 26#include <dix-config.h> 27#endif 28 29#include <stdlib.h> 30 31#include "exa_priv.h" 32 33#include "mipict.h" 34 35#if DEBUG_TRACE_FALL 36static void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n) 37{ 38 char format[20]; 39 char size[20]; 40 char loc; 41 int temp; 42 43 if (!pict) { 44 snprintf(string, n, "None"); 45 return; 46 } 47 48 switch (pict->format) 49 { 50 case PICT_a8r8g8b8: 51 snprintf(format, 20, "ARGB8888"); 52 break; 53 case PICT_x8r8g8b8: 54 snprintf(format, 20, "XRGB8888"); 55 break; 56 case PICT_b8g8r8a8: 57 snprintf(format, 20, "BGRA8888"); 58 break; 59 case PICT_b8g8r8x8: 60 snprintf(format, 20, "BGRX8888"); 61 break; 62 case PICT_r5g6b5: 63 snprintf(format, 20, "RGB565 "); 64 break; 65 case PICT_x1r5g5b5: 66 snprintf(format, 20, "RGB555 "); 67 break; 68 case PICT_a8: 69 snprintf(format, 20, "A8 "); 70 break; 71 case PICT_a1: 72 snprintf(format, 20, "A1 "); 73 break; 74 default: 75 snprintf(format, 20, "0x%x", (int)pict->format); 76 break; 77 } 78 79 if (pict->pDrawable) { 80 loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm'; 81 82 snprintf(size, 20, "%dx%d%s", pict->pDrawable->width, 83 pict->pDrawable->height, pict->repeat ? 84 " R" : ""); 85 } else { 86 loc = '-'; 87 88 snprintf(size, 20, "%s", pict->repeat ? " R" : ""); 89 } 90 91 snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format, size); 92} 93 94static void 95exaPrintCompositeFallback(CARD8 op, 96 PicturePtr pSrc, 97 PicturePtr pMask, 98 PicturePtr pDst) 99{ 100 char sop[20]; 101 char srcdesc[40], maskdesc[40], dstdesc[40]; 102 103 switch(op) 104 { 105 case PictOpSrc: 106 sprintf(sop, "Src"); 107 break; 108 case PictOpOver: 109 sprintf(sop, "Over"); 110 break; 111 default: 112 sprintf(sop, "0x%x", (int)op); 113 break; 114 } 115 116 exaCompositeFallbackPictDesc(pSrc, srcdesc, 40); 117 exaCompositeFallbackPictDesc(pMask, maskdesc, 40); 118 exaCompositeFallbackPictDesc(pDst, dstdesc, 40); 119 120 ErrorF("Composite fallback: op %s, \n" 121 " src %s, \n" 122 " mask %s, \n" 123 " dst %s, \n", 124 sop, srcdesc, maskdesc, dstdesc); 125} 126#endif /* DEBUG_TRACE_FALL */ 127 128Bool 129exaOpReadsDestination (CARD8 op) 130{ 131 /* FALSE (does not read destination) is the list of ops in the protocol 132 * document with "0" in the "Fb" column and no "Ab" in the "Fa" column. 133 * That's just Clear and Src. ReduceCompositeOp() will already have 134 * converted con/disjoint clear/src to Clear or Src. 135 */ 136 switch (op) { 137 case PictOpClear: 138 case PictOpSrc: 139 return FALSE; 140 default: 141 return TRUE; 142 } 143} 144 145 146static Bool 147exaGetPixelFromRGBA(CARD32 *pixel, 148 CARD16 red, 149 CARD16 green, 150 CARD16 blue, 151 CARD16 alpha, 152 PictFormatPtr pFormat) 153{ 154 int rbits, bbits, gbits, abits; 155 int rshift, bshift, gshift, ashift; 156 157 *pixel = 0; 158 159 if (!PICT_FORMAT_COLOR(pFormat->format) && 160 PICT_FORMAT_TYPE(pFormat->format) != PICT_TYPE_A) 161 return FALSE; 162 163 rbits = PICT_FORMAT_R(pFormat->format); 164 gbits = PICT_FORMAT_G(pFormat->format); 165 bbits = PICT_FORMAT_B(pFormat->format); 166 abits = PICT_FORMAT_A(pFormat->format); 167 168 rshift = pFormat->direct.red; 169 gshift = pFormat->direct.green; 170 bshift = pFormat->direct.blue; 171 ashift = pFormat->direct.alpha; 172 173 *pixel |= ( blue >> (16 - bbits)) << bshift; 174 *pixel |= ( red >> (16 - rbits)) << rshift; 175 *pixel |= (green >> (16 - gbits)) << gshift; 176 *pixel |= (alpha >> (16 - abits)) << ashift; 177 178 return TRUE; 179} 180 181static Bool 182exaGetRGBAFromPixel(CARD32 pixel, 183 CARD16 *red, 184 CARD16 *green, 185 CARD16 *blue, 186 CARD16 *alpha, 187 PictFormatPtr pFormat, 188 PictFormatShort format) 189{ 190 int rbits, bbits, gbits, abits; 191 int rshift, bshift, gshift, ashift; 192 193 if (!PICT_FORMAT_COLOR(format) && PICT_FORMAT_TYPE(format) != PICT_TYPE_A) 194 return FALSE; 195 196 rbits = PICT_FORMAT_R(format); 197 gbits = PICT_FORMAT_G(format); 198 bbits = PICT_FORMAT_B(format); 199 abits = PICT_FORMAT_A(format); 200 201 if (pFormat) { 202 rshift = pFormat->direct.red; 203 gshift = pFormat->direct.green; 204 bshift = pFormat->direct.blue; 205 ashift = pFormat->direct.alpha; 206 } else if (format == PICT_a8r8g8b8) { 207 rshift = 16; 208 gshift = 8; 209 bshift = 0; 210 ashift = 24; 211 } else 212 FatalError("EXA bug: exaGetRGBAFromPixel() doesn't match " 213 "createSourcePicture()\n"); 214 215 if (rbits) { 216 *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits); 217 while (rbits < 16) { 218 *red |= *red >> rbits; 219 rbits <<= 1; 220 } 221 222 *green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits); 223 while (gbits < 16) { 224 *green |= *green >> gbits; 225 gbits <<= 1; 226 } 227 228 *blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits); 229 while (bbits < 16) { 230 *blue |= *blue >> bbits; 231 bbits <<= 1; 232 } 233 } else { 234 *red = 0x0000; 235 *green = 0x0000; 236 *blue = 0x0000; 237 } 238 239 if (abits) { 240 *alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits); 241 while (abits < 16) { 242 *alpha |= *alpha >> abits; 243 abits <<= 1; 244 } 245 } else 246 *alpha = 0xffff; 247 248 return TRUE; 249} 250 251static int 252exaTryDriverSolidFill(PicturePtr pSrc, 253 PicturePtr pDst, 254 INT16 xSrc, 255 INT16 ySrc, 256 INT16 xDst, 257 INT16 yDst, 258 CARD16 width, 259 CARD16 height) 260{ 261 ExaScreenPriv (pDst->pDrawable->pScreen); 262 RegionRec region; 263 BoxPtr pbox; 264 int nbox; 265 int dst_off_x, dst_off_y; 266 PixmapPtr pSrcPix, pDstPix; 267 ExaPixmapPrivPtr pDstExaPix; 268 CARD32 pixel; 269 CARD16 red, green, blue, alpha; 270 271 pDstPix = exaGetDrawablePixmap (pDst->pDrawable); 272 pDstExaPix = ExaGetPixmapPriv(pDstPix); 273 274 /* Check whether the accelerator can use the destination pixmap. 275 */ 276 if (pDstExaPix->accel_blocked) 277 { 278 return -1; 279 } 280 281 xDst += pDst->pDrawable->x; 282 yDst += pDst->pDrawable->y; 283 if (pSrc->pDrawable) { 284 xSrc += pSrc->pDrawable->x; 285 ySrc += pSrc->pDrawable->y; 286 } 287 288 if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, 289 xSrc, ySrc, 0, 0, xDst, yDst, 290 width, height)) 291 return 1; 292 293 exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); 294 295 RegionTranslate(®ion, dst_off_x, dst_off_y); 296 297 if (pSrc->pDrawable) { 298 pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable); 299 pixel = exaGetPixmapFirstPixel (pSrcPix); 300 } else 301 pixel = pSrc->pSourcePict->solidFill.color; 302 303 if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha, 304 pSrc->pFormat, pSrc->format) || 305 !exaGetPixelFromRGBA(&pixel, red, green, blue, alpha, 306 pDst->pFormat)) 307 { 308 RegionUninit(®ion); 309 return -1; 310 } 311 312 if (pExaScr->do_migration) { 313 ExaMigrationRec pixmaps[1]; 314 315 pixmaps[0].as_dst = TRUE; 316 pixmaps[0].as_src = FALSE; 317 pixmaps[0].pPix = pDstPix; 318 pixmaps[0].pReg = ®ion; 319 exaDoMigration(pixmaps, 1, TRUE); 320 } 321 322 if (!exaPixmapHasGpuCopy(pDstPix)) { 323 RegionUninit(®ion); 324 return 0; 325 } 326 327 if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel)) 328 { 329 RegionUninit(®ion); 330 return -1; 331 } 332 333 nbox = RegionNumRects(®ion); 334 pbox = RegionRects(®ion); 335 336 while (nbox--) 337 { 338 (*pExaScr->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, pbox->y2); 339 pbox++; 340 } 341 342 (*pExaScr->info->DoneSolid) (pDstPix); 343 exaMarkSync(pDst->pDrawable->pScreen); 344 345 RegionUninit(®ion); 346 return 1; 347} 348 349static int 350exaTryDriverCompositeRects(CARD8 op, 351 PicturePtr pSrc, 352 PicturePtr pMask, 353 PicturePtr pDst, 354 int nrect, 355 ExaCompositeRectPtr rects) 356{ 357 ExaScreenPriv (pDst->pDrawable->pScreen); 358 int src_off_x = 0, src_off_y = 0, mask_off_x = 0, mask_off_y = 0; 359 int dst_off_x, dst_off_y; 360 PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; 361 ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; 362 363 if (!pExaScr->info->PrepareComposite) 364 return -1; 365 366 if (pSrc->pDrawable) { 367 pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); 368 pSrcExaPix = ExaGetPixmapPriv(pSrcPix); 369 } 370 371 if (pMask && pMask->pDrawable) { 372 pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); 373 pMaskExaPix = ExaGetPixmapPriv(pMaskPix); 374 } 375 376 pDstPix = exaGetDrawablePixmap(pDst->pDrawable); 377 pDstExaPix = ExaGetPixmapPriv(pDstPix); 378 379 /* Check whether the accelerator can use these pixmaps. 380 * FIXME: If it cannot, use temporary pixmaps so that the drawing 381 * happens within limits. 382 */ 383 if (pDstExaPix->accel_blocked || 384 (pSrcExaPix && pSrcExaPix->accel_blocked) || 385 (pMaskExaPix && pMaskExaPix->accel_blocked)) 386 { 387 return -1; 388 } 389 390 if (pExaScr->info->CheckComposite && 391 !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) 392 { 393 return -1; 394 } 395 396 if (pExaScr->do_migration) { 397 ExaMigrationRec pixmaps[3]; 398 int i = 0; 399 400 pixmaps[i].as_dst = TRUE; 401 pixmaps[i].as_src = exaOpReadsDestination(op); 402 pixmaps[i].pPix = pDstPix; 403 pixmaps[i].pReg = NULL; 404 i++; 405 406 if (pSrcPix) { 407 pixmaps[i].as_dst = FALSE; 408 pixmaps[i].as_src = TRUE; 409 pixmaps[i].pPix = pSrcPix; 410 pixmaps[i].pReg = NULL; 411 i++; 412 } 413 414 if (pMaskPix) { 415 pixmaps[i].as_dst = FALSE; 416 pixmaps[i].as_src = TRUE; 417 pixmaps[i].pPix = pMaskPix; 418 pixmaps[i].pReg = NULL; 419 i++; 420 } 421 422 exaDoMigration(pixmaps, i, TRUE); 423 } 424 425 pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y); 426 if (!pDstPix) 427 return 0; 428 429 if (pSrcPix) { 430 pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); 431 if (!pSrcPix) 432 return 0; 433 } 434 435 if (pMaskPix) { 436 pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, &mask_off_y); 437 if (!pMaskPix) 438 return 0; 439 } 440 441 if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, 442 pMaskPix, pDstPix)) 443 return -1; 444 445 while (nrect--) 446 { 447 INT16 xDst = rects->xDst + pDst->pDrawable->x; 448 INT16 yDst = rects->yDst + pDst->pDrawable->y; 449 INT16 xMask = rects->xMask; 450 INT16 yMask = rects->yMask; 451 INT16 xSrc = rects->xSrc; 452 INT16 ySrc = rects->ySrc; 453 RegionRec region; 454 BoxPtr pbox; 455 int nbox; 456 457 if (pMaskPix) { 458 xMask += pMask->pDrawable->x; 459 yMask += pMask->pDrawable->y; 460 } 461 462 if (pSrcPix) { 463 xSrc += pSrc->pDrawable->x; 464 ySrc += pSrc->pDrawable->y; 465 } 466 467 if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, 468 xSrc, ySrc, xMask, yMask, xDst, yDst, 469 rects->width, rects->height)) 470 goto next_rect; 471 472 RegionTranslate(®ion, dst_off_x, dst_off_y); 473 474 nbox = RegionNumRects(®ion); 475 pbox = RegionRects(®ion); 476 477 xMask = xMask + mask_off_x - xDst - dst_off_x; 478 yMask = yMask + mask_off_y - yDst - dst_off_y; 479 xSrc = xSrc + src_off_x - xDst - dst_off_x; 480 ySrc = ySrc + src_off_y - yDst - dst_off_y; 481 482 while (nbox--) 483 { 484 (*pExaScr->info->Composite) (pDstPix, 485 pbox->x1 + xSrc, 486 pbox->y1 + ySrc, 487 pbox->x1 + xMask, 488 pbox->y1 + yMask, 489 pbox->x1, 490 pbox->y1, 491 pbox->x2 - pbox->x1, 492 pbox->y2 - pbox->y1); 493 pbox++; 494 } 495 496 next_rect: 497 RegionUninit(®ion); 498 499 rects++; 500 } 501 502 (*pExaScr->info->DoneComposite) (pDstPix); 503 exaMarkSync(pDst->pDrawable->pScreen); 504 505 return 1; 506} 507 508/** 509 * Copy a number of rectangles from source to destination in a single 510 * operation. This is specialized for glyph rendering: we don't have the 511 * special-case fallbacks found in exaComposite() - if the driver can support 512 * it, we use the driver functionality, otherwise we fall back straight to 513 * software. 514 */ 515void 516exaCompositeRects(CARD8 op, 517 PicturePtr pSrc, 518 PicturePtr pMask, 519 PicturePtr pDst, 520 int nrect, 521 ExaCompositeRectPtr rects) 522{ 523 ExaScreenPriv (pDst->pDrawable->pScreen); 524 int n; 525 ExaCompositeRectPtr r; 526 int ret; 527 528 /* If we get a mask, that means we're rendering to the exaGlyphs 529 * destination directly, so the damage layer takes care of this. 530 */ 531 if (!pMask) { 532 RegionRec region; 533 int x1 = MAXSHORT; 534 int y1 = MAXSHORT; 535 int x2 = MINSHORT; 536 int y2 = MINSHORT; 537 BoxRec box; 538 539 /* We have to manage the damage ourselves, since CompositeRects isn't 540 * something in the screen that can be managed by the damage extension, 541 * and EXA depends on damage to track what needs to be migrated between 542 * the gpu and the cpu. 543 */ 544 545 /* Compute the overall extents of the composited region - we're making 546 * the assumption here that we are compositing a bunch of glyphs that 547 * cluster closely together and damaging each glyph individually would 548 * be a loss compared to damaging the bounding box. 549 */ 550 n = nrect; 551 r = rects; 552 while (n--) { 553 int rect_x2 = r->xDst + r->width; 554 int rect_y2 = r->yDst + r->height; 555 556 if (r->xDst < x1) x1 = r->xDst; 557 if (r->yDst < y1) y1 = r->yDst; 558 if (rect_x2 > x2) x2 = rect_x2; 559 if (rect_y2 > y2) y2 = rect_y2; 560 561 r++; 562 } 563 564 if (x2 <= x1 || y2 <= y1) 565 return; 566 567 box.x1 = x1; 568 box.x2 = x2 < MAXSHORT ? x2 : MAXSHORT; 569 box.y1 = y1; 570 box.y2 = y2 < MAXSHORT ? y2 : MAXSHORT; 571 572 /* The pixmap migration code relies on pendingDamage indicating 573 * the bounds of the current rendering, so we need to force 574 * the actual damage into that region before we do anything, and 575 * (see use of DamagePendingRegion in exaCopyDirty) 576 */ 577 578 RegionInit(®ion, &box, 1); 579 580 DamageRegionAppend(pDst->pDrawable, ®ion); 581 582 RegionUninit(®ion); 583 } 584 585 /************************************************************/ 586 587 ValidatePicture (pSrc); 588 if (pMask) 589 ValidatePicture (pMask); 590 ValidatePicture (pDst); 591 592 ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, rects); 593 594 if (ret != 1) { 595 if (ret == -1 && op == PictOpOver && pMask && pMask->componentAlpha && 596 (!pExaScr->info->CheckComposite || 597 ((*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask, 598 pDst) && 599 (*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst)))) { 600 ret = exaTryDriverCompositeRects(PictOpOutReverse, pSrc, pMask, 601 pDst, nrect, rects); 602 if (ret == 1) { 603 op = PictOpAdd; 604 ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, 605 rects); 606 } 607 } 608 609 if (ret != 1) { 610 n = nrect; 611 r = rects; 612 while (n--) { 613 ExaCheckComposite (op, pSrc, pMask, pDst, 614 r->xSrc, r->ySrc, 615 r->xMask, r->yMask, 616 r->xDst, r->yDst, 617 r->width, r->height); 618 r++; 619 } 620 } 621 } 622 623 /************************************************************/ 624 625 if (!pMask) { 626 /* Now we have to flush the damage out from pendingDamage => damage 627 * Calling DamageRegionProcessPending has that effect. 628 */ 629 630 DamageRegionProcessPending(pDst->pDrawable); 631 } 632} 633 634static int 635exaTryDriverComposite(CARD8 op, 636 PicturePtr pSrc, 637 PicturePtr pMask, 638 PicturePtr pDst, 639 INT16 xSrc, 640 INT16 ySrc, 641 INT16 xMask, 642 INT16 yMask, 643 INT16 xDst, 644 INT16 yDst, 645 CARD16 width, 646 CARD16 height) 647{ 648 ExaScreenPriv (pDst->pDrawable->pScreen); 649 RegionRec region; 650 BoxPtr pbox; 651 int nbox; 652 int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; 653 PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; 654 ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; 655 656 if (pSrc->pDrawable) { 657 pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); 658 pSrcExaPix = ExaGetPixmapPriv(pSrcPix); 659 } 660 661 pDstPix = exaGetDrawablePixmap(pDst->pDrawable); 662 pDstExaPix = ExaGetPixmapPriv(pDstPix); 663 664 if (pMask && pMask->pDrawable) { 665 pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); 666 pMaskExaPix = ExaGetPixmapPriv(pMaskPix); 667 } 668 669 /* Check whether the accelerator can use these pixmaps. 670 * FIXME: If it cannot, use temporary pixmaps so that the drawing 671 * happens within limits. 672 */ 673 if (pDstExaPix->accel_blocked || 674 (pSrcExaPix && pSrcExaPix->accel_blocked) || 675 (pMaskExaPix && (pMaskExaPix->accel_blocked))) 676 { 677 return -1; 678 } 679 680 xDst += pDst->pDrawable->x; 681 yDst += pDst->pDrawable->y; 682 683 if (pMaskPix) { 684 xMask += pMask->pDrawable->x; 685 yMask += pMask->pDrawable->y; 686 } 687 688 if (pSrcPix) { 689 xSrc += pSrc->pDrawable->x; 690 ySrc += pSrc->pDrawable->y; 691 } 692 693 if (pExaScr->info->CheckComposite && 694 !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) 695 { 696 return -1; 697 } 698 699 if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, 700 xSrc, ySrc, xMask, yMask, xDst, yDst, 701 width, height)) 702 return 1; 703 704 exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); 705 706 RegionTranslate(®ion, dst_off_x, dst_off_y); 707 708 if (pExaScr->do_migration) { 709 ExaMigrationRec pixmaps[3]; 710 int i = 0; 711 712 pixmaps[i].as_dst = TRUE; 713 pixmaps[i].as_src = exaOpReadsDestination(op); 714 pixmaps[i].pPix = pDstPix; 715 pixmaps[i].pReg = pixmaps[0].as_src ? NULL : ®ion; 716 i++; 717 718 if (pSrcPix) { 719 pixmaps[i].as_dst = FALSE; 720 pixmaps[i].as_src = TRUE; 721 pixmaps[i].pPix = pSrcPix; 722 pixmaps[i].pReg = NULL; 723 i++; 724 } 725 726 if (pMaskPix) { 727 pixmaps[i].as_dst = FALSE; 728 pixmaps[i].as_src = TRUE; 729 pixmaps[i].pPix = pMaskPix; 730 pixmaps[i].pReg = NULL; 731 i++; 732 } 733 734 exaDoMigration(pixmaps, i, TRUE); 735 } 736 737 if (pSrcPix) { 738 pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); 739 if (!pSrcPix) { 740 RegionUninit(®ion); 741 return 0; 742 } 743 } 744 745 if (pMaskPix) { 746 pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, 747 &mask_off_y); 748 if (!pMaskPix) { 749 RegionUninit(®ion); 750 return 0; 751 } 752 } 753 754 if (!exaPixmapHasGpuCopy(pDstPix)) { 755 RegionUninit(®ion); 756 return 0; 757 } 758 759 if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, 760 pMaskPix, pDstPix)) 761 { 762 RegionUninit(®ion); 763 return -1; 764 } 765 766 nbox = RegionNumRects(®ion); 767 pbox = RegionRects(®ion); 768 769 xMask = xMask + mask_off_x - xDst - dst_off_x; 770 yMask = yMask + mask_off_y - yDst - dst_off_y; 771 772 xSrc = xSrc + src_off_x - xDst - dst_off_x; 773 ySrc = ySrc + src_off_y - yDst - dst_off_y; 774 775 while (nbox--) 776 { 777 (*pExaScr->info->Composite) (pDstPix, 778 pbox->x1 + xSrc, 779 pbox->y1 + ySrc, 780 pbox->x1 + xMask, 781 pbox->y1 + yMask, 782 pbox->x1, 783 pbox->y1, 784 pbox->x2 - pbox->x1, 785 pbox->y2 - pbox->y1); 786 pbox++; 787 } 788 (*pExaScr->info->DoneComposite) (pDstPix); 789 exaMarkSync(pDst->pDrawable->pScreen); 790 791 RegionUninit(®ion); 792 return 1; 793} 794 795/** 796 * exaTryMagicTwoPassCompositeHelper implements PictOpOver using two passes of 797 * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component 798 * alpha and limited 1-tmu cards. 799 * 800 * From http://anholt.livejournal.com/32058.html: 801 * 802 * The trouble is that component-alpha rendering requires two different sources 803 * for blending: one for the source value to the blender, which is the 804 * per-channel multiplication of source and mask, and one for the source alpha 805 * for multiplying with the destination channels, which is the multiplication 806 * of the source channels by the mask alpha. So the equation for Over is: 807 * 808 * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A 809 * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R 810 * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G 811 * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B 812 * 813 * But we can do some simpler operations, right? How about PictOpOutReverse, 814 * which has a source factor of 0 and dest factor of (1 - source alpha). We 815 * can get the source alpha value (srca.X = src.A * mask.X) out of the texture 816 * blenders pretty easily. So we can do a component-alpha OutReverse, which 817 * gets us: 818 * 819 * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A 820 * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R 821 * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G 822 * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B 823 * 824 * OK. And if an op doesn't use the source alpha value for the destination 825 * factor, then we can do the channel multiplication in the texture blenders 826 * to get the source value, and ignore the source alpha that we wouldn't use. 827 * We've supported this in the Radeon driver for a long time. An example would 828 * be PictOpAdd, which does: 829 * 830 * dst.A = src.A * mask.A + dst.A 831 * dst.R = src.R * mask.R + dst.R 832 * dst.G = src.G * mask.G + dst.G 833 * dst.B = src.B * mask.B + dst.B 834 * 835 * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right 836 * after it, we get: 837 * 838 * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A) 839 * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R) 840 * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G) 841 * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B) 842 */ 843 844static int 845exaTryMagicTwoPassCompositeHelper(CARD8 op, 846 PicturePtr pSrc, 847 PicturePtr pMask, 848 PicturePtr pDst, 849 INT16 xSrc, 850 INT16 ySrc, 851 INT16 xMask, 852 INT16 yMask, 853 INT16 xDst, 854 INT16 yDst, 855 CARD16 width, 856 CARD16 height) 857{ 858 ExaScreenPriv (pDst->pDrawable->pScreen); 859 860 assert(op == PictOpOver); 861 862 if (pExaScr->info->CheckComposite && 863 (!(*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask, 864 pDst) || 865 !(*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst))) 866 { 867 return -1; 868 } 869 870 /* Now, we think we should be able to accelerate this operation. First, 871 * composite the destination to be the destination times the source alpha 872 * factors. 873 */ 874 exaComposite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, 875 xDst, yDst, width, height); 876 877 /* Then, add in the source value times the destination alpha factors (1.0). 878 */ 879 exaComposite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, 880 xDst, yDst, width, height); 881 882 return 1; 883} 884 885void 886exaComposite(CARD8 op, 887 PicturePtr pSrc, 888 PicturePtr pMask, 889 PicturePtr pDst, 890 INT16 xSrc, 891 INT16 ySrc, 892 INT16 xMask, 893 INT16 yMask, 894 INT16 xDst, 895 INT16 yDst, 896 CARD16 width, 897 CARD16 height) 898{ 899 ExaScreenPriv (pDst->pDrawable->pScreen); 900 int ret = -1; 901 Bool saveSrcRepeat = pSrc->repeat; 902 Bool saveMaskRepeat = pMask ? pMask->repeat : 0; 903 RegionRec region; 904 905 if (pExaScr->swappedOut) 906 goto fallback; 907 908 /* Remove repeat in source if useless */ 909 if (pSrc->pDrawable && pSrc->repeat && !pSrc->transform && xSrc >= 0 && 910 (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 && 911 (ySrc + height) <= pSrc->pDrawable->height) 912 pSrc->repeat = 0; 913 914 if (!pMask && !pSrc->alphaMap && !pDst->alphaMap && 915 (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) 916 { 917 if (pSrc->pDrawable ? 918 (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && 919 pSrc->repeat) : 920 (pSrc->pSourcePict->type == SourcePictTypeSolidFill)) 921 { 922 ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst, 923 width, height); 924 if (ret == 1) 925 goto done; 926 } else if (pSrc->pDrawable && !pSrc->transform && 927 ((op == PictOpSrc && 928 (pSrc->format == pDst->format || 929 (PICT_FORMAT_COLOR(pDst->format) && 930 PICT_FORMAT_COLOR(pSrc->format) && 931 pDst->format == PICT_FORMAT(PICT_FORMAT_BPP(pSrc->format), 932 PICT_FORMAT_TYPE(pSrc->format), 933 0, 934 PICT_FORMAT_R(pSrc->format), 935 PICT_FORMAT_G(pSrc->format), 936 PICT_FORMAT_B(pSrc->format))))) || 937 (op == PictOpOver && pSrc->format == pDst->format && 938 !PICT_FORMAT_A(pSrc->format)))) 939 { 940 if (!pSrc->repeat && xSrc >= 0 && ySrc >= 0 && 941 (xSrc + width <= pSrc->pDrawable->width) && 942 (ySrc + height <= pSrc->pDrawable->height)) 943 { 944 Bool ret; 945 xDst += pDst->pDrawable->x; 946 yDst += pDst->pDrawable->y; 947 xSrc += pSrc->pDrawable->x; 948 ySrc += pSrc->pDrawable->y; 949 950 if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, 951 xSrc, ySrc, xMask, yMask, xDst, 952 yDst, width, height)) 953 goto done; 954 955 ret = exaHWCopyNtoN(pSrc->pDrawable, pDst->pDrawable, NULL, 956 RegionRects(®ion), RegionNumRects(®ion), 957 xSrc - xDst, ySrc - yDst, FALSE, FALSE); 958 RegionUninit(®ion); 959 960 /* Reset values to their original values. */ 961 xDst -= pDst->pDrawable->x; 962 yDst -= pDst->pDrawable->y; 963 xSrc -= pSrc->pDrawable->x; 964 ySrc -= pSrc->pDrawable->y; 965 966 if (!ret) 967 goto fallback; 968 969 goto done; 970 } 971 972 if (pSrc->repeat && pSrc->repeatType == RepeatNormal && 973 pSrc->pDrawable->type == DRAWABLE_PIXMAP) 974 { 975 DDXPointRec patOrg; 976 977 /* Let's see if the driver can do the repeat in one go */ 978 if (pExaScr->info->PrepareComposite && !pSrc->alphaMap && 979 !pDst->alphaMap) 980 { 981 ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, 982 ySrc, xMask, yMask, xDst, yDst, 983 width, height); 984 if (ret == 1) 985 goto done; 986 } 987 988 /* Now see if we can use exaFillRegionTiled() */ 989 xDst += pDst->pDrawable->x; 990 yDst += pDst->pDrawable->y; 991 xSrc += pSrc->pDrawable->x; 992 ySrc += pSrc->pDrawable->y; 993 994 if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, 995 ySrc, xMask, yMask, xDst, yDst, 996 width, height)) 997 goto done; 998 999 /* pattern origin is the point in the destination drawable 1000 * corresponding to (0,0) in the source */ 1001 patOrg.x = xDst - xSrc; 1002 patOrg.y = yDst - ySrc; 1003 1004 ret = exaFillRegionTiled(pDst->pDrawable, ®ion, 1005 (PixmapPtr)pSrc->pDrawable, 1006 &patOrg, FB_ALLONES, GXcopy, CT_NONE); 1007 1008 RegionUninit(®ion); 1009 1010 if (ret) 1011 goto done; 1012 1013 /* Let's be correct and restore the variables to their original state. */ 1014 xDst -= pDst->pDrawable->x; 1015 yDst -= pDst->pDrawable->y; 1016 xSrc -= pSrc->pDrawable->x; 1017 ySrc -= pSrc->pDrawable->y; 1018 } 1019 } 1020 } 1021 1022 /* Remove repeat in mask if useless */ 1023 if (pMask && pMask->pDrawable && pMask->repeat && !pMask->transform && 1024 xMask >= 0 && (xMask + width) <= pMask->pDrawable->width && 1025 yMask >= 0 && (yMask + height) <= pMask->pDrawable->height) 1026 pMask->repeat = 0; 1027 1028 if (pExaScr->info->PrepareComposite && 1029 !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap) 1030 { 1031 Bool isSrcSolid; 1032 1033 ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, 1034 yMask, xDst, yDst, width, height); 1035 if (ret == 1) 1036 goto done; 1037 1038 /* For generic masks and solid src pictures, mach64 can do Over in two 1039 * passes, similar to the component-alpha case. 1040 */ 1041 isSrcSolid = pSrc->pDrawable ? 1042 (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && 1043 pSrc->repeat) : 1044 (pSrc->pSourcePict->type == SourcePictTypeSolidFill); 1045 1046 /* If we couldn't do the Composite in a single pass, and it was a 1047 * component-alpha Over, see if we can do it in two passes with 1048 * an OutReverse and then an Add. 1049 */ 1050 if (ret == -1 && op == PictOpOver && pMask && 1051 (pMask->componentAlpha || isSrcSolid)) { 1052 ret = exaTryMagicTwoPassCompositeHelper(op, pSrc, pMask, pDst, 1053 xSrc, ySrc, 1054 xMask, yMask, xDst, yDst, 1055 width, height); 1056 if (ret == 1) 1057 goto done; 1058 } 1059 } 1060 1061fallback: 1062#if DEBUG_TRACE_FALL 1063 exaPrintCompositeFallback (op, pSrc, pMask, pDst); 1064#endif 1065 1066 ExaCheckComposite (op, pSrc, pMask, pDst, xSrc, ySrc, 1067 xMask, yMask, xDst, yDst, width, height); 1068 1069done: 1070 pSrc->repeat = saveSrcRepeat; 1071 if (pMask) 1072 pMask->repeat = saveMaskRepeat; 1073} 1074 1075/** 1076 * Same as miCreateAlphaPicture, except it uses ExaCheckPolyFillRect instead 1077 * of PolyFillRect to initialize the pixmap after creating it, to prevent 1078 * the pixmap from being migrated. 1079 * 1080 * See the comments about exaTrapezoids and exaTriangles. 1081 */ 1082static PicturePtr 1083exaCreateAlphaPicture (ScreenPtr pScreen, 1084 PicturePtr pDst, 1085 PictFormatPtr pPictFormat, 1086 CARD16 width, 1087 CARD16 height) 1088{ 1089 PixmapPtr pPixmap; 1090 PicturePtr pPicture; 1091 GCPtr pGC; 1092 int error; 1093 xRectangle rect; 1094 1095 if (width > 32767 || height > 32767) 1096 return 0; 1097 1098 if (!pPictFormat) 1099 { 1100 if (pDst->polyEdge == PolyEdgeSharp) 1101 pPictFormat = PictureMatchFormat (pScreen, 1, PICT_a1); 1102 else 1103 pPictFormat = PictureMatchFormat (pScreen, 8, PICT_a8); 1104 if (!pPictFormat) 1105 return 0; 1106 } 1107 1108 pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 1109 pPictFormat->depth, 0); 1110 if (!pPixmap) 1111 return 0; 1112 pGC = GetScratchGC (pPixmap->drawable.depth, pScreen); 1113 if (!pGC) 1114 { 1115 (*pScreen->DestroyPixmap) (pPixmap); 1116 return 0; 1117 } 1118 ValidateGC (&pPixmap->drawable, pGC); 1119 rect.x = 0; 1120 rect.y = 0; 1121 rect.width = width; 1122 rect.height = height; 1123 ExaCheckPolyFillRect (&pPixmap->drawable, pGC, 1, &rect); 1124 exaPixmapDirty (pPixmap, 0, 0, width, height); 1125 FreeScratchGC (pGC); 1126 pPicture = CreatePicture (0, &pPixmap->drawable, pPictFormat, 1127 0, 0, serverClient, &error); 1128 (*pScreen->DestroyPixmap) (pPixmap); 1129 return pPicture; 1130} 1131 1132/** 1133 * exaTrapezoids is essentially a copy of miTrapezoids that uses 1134 * exaCreateAlphaPicture instead of miCreateAlphaPicture. 1135 * 1136 * The problem with miCreateAlphaPicture is that it calls PolyFillRect 1137 * to initialize the contents after creating the pixmap, which 1138 * causes the pixmap to be moved in for acceleration. The subsequent 1139 * call to RasterizeTrapezoid won't be accelerated however, which 1140 * forces the pixmap to be moved out again. 1141 * 1142 * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect 1143 * to initialize the contents. 1144 */ 1145void 1146exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, 1147 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 1148 int ntrap, xTrapezoid *traps) 1149{ 1150 ScreenPtr pScreen = pDst->pDrawable->pScreen; 1151 PictureScreenPtr ps = GetPictureScreen(pScreen); 1152 BoxRec bounds; 1153 1154 if (maskFormat) { 1155 PicturePtr pPicture; 1156 INT16 xDst, yDst; 1157 INT16 xRel, yRel; 1158 1159 miTrapezoidBounds (ntrap, traps, &bounds); 1160 1161 if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 1162 return; 1163 1164 xDst = traps[0].left.p1.x >> 16; 1165 yDst = traps[0].left.p1.y >> 16; 1166 1167 pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat, 1168 bounds.x2 - bounds.x1, 1169 bounds.y2 - bounds.y1); 1170 if (!pPicture) 1171 return; 1172 1173 exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); 1174 for (; ntrap; ntrap--, traps++) 1175 if (xTrapezoidValid(traps)) 1176 (*ps->RasterizeTrapezoid) (pPicture, traps, 1177 -bounds.x1, -bounds.y1); 1178 exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); 1179 1180 xRel = bounds.x1 + xSrc - xDst; 1181 yRel = bounds.y1 + ySrc - yDst; 1182 CompositePicture (op, pSrc, pPicture, pDst, 1183 xRel, yRel, 0, 0, bounds.x1, bounds.y1, 1184 bounds.x2 - bounds.x1, 1185 bounds.y2 - bounds.y1); 1186 FreePicture (pPicture, 0); 1187 } else { 1188 if (pDst->polyEdge == PolyEdgeSharp) 1189 maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); 1190 else 1191 maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); 1192 for (; ntrap; ntrap--, traps++) 1193 exaTrapezoids (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps); 1194 } 1195} 1196 1197/** 1198 * exaTriangles is essentially a copy of miTriangles that uses 1199 * exaCreateAlphaPicture instead of miCreateAlphaPicture. 1200 * 1201 * The problem with miCreateAlphaPicture is that it calls PolyFillRect 1202 * to initialize the contents after creating the pixmap, which 1203 * causes the pixmap to be moved in for acceleration. The subsequent 1204 * call to AddTriangles won't be accelerated however, which forces the pixmap 1205 * to be moved out again. 1206 * 1207 * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect 1208 * to initialize the contents. 1209 */ 1210void 1211exaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst, 1212 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 1213 int ntri, xTriangle *tris) 1214{ 1215 ScreenPtr pScreen = pDst->pDrawable->pScreen; 1216 PictureScreenPtr ps = GetPictureScreen(pScreen); 1217 BoxRec bounds; 1218 1219 if (maskFormat) { 1220 PicturePtr pPicture; 1221 INT16 xDst, yDst; 1222 INT16 xRel, yRel; 1223 1224 miTriangleBounds (ntri, tris, &bounds); 1225 1226 if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 1227 return; 1228 1229 xDst = tris[0].p1.x >> 16; 1230 yDst = tris[0].p1.y >> 16; 1231 1232 pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat, 1233 bounds.x2 - bounds.x1, 1234 bounds.y2 - bounds.y1); 1235 if (!pPicture) 1236 return; 1237 1238 exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); 1239 (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris); 1240 exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); 1241 1242 xRel = bounds.x1 + xSrc - xDst; 1243 yRel = bounds.y1 + ySrc - yDst; 1244 CompositePicture (op, pSrc, pPicture, pDst, 1245 xRel, yRel, 0, 0, bounds.x1, bounds.y1, 1246 bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); 1247 FreePicture (pPicture, 0); 1248 } else { 1249 if (pDst->polyEdge == PolyEdgeSharp) 1250 maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); 1251 else 1252 maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); 1253 1254 for (; ntri; ntri--, tris++) 1255 exaTriangles (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris); 1256 } 1257} 1258