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