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