uxa-render.c revision fa225cbc
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 441#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC (1,6,99,1,0) 442#define IMAGE_FROM_PICT(P) image_from_pict(P, 0) 443#else 444#define IMAGE_FROM_PICT(P) image_from_pict(P, 0, 0) 445#endif 446 447static PicturePtr 448uxa_acquire_pattern (ScreenPtr pScreen, 449 PicturePtr pPict, 450 pixman_format_code_t format, 451 INT16 x, INT16 y, 452 CARD16 width, CARD16 height) 453{ 454 pixman_image_t *source, *image; 455 456 source = IMAGE_FROM_PICT (pPict); 457 if (!source) 458 return 0; 459 460 image = pixman_image_create_bits (format, width, height, NULL, 0); 461 if (!image) { 462 pixman_image_unref (source); 463 return 0; 464 } 465 466 pixman_image_composite (PIXMAN_OP_SRC, 467 source, NULL, image, 468 x, y, 469 0, 0, 470 0, 0, 471 width, height); 472 pixman_image_unref (source); 473 474 pPict = uxa_picture_from_pixman_image (pScreen, image, format); 475 pixman_image_unref (image); 476 477 return pPict; 478} 479 480static PicturePtr 481uxa_acquire_source (ScreenPtr pScreen, 482 PicturePtr pPict, 483 INT16 x, INT16 y, 484 CARD16 width, CARD16 height, 485 INT16 *out_x, INT16 *out_y) 486{ 487 if (pPict->pDrawable) { 488 *out_x = x + pPict->pDrawable->x; 489 *out_y = y + pPict->pDrawable->y; 490 return pPict; 491 } 492 493 *out_x = 0; 494 *out_y = 0; 495 return uxa_acquire_pattern (pScreen, pPict, 496 PICT_a8r8g8b8, x, y, width, height); 497} 498 499static PicturePtr 500uxa_acquire_mask (ScreenPtr pScreen, 501 PicturePtr pPict, 502 INT16 x, INT16 y, 503 INT16 width, INT16 height, 504 INT16 *out_x, INT16 *out_y) 505{ 506 if (pPict->pDrawable) { 507 *out_x = x + pPict->pDrawable->x; 508 *out_y = y + pPict->pDrawable->y; 509 return pPict; 510 } 511 512 *out_x = 0; 513 *out_y = 0; 514 return uxa_acquire_pattern (pScreen, pPict, 515 PICT_a8, x, y, width, height); 516} 517 518static int 519uxa_try_driver_composite_rects(CARD8 op, 520 PicturePtr pSrc, 521 PicturePtr pDst, 522 int nrect, 523 uxa_composite_rect_t *rects) 524{ 525 uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); 526 int src_off_x, src_off_y, dst_off_x, dst_off_y; 527 PixmapPtr pSrcPix, pDstPix; 528 529 if (!uxa_screen->info->prepare_composite || uxa_screen->swappedOut) 530 return -1; 531 532 if (uxa_screen->info->check_composite && 533 !(*uxa_screen->info->check_composite) (op, pSrc, NULL, pDst)) 534 { 535 return -1; 536 } 537 538 pDstPix = uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); 539 if (!pDstPix) 540 return 0; 541 542 pSrcPix = uxa_get_offscreen_pixmap(pSrc->pDrawable, &src_off_x, &src_off_y); 543 if (!pSrcPix) 544 return 0; 545 546 if (!(*uxa_screen->info->prepare_composite) (op, pSrc, NULL, pDst, pSrcPix, 547 NULL, pDstPix)) 548 return -1; 549 550 while (nrect--) 551 { 552 INT16 xDst = rects->xDst + pDst->pDrawable->x; 553 INT16 yDst = rects->yDst + pDst->pDrawable->y; 554 INT16 xSrc = rects->xSrc + pSrc->pDrawable->x; 555 INT16 ySrc = rects->ySrc + pSrc->pDrawable->y; 556 557 RegionRec region; 558 BoxPtr pbox; 559 int nbox; 560 561 if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, 562 xSrc, ySrc, 0, 0, xDst, yDst, 563 rects->width, rects->height)) 564 goto next_rect; 565 566 REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); 567 568 nbox = REGION_NUM_RECTS(®ion); 569 pbox = REGION_RECTS(®ion); 570 571 xSrc = xSrc + src_off_x - xDst - dst_off_x; 572 ySrc = ySrc + src_off_y - yDst - dst_off_y; 573 574 while (nbox--) 575 { 576 (*uxa_screen->info->composite) (pDstPix, 577 pbox->x1 + xSrc, 578 pbox->y1 + ySrc, 579 0, 0, 580 pbox->x1, 581 pbox->y1, 582 pbox->x2 - pbox->x1, 583 pbox->y2 - pbox->y1); 584 pbox++; 585 } 586 587 next_rect: 588 REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 589 590 rects++; 591 } 592 (*uxa_screen->info->done_composite) (pDstPix); 593 594 return 1; 595} 596 597/** 598 * Copy a number of rectangles from source to destination in a single 599 * operation. This is specialized for building a glyph mask: we don'y 600 * have a mask argument because we don't need it for that, and we 601 * don't have he special-case fallbacks found in uxa_composite() - if the 602 * driver can support it, we use the driver functionality, otherwise we 603 * fallback straight to software. 604 */ 605void 606uxa_composite_rects(CARD8 op, 607 PicturePtr pSrc, 608 PicturePtr pDst, 609 int nrect, 610 uxa_composite_rect_t *rects) 611{ 612 int n; 613 uxa_composite_rect_t *r; 614 615 /************************************************************/ 616 617 ValidatePicture (pSrc); 618 ValidatePicture (pDst); 619 620 if (uxa_try_driver_composite_rects(op, pSrc, pDst, nrect, rects) != 1) { 621 n = nrect; 622 r = rects; 623 while (n--) { 624 uxa_check_composite (op, pSrc, NULL, pDst, 625 r->xSrc, r->ySrc, 626 0, 0, 627 r->xDst, r->yDst, 628 r->width, r->height); 629 r++; 630 } 631 } 632 633 /************************************************************/ 634 635} 636 637static int 638uxa_try_driver_composite(CARD8 op, 639 PicturePtr pSrc, 640 PicturePtr pMask, 641 PicturePtr pDst, 642 INT16 xSrc, 643 INT16 ySrc, 644 INT16 xMask, 645 INT16 yMask, 646 INT16 xDst, 647 INT16 yDst, 648 CARD16 width, 649 CARD16 height) 650{ 651 uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); 652 RegionRec region; 653 BoxPtr pbox; 654 int nbox; 655 int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; 656 PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix; 657 PicturePtr localSrc, localMask = NULL; 658 659 xDst += pDst->pDrawable->x; 660 yDst += pDst->pDrawable->y; 661 662 localSrc = uxa_acquire_source (pDst->pDrawable->pScreen, 663 pSrc, xSrc, ySrc, width, height, 664 &xSrc, &ySrc); 665 if (! localSrc) 666 return 0; 667 668 if (pMask) { 669 localMask = uxa_acquire_mask (pDst->pDrawable->pScreen, 670 pMask, xMask, yMask, width, height, 671 &xMask, &yMask); 672 if (! localMask) { 673 if (localSrc != pSrc) 674 FreePicture (localSrc, 0); 675 676 return 0; 677 } 678 } 679 680 if (uxa_screen->info->check_composite && 681 !(*uxa_screen->info->check_composite) (op, localSrc, localMask, pDst)) 682 { 683 if (localSrc != pSrc) 684 FreePicture (localSrc, 0); 685 if (localMask && localMask != pMask) 686 FreePicture (localMask, 0); 687 688 return -1; 689 } 690 691 if (!miComputeCompositeRegion (®ion, localSrc, localMask, pDst, 692 xSrc, ySrc, xMask, yMask, xDst, yDst, 693 width, height)) 694 { 695 if (localSrc != pSrc) 696 FreePicture (localSrc, 0); 697 if (localMask && localMask != pMask) 698 FreePicture (localMask, 0); 699 700 return 1; 701 } 702 703 pDstPix = uxa_get_offscreen_pixmap (pDst->pDrawable, &dst_off_x, &dst_off_y); 704 705 pSrcPix = uxa_get_offscreen_pixmap (localSrc->pDrawable, 706 &src_off_x, &src_off_y); 707 708 if (localMask) 709 pMaskPix = uxa_get_offscreen_pixmap (localMask->pDrawable, 710 &mask_off_x, &mask_off_y); 711 712 if (!pDstPix || !pSrcPix || (localMask && !pMaskPix)) { 713 REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 714 715 if (localSrc != pSrc) 716 FreePicture (localSrc, 0); 717 if (localMask && localMask != pMask) 718 FreePicture (localMask, 0); 719 720 return 0; 721 } 722 723 REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); 724 725 if (!(*uxa_screen->info->prepare_composite) (op, localSrc, localMask, pDst, 726 pSrcPix, pMaskPix, pDstPix)) 727 { 728 REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 729 730 if (localSrc != pSrc) 731 FreePicture (localSrc, 0); 732 if (localMask && localMask != pMask) 733 FreePicture (localMask, 0); 734 735 return -1; 736 } 737 738 nbox = REGION_NUM_RECTS(®ion); 739 pbox = REGION_RECTS(®ion); 740 741 xMask = xMask + mask_off_x - xDst - dst_off_x; 742 yMask = yMask + mask_off_y - yDst - dst_off_y; 743 744 xSrc = xSrc + src_off_x - xDst - dst_off_x; 745 ySrc = ySrc + src_off_y - yDst - dst_off_y; 746 747 while (nbox--) 748 { 749 (*uxa_screen->info->composite) (pDstPix, 750 pbox->x1 + xSrc, 751 pbox->y1 + ySrc, 752 pbox->x1 + xMask, 753 pbox->y1 + yMask, 754 pbox->x1, 755 pbox->y1, 756 pbox->x2 - pbox->x1, 757 pbox->y2 - pbox->y1); 758 pbox++; 759 } 760 (*uxa_screen->info->done_composite) (pDstPix); 761 762 REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 763 764 if (localSrc != pSrc) 765 FreePicture (localSrc, 0); 766 if (localMask && localMask != pMask) 767 FreePicture (localMask, 0); 768 769 return 1; 770} 771 772/** 773 * uxa_try_magic_two_pass_composite_helper implements PictOpOver using two passes of 774 * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component 775 * alpha and limited 1-tmu cards. 776 * 777 * From http://anholt.livejournal.com/32058.html: 778 * 779 * The trouble is that component-alpha rendering requires two different sources 780 * for blending: one for the source value to the blender, which is the 781 * per-channel multiplication of source and mask, and one for the source alpha 782 * for multiplying with the destination channels, which is the multiplication 783 * of the source channels by the mask alpha. So the equation for Over is: 784 * 785 * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A 786 * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R 787 * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G 788 * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B 789 * 790 * But we can do some simpler operations, right? How about PictOpOutReverse, 791 * which has a source factor of 0 and dest factor of (1 - source alpha). We 792 * can get the source alpha value (srca.X = src.A * mask.X) out of the texture 793 * blenders pretty easily. So we can do a component-alpha OutReverse, which 794 * gets us: 795 * 796 * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A 797 * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R 798 * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G 799 * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B 800 * 801 * OK. And if an op doesn't use the source alpha value for the destination 802 * factor, then we can do the channel multiplication in the texture blenders 803 * to get the source value, and ignore the source alpha that we wouldn't use. 804 * We've supported this in the Radeon driver for a long time. An example would 805 * be PictOpAdd, which does: 806 * 807 * dst.A = src.A * mask.A + dst.A 808 * dst.R = src.R * mask.R + dst.R 809 * dst.G = src.G * mask.G + dst.G 810 * dst.B = src.B * mask.B + dst.B 811 * 812 * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right 813 * after it, we get: 814 * 815 * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A) 816 * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R) 817 * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G) 818 * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B) 819 */ 820 821static int 822uxa_try_magic_two_pass_composite_helper(CARD8 op, 823 PicturePtr pSrc, 824 PicturePtr pMask, 825 PicturePtr pDst, 826 INT16 xSrc, 827 INT16 ySrc, 828 INT16 xMask, 829 INT16 yMask, 830 INT16 xDst, 831 INT16 yDst, 832 CARD16 width, 833 CARD16 height) 834{ 835 uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); 836 837 assert(op == PictOpOver); 838 839 if (uxa_screen->info->check_composite && 840 (!(*uxa_screen->info->check_composite)(PictOpOutReverse, pSrc, pMask, 841 pDst) || 842 !(*uxa_screen->info->check_composite)(PictOpAdd, pSrc, pMask, pDst))) 843 { 844 return -1; 845 } 846 847 /* Now, we think we should be able to accelerate this operation. First, 848 * composite the destination to be the destination times the source alpha 849 * factors. 850 */ 851 uxa_composite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, 852 xDst, yDst, width, height); 853 854 /* Then, add in the source value times the destination alpha factors (1.0). 855 */ 856 uxa_composite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, 857 xDst, yDst, width, height); 858 859 return 1; 860} 861 862void 863uxa_composite(CARD8 op, 864 PicturePtr pSrc, 865 PicturePtr pMask, 866 PicturePtr pDst, 867 INT16 xSrc, 868 INT16 ySrc, 869 INT16 xMask, 870 INT16 yMask, 871 INT16 xDst, 872 INT16 yDst, 873 CARD16 width, 874 CARD16 height) 875{ 876 uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); 877 int ret = -1; 878 Bool saveSrcRepeat = pSrc->repeat; 879 Bool saveMaskRepeat = pMask ? pMask->repeat : 0; 880 RegionRec region; 881 882 if (uxa_screen->swappedOut) 883 goto fallback; 884 885 if (pSrc->pDrawable == NULL || (pMask && pMask->pDrawable == NULL)) 886 goto composite; 887 888 /* Remove repeat in source if useless */ 889 if (pSrc->repeat && !pSrc->transform && xSrc >= 0 && 890 (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 && 891 (ySrc + height) <= pSrc->pDrawable->height) 892 pSrc->repeat = 0; 893 894 if (!pMask) 895 { 896 if ((op == PictOpSrc && 897 ((pSrc->format == pDst->format) || 898 (pSrc->format==PICT_a8r8g8b8 && pDst->format==PICT_x8r8g8b8) || 899 (pSrc->format==PICT_a8b8g8r8 && pDst->format==PICT_x8b8g8r8))) || 900 (op == PictOpOver && !pSrc->alphaMap && !pDst->alphaMap && 901 pSrc->format == pDst->format && 902 (pSrc->format==PICT_x8r8g8b8 || pSrc->format==PICT_x8b8g8r8))) 903 { 904 if (pSrc->pDrawable->width == 1 && 905 pSrc->pDrawable->height == 1 && 906 pSrc->repeat) 907 { 908 ret = uxa_try_driver_solid_fill(pSrc, pDst, xSrc, ySrc, xDst, yDst, 909 width, height); 910 if (ret == 1) 911 goto done; 912 } 913 else if (pSrc->pDrawable != NULL && 914 !pSrc->repeat && 915 !pSrc->transform) 916 { 917 xDst += pDst->pDrawable->x; 918 yDst += pDst->pDrawable->y; 919 xSrc += pSrc->pDrawable->x; 920 ySrc += pSrc->pDrawable->y; 921 922 if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, 923 xSrc, ySrc, xMask, yMask, xDst, 924 yDst, width, height)) 925 goto done; 926 927 928 uxa_copy_n_to_n (pSrc->pDrawable, pDst->pDrawable, NULL, 929 REGION_RECTS(®ion), REGION_NUM_RECTS(®ion), 930 xSrc - xDst, ySrc - yDst, 931 FALSE, FALSE, 0, NULL); 932 REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 933 goto done; 934 } 935 else if (pSrc->pDrawable != NULL && 936 pSrc->pDrawable->type == DRAWABLE_PIXMAP && 937 !pSrc->transform && 938 pSrc->repeatType == RepeatNormal) 939 { 940 DDXPointRec patOrg; 941 942 /* Let's see if the driver can do the repeat in one go */ 943 if (uxa_screen->info->prepare_composite && !pSrc->alphaMap && 944 !pDst->alphaMap) 945 { 946 ret = uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc, 947 ySrc, xMask, yMask, xDst, yDst, 948 width, height); 949 if (ret == 1) 950 goto done; 951 } 952 953 /* Now see if we can use uxa_fill_region_tiled() */ 954 xDst += pDst->pDrawable->x; 955 yDst += pDst->pDrawable->y; 956 xSrc += pSrc->pDrawable->x; 957 ySrc += pSrc->pDrawable->y; 958 959 if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, 960 ySrc, xMask, yMask, xDst, yDst, 961 width, height)) 962 goto done; 963 964 /* pattern origin is the point in the destination drawable 965 * corresponding to (0,0) in the source */ 966 patOrg.x = xDst - xSrc; 967 patOrg.y = yDst - ySrc; 968 969 ret = uxa_fill_region_tiled(pDst->pDrawable, ®ion, 970 (PixmapPtr)pSrc->pDrawable, 971 &patOrg, FB_ALLONES, GXcopy); 972 973 REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 974 975 if (ret) 976 goto done; 977 } 978 } 979 } 980 981composite: 982 /* Remove repeat in mask if useless */ 983 if (pMask && pMask->repeat && !pMask->transform && pMask->pDrawable && 984 xMask >= 0 && (xMask + width) <= pMask->pDrawable->width && 985 yMask >= 0 && (yMask + height) <= pMask->pDrawable->height) 986 pMask->repeat = 0; 987 988 if (uxa_screen->info->prepare_composite && 989 !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap) 990 { 991 Bool isSrcSolid; 992 993 ret = uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, 994 yMask, xDst, yDst, width, height); 995 if (ret == 1) 996 goto done; 997 998 /* For generic masks and solid src pictures, mach64 can do Over in two 999 * passes, similar to the component-alpha case. 1000 */ 1001 isSrcSolid = pSrc->pDrawable && 1002 pSrc->pDrawable->width == 1 && 1003 pSrc->pDrawable->height == 1 && 1004 pSrc->repeat; 1005 1006 /* If we couldn't do the Composite in a single pass, and it was a 1007 * component-alpha Over, see if we can do it in two passes with 1008 * an OutReverse and then an Add. 1009 */ 1010 if (ret == -1 && op == PictOpOver && pMask && 1011 (pMask->componentAlpha || isSrcSolid)) { 1012 ret = uxa_try_magic_two_pass_composite_helper(op, pSrc, pMask, pDst, 1013 xSrc, ySrc, 1014 xMask, yMask, xDst, yDst, 1015 width, height); 1016 if (ret == 1) 1017 goto done; 1018 } 1019 } 1020 1021fallback: 1022 if (uxa_screen->fallback_debug) 1023 uxa_print_composite_fallback (op, pSrc, pMask, pDst); 1024 1025 uxa_check_composite (op, pSrc, pMask, pDst, xSrc, ySrc, 1026 xMask, yMask, xDst, yDst, width, height); 1027 1028done: 1029 pSrc->repeat = saveSrcRepeat; 1030 if (pMask) 1031 pMask->repeat = saveMaskRepeat; 1032} 1033#endif 1034 1035/** 1036 * Same as miCreateAlphaPicture, except it uses uxa_check_poly_fill_rect instead 1037 * of PolyFillRect to initialize the pixmap after creating it, to prevent 1038 * the pixmap from being migrated. 1039 * 1040 * See the comments about uxa_trapezoids and uxa_triangles. 1041 */ 1042static PicturePtr 1043uxa_create_alpha_picture (ScreenPtr pScreen, 1044 PicturePtr pDst, 1045 PictFormatPtr pPictFormat, 1046 CARD16 width, 1047 CARD16 height) 1048{ 1049 PixmapPtr pPixmap; 1050 PicturePtr pPicture; 1051 int error; 1052 1053 if (width > 32767 || height > 32767) 1054 return 0; 1055 1056 if (!pPictFormat) 1057 { 1058 if (pDst->polyEdge == PolyEdgeSharp) 1059 pPictFormat = PictureMatchFormat (pScreen, 1, PICT_a1); 1060 else 1061 pPictFormat = PictureMatchFormat (pScreen, 8, PICT_a8); 1062 if (!pPictFormat) 1063 return 0; 1064 } 1065 1066 pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 1067 pPictFormat->depth, 1068 UXA_CREATE_PIXMAP_FOR_MAP); 1069 if (!pPixmap) 1070 return 0; 1071 pPicture = CreatePicture (0, &pPixmap->drawable, pPictFormat, 1072 0, 0, serverClient, &error); 1073 (*pScreen->DestroyPixmap) (pPixmap); 1074 return pPicture; 1075} 1076 1077/** 1078 * uxa_trapezoids is essentially a copy of miTrapezoids that uses 1079 * uxa_create_alpha_picture instead of miCreateAlphaPicture. 1080 * 1081 * The problem with miCreateAlphaPicture is that it calls PolyFillRect 1082 * to initialize the contents after creating the pixmap, which 1083 * causes the pixmap to be moved in for acceleration. The subsequent 1084 * call to RasterizeTrapezoid won't be accelerated however, which 1085 * forces the pixmap to be moved out again. 1086 * 1087 * uxa_create_alpha_picture avoids this roundtrip by using uxa_check_poly_fill_rect 1088 * to initialize the contents. 1089 */ 1090void 1091uxa_trapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, 1092 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 1093 int ntrap, xTrapezoid *traps) 1094{ 1095 ScreenPtr pScreen = pDst->pDrawable->pScreen; 1096 PictureScreenPtr ps = GetPictureScreen(pScreen); 1097 BoxRec bounds; 1098 Bool direct = op == PictOpAdd && miIsSolidAlpha (pSrc); 1099 1100 if (maskFormat || direct) { 1101 miTrapezoidBounds (ntrap, traps, &bounds); 1102 1103 if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 1104 return; 1105 } 1106 1107 /* 1108 * Check for solid alpha add 1109 */ 1110 if (direct) 1111 { 1112 DrawablePtr pDraw = pDst->pDrawable; 1113 PixmapPtr pixmap = uxa_get_drawable_pixmap (pDraw); 1114 int xoff, yoff; 1115 1116 uxa_get_drawable_deltas(pDraw, pixmap, &xoff, &yoff); 1117 1118 xoff += pDraw->x; 1119 yoff += pDraw->y; 1120 1121 if (uxa_prepare_access(pDraw, UXA_ACCESS_RW)) 1122 { 1123 for (; ntrap; ntrap--, traps++) 1124 (*ps->RasterizeTrapezoid) (pDst, traps, 0, 0); 1125 uxa_finish_access(pDraw); 1126 } 1127 } 1128 else if (maskFormat) 1129 { 1130 PicturePtr pPicture; 1131 INT16 xDst, yDst; 1132 INT16 xRel, yRel; 1133 int width, height; 1134 pixman_image_t *image; 1135 pixman_format_code_t format; 1136 1137 xDst = traps[0].left.p1.x >> 16; 1138 yDst = traps[0].left.p1.y >> 16; 1139 1140 width = bounds.x2 - bounds.x1; 1141 height = bounds.y2 - bounds.y1; 1142 1143 format = maskFormat->format | (BitsPerPixel (maskFormat->depth) << 24); 1144 image = pixman_image_create_bits (format, width, height, NULL, 0); 1145 if (!image) 1146 return; 1147 1148 for (; ntrap; ntrap--, traps++) 1149 pixman_rasterize_trapezoid (image, (pixman_trapezoid_t *) traps, 1150 -bounds.x1, -bounds.y1); 1151 1152 pPicture = uxa_picture_from_pixman_image (pScreen, image, format); 1153 pixman_image_unref (image); 1154 if (!pPicture) 1155 return; 1156 1157 xRel = bounds.x1 + xSrc - xDst; 1158 yRel = bounds.y1 + ySrc - yDst; 1159 CompositePicture (op, pSrc, pPicture, pDst, 1160 xRel, yRel, 0, 0, bounds.x1, bounds.y1, 1161 bounds.x2 - bounds.x1, 1162 bounds.y2 - bounds.y1); 1163 FreePicture (pPicture, 0); 1164 } 1165 else 1166 { 1167 if (pDst->polyEdge == PolyEdgeSharp) 1168 maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); 1169 else 1170 maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); 1171 for (; ntrap; ntrap--, traps++) 1172 uxa_trapezoids (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps); 1173 } 1174} 1175 1176/** 1177 * uxa_triangles is essentially a copy of miTriangles that uses 1178 * uxa_create_alpha_picture instead of miCreateAlphaPicture. 1179 * 1180 * The problem with miCreateAlphaPicture is that it calls PolyFillRect 1181 * to initialize the contents after creating the pixmap, which 1182 * causes the pixmap to be moved in for acceleration. The subsequent 1183 * call to AddTriangles won't be accelerated however, which forces the pixmap 1184 * to be moved out again. 1185 * 1186 * uxa_create_alpha_picture avoids this roundtrip by using uxa_check_poly_fill_rect 1187 * to initialize the contents. 1188 */ 1189void 1190uxa_triangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst, 1191 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 1192 int ntri, xTriangle *tris) 1193{ 1194 ScreenPtr pScreen = pDst->pDrawable->pScreen; 1195 PictureScreenPtr ps = GetPictureScreen(pScreen); 1196 BoxRec bounds; 1197 Bool direct = op == PictOpAdd && miIsSolidAlpha (pSrc); 1198 1199 if (maskFormat || direct) { 1200 miTriangleBounds (ntri, tris, &bounds); 1201 1202 if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 1203 return; 1204 } 1205 1206 /* 1207 * Check for solid alpha add 1208 */ 1209 if (direct) 1210 { 1211 DrawablePtr pDraw = pDst->pDrawable; 1212 if (uxa_prepare_access(pDraw, UXA_ACCESS_RW)) { 1213 (*ps->AddTriangles) (pDst, 0, 0, ntri, tris); 1214 uxa_finish_access(pDraw); 1215 } 1216 } 1217 else if (maskFormat) 1218 { 1219 PicturePtr pPicture; 1220 INT16 xDst, yDst; 1221 INT16 xRel, yRel; 1222 int width = bounds.x2 - bounds.x1; 1223 int height = bounds.y2 - bounds.y1; 1224 GCPtr pGC; 1225 xRectangle rect; 1226 1227 xDst = tris[0].p1.x >> 16; 1228 yDst = tris[0].p1.y >> 16; 1229 1230 pPicture = uxa_create_alpha_picture (pScreen, pDst, maskFormat, 1231 width, height); 1232 if (!pPicture) 1233 return; 1234 1235 /* Clear the alpha picture to 0. */ 1236 pGC = GetScratchGC (pPicture->pDrawable->depth, pScreen); 1237 if (!pGC) { 1238 FreePicture (pPicture, 0); 1239 return; 1240 } 1241 ValidateGC (pPicture->pDrawable, pGC); 1242 rect.x = 0; 1243 rect.y = 0; 1244 rect.width = width; 1245 rect.height = height; 1246 uxa_check_poly_fill_rect (pPicture->pDrawable, pGC, 1, &rect); 1247 FreeScratchGC (pGC); 1248 1249 if (uxa_prepare_access(pPicture->pDrawable, UXA_ACCESS_RW)) { 1250 (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris); 1251 uxa_finish_access(pPicture->pDrawable); 1252 } 1253 1254 xRel = bounds.x1 + xSrc - xDst; 1255 yRel = bounds.y1 + ySrc - yDst; 1256 CompositePicture (op, pSrc, pPicture, pDst, 1257 xRel, yRel, 0, 0, bounds.x1, bounds.y1, 1258 bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); 1259 FreePicture (pPicture, 0); 1260 } 1261 else 1262 { 1263 if (pDst->polyEdge == PolyEdgeSharp) 1264 maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); 1265 else 1266 maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); 1267 1268 for (; ntri; ntri--, tris++) 1269 uxa_triangles (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris); 1270 } 1271} 1272