uxa-render.c revision d514b0f3
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, 38 int n) 39{ 40 char format[20]; 41 char size[20]; 42 char loc; 43 44 if (!pict) { 45 snprintf(string, n, "None"); 46 return; 47 } 48 49 if (pict->pDrawable == NULL) { 50 snprintf(string, n, "source-only"); 51 return; 52 } 53 54 switch (pict->format) { 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 ? " R" : ""); 82 83 snprintf(string, n, "%p:%c fmt %s (%s)%s", 84 pict->pDrawable, loc, format, size, 85 pict->alphaMap ? " with alpha map" :""); 86} 87 88static const char * 89op_to_string(CARD8 op) 90{ 91 switch (op) { 92#define C(x) case PictOp##x: return #x 93 C(Clear); 94 C(Src); 95 C(Dst); 96 C(Over); 97 C(OverReverse); 98 C(In); 99 C(InReverse); 100 C(Out); 101 C(OutReverse); 102 C(Atop); 103 C(AtopReverse); 104 C(Xor); 105 C(Add); 106 C(Saturate); 107 108 /* 109 * Operators only available in version 0.2 110 */ 111 C(DisjointClear); 112 C(DisjointSrc); 113 C(DisjointDst); 114 C(DisjointOver); 115 C(DisjointOverReverse); 116 C(DisjointIn); 117 C(DisjointInReverse); 118 C(DisjointOut); 119 C(DisjointOutReverse); 120 C(DisjointAtop); 121 C(DisjointAtopReverse); 122 C(DisjointXor); 123 124 C(ConjointClear); 125 C(ConjointSrc); 126 C(ConjointDst); 127 C(ConjointOver); 128 C(ConjointOverReverse); 129 C(ConjointIn); 130 C(ConjointInReverse); 131 C(ConjointOut); 132 C(ConjointOutReverse); 133 C(ConjointAtop); 134 C(ConjointAtopReverse); 135 C(ConjointXor); 136 137 /* 138 * Operators only available in version 0.11 139 */ 140 C(Multiply); 141 C(Screen); 142 C(Overlay); 143 C(Darken); 144 C(Lighten); 145 C(ColorDodge); 146 C(ColorBurn); 147 C(HardLight); 148 C(SoftLight); 149 C(Difference); 150 C(Exclusion); 151 C(HSLHue); 152 C(HSLSaturation); 153 C(HSLColor); 154 C(HSLLuminosity); 155 default: return "garbage"; 156#undef C 157 } 158} 159 160static void 161uxa_print_composite_fallback(const char *func, CARD8 op, 162 PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst) 163{ 164 uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); 165 char srcdesc[40], maskdesc[40], dstdesc[40]; 166 167 if (! uxa_screen->fallback_debug) 168 return; 169 170 /* Limit the noise if fallbacks are expected. */ 171 if (uxa_screen->force_fallback) 172 return; 173 174 uxa_composite_fallback_pict_desc(pSrc, srcdesc, 40); 175 uxa_composite_fallback_pict_desc(pMask, maskdesc, 40); 176 uxa_composite_fallback_pict_desc(pDst, dstdesc, 40); 177 178 ErrorF("Composite fallback at %s:\n" 179 " op %s, \n" 180 " src %s, \n" 181 " mask %s, \n" 182 " dst %s, \n" 183 " screen %s\n", 184 func, op_to_string (op), srcdesc, maskdesc, dstdesc, 185 uxa_screen->swappedOut ? "swapped out" : "normal"); 186} 187 188Bool uxa_op_reads_destination(CARD8 op) 189{ 190 /* FALSE (does not read destination) is the list of ops in the protocol 191 * document with "0" in the "Fb" column and no "Ab" in the "Fa" column. 192 * That's just Clear and Src. ReduceCompositeOp() will already have 193 * converted con/disjoint clear/src to Clear or Src. 194 */ 195 switch (op) { 196 case PictOpClear: 197 case PictOpSrc: 198 return FALSE; 199 default: 200 return TRUE; 201 } 202} 203 204static Bool 205uxa_get_pixel_from_rgba(CARD32 * pixel, 206 CARD16 red, 207 CARD16 green, 208 CARD16 blue, 209 CARD16 alpha, 210 CARD32 format) 211{ 212 int rbits, bbits, gbits, abits; 213 int rshift, bshift, gshift, ashift; 214 215 rbits = PICT_FORMAT_R(format); 216 gbits = PICT_FORMAT_G(format); 217 bbits = PICT_FORMAT_B(format); 218 abits = PICT_FORMAT_A(format); 219 if (abits == 0) 220 abits = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits); 221 222 if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) { 223 *pixel = alpha >> (16 - abits); 224 return TRUE; 225 } 226 227 if (!PICT_FORMAT_COLOR(format)) 228 return FALSE; 229 230 if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { 231 bshift = 0; 232 gshift = bbits; 233 rshift = gshift + gbits; 234 ashift = rshift + rbits; 235 } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { 236 rshift = 0; 237 gshift = rbits; 238 bshift = gshift + gbits; 239 ashift = bshift + bbits; 240 } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) { 241 ashift = 0; 242 rshift = abits; 243 gshift = rshift + rbits; 244 bshift = gshift + gbits; 245 } else { 246 return FALSE; 247 } 248 249 *pixel = 0; 250 *pixel |= (blue >> (16 - bbits)) << bshift; 251 *pixel |= (green >> (16 - gbits)) << gshift; 252 *pixel |= (red >> (16 - rbits)) << rshift; 253 *pixel |= (alpha >> (16 - abits)) << ashift; 254 255 return TRUE; 256} 257 258Bool 259uxa_get_rgba_from_pixel(CARD32 pixel, 260 CARD16 * red, 261 CARD16 * green, 262 CARD16 * blue, 263 CARD16 * alpha, 264 CARD32 format) 265{ 266 int rbits, bbits, gbits, abits; 267 int rshift, bshift, gshift, ashift; 268 269 rbits = PICT_FORMAT_R(format); 270 gbits = PICT_FORMAT_G(format); 271 bbits = PICT_FORMAT_B(format); 272 abits = PICT_FORMAT_A(format); 273 274 if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) { 275 rshift = gshift = bshift = ashift = 0; 276 } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { 277 bshift = 0; 278 gshift = bbits; 279 rshift = gshift + gbits; 280 ashift = rshift + rbits; 281 } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { 282 rshift = 0; 283 gshift = rbits; 284 bshift = gshift + gbits; 285 ashift = bshift + bbits; 286 } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) { 287 ashift = 0; 288 rshift = abits; 289 if (abits == 0) 290 rshift = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits); 291 gshift = rshift + rbits; 292 bshift = gshift + gbits; 293 } else { 294 return FALSE; 295 } 296 297 if (rbits) { 298 *red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits); 299 while (rbits < 16) { 300 *red |= *red >> rbits; 301 rbits <<= 1; 302 } 303 } else 304 *red = 0; 305 306 if (gbits) { 307 *green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits); 308 while (gbits < 16) { 309 *green |= *green >> gbits; 310 gbits <<= 1; 311 } 312 } else 313 *green = 0; 314 315 if (bbits) { 316 *blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits); 317 while (bbits < 16) { 318 *blue |= *blue >> bbits; 319 bbits <<= 1; 320 } 321 } else 322 *blue = 0; 323 324 if (abits) { 325 *alpha = 326 ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits); 327 while (abits < 16) { 328 *alpha |= *alpha >> abits; 329 abits <<= 1; 330 } 331 } else 332 *alpha = 0xffff; 333 334 return TRUE; 335} 336 337Bool 338uxa_get_color_for_pixmap (PixmapPtr pixmap, 339 CARD32 src_format, 340 CARD32 dst_format, 341 CARD32 *pixel) 342{ 343 CARD16 red, green, blue, alpha; 344 345 *pixel = uxa_get_pixmap_first_pixel(pixmap); 346 347 if (src_format != dst_format) { 348 if (!uxa_get_rgba_from_pixel(*pixel, 349 &red, &green, &blue, &alpha, 350 src_format)) 351 return FALSE; 352 353 if (!uxa_get_pixel_from_rgba(pixel, 354 red, green, blue, alpha, 355 dst_format)) 356 return FALSE; 357 } 358 359 return TRUE; 360} 361 362static int 363uxa_try_driver_solid_fill(PicturePtr pSrc, 364 PicturePtr pDst, 365 INT16 xSrc, 366 INT16 ySrc, 367 INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) 368{ 369 uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); 370 RegionRec region; 371 BoxPtr pbox; 372 int nbox; 373 int dst_off_x, dst_off_y; 374 PixmapPtr pSrcPix = NULL, pDstPix; 375 CARD32 pixel; 376 377 if (uxa_screen->info->check_solid && !uxa_screen->info->check_solid(pDst->pDrawable, GXcopy, FB_ALLONES)) 378 return -1; 379 380 pDstPix = uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); 381 if (!pDstPix) 382 return -1; 383 384 xDst += pDst->pDrawable->x; 385 yDst += pDst->pDrawable->y; 386 387 if (pSrc->pDrawable) { 388 pSrcPix = uxa_get_drawable_pixmap(pSrc->pDrawable); 389 xSrc += pSrc->pDrawable->x; 390 ySrc += pSrc->pDrawable->y; 391 } 392 393 if (!miComputeCompositeRegion(®ion, pSrc, NULL, pDst, 394 xSrc, ySrc, 0, 0, xDst, yDst, 395 width, height)) 396 return 1; 397 398 if (pSrcPix) { 399 if (! uxa_get_color_for_pixmap (pSrcPix, pSrc->format, pDst->format, &pixel)) { 400 REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 401 return -1; 402 } 403 } else { 404 SourcePict *source = pSrc->pSourcePict; 405 PictSolidFill *solid = &source->solidFill; 406 407 if (source == NULL || source->type != SourcePictTypeSolidFill) { 408 REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 409 return -1; 410 } 411 412 if (pDst->format == PICT_a8r8g8b8) { 413 pixel = solid->color; 414 } else if (pDst->format == PICT_x8r8g8b8) { 415 pixel = solid->color | 0xff000000; 416 } else { 417 CARD16 red, green, blue, alpha; 418 419 if (!uxa_get_rgba_from_pixel(solid->color, 420 &red, &green, &blue, &alpha, 421 PIXMAN_a8r8g8b8) || 422 !uxa_get_pixel_from_rgba(&pixel, 423 red, green, blue, alpha, 424 pDst->format)) { 425 REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 426 return -1; 427 } 428 } 429 } 430 431 if (!(*uxa_screen->info->prepare_solid) 432 (pDstPix, GXcopy, FB_ALLONES, pixel)) { 433 REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 434 return -1; 435 } 436 437 REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); 438 439 nbox = REGION_NUM_RECTS(®ion); 440 pbox = REGION_RECTS(®ion); 441 442 while (nbox--) { 443 (*uxa_screen->info->solid) (pDstPix, pbox->x1, pbox->y1, 444 pbox->x2, pbox->y2); 445 pbox++; 446 } 447 448 (*uxa_screen->info->done_solid) (pDstPix); 449 450 REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 451 return 1; 452} 453 454static PicturePtr 455uxa_picture_for_pixman_format(ScreenPtr pScreen, 456 pixman_format_code_t format, 457 int width, int height) 458{ 459 PicturePtr pPicture; 460 PixmapPtr pPixmap; 461 int error; 462 463 if (format == PIXMAN_a1) 464 format = PIXMAN_a8; 465 466 /* fill alpha if unset */ 467 if (PIXMAN_FORMAT_A(format) == 0) 468 format = PIXMAN_a8r8g8b8; 469 470 pPixmap = (*pScreen->CreatePixmap)(pScreen, width, height, 471 PIXMAN_FORMAT_DEPTH(format), 472 UXA_CREATE_PIXMAP_FOR_MAP); 473 if (!pPixmap) 474 return 0; 475 476 pPicture = CreatePicture(0, &pPixmap->drawable, 477 PictureMatchFormat(pScreen, 478 PIXMAN_FORMAT_DEPTH(format), 479 format), 480 0, 0, serverClient, &error); 481 (*pScreen->DestroyPixmap) (pPixmap); 482 if (!pPicture) 483 return 0; 484 485 ValidatePicture(pPicture); 486 487 return pPicture; 488} 489 490static PicturePtr 491uxa_picture_from_pixman_image(ScreenPtr screen, 492 pixman_image_t * image, 493 pixman_format_code_t format) 494{ 495 uxa_screen_t *uxa_screen = uxa_get_screen(screen); 496 PicturePtr picture; 497 PixmapPtr pixmap; 498 int width, height; 499 500 width = pixman_image_get_width(image); 501 height = pixman_image_get_height(image); 502 503 picture = uxa_picture_for_pixman_format(screen, format, 504 width, height); 505 if (!picture) 506 return 0; 507 508 if (uxa_screen->info->put_image && 509 ((picture->pDrawable->depth << 24) | picture->format) == format && 510 uxa_screen->info->put_image((PixmapPtr)picture->pDrawable, 511 0, 0, 512 width, height, 513 (char *)pixman_image_get_data(image), 514 pixman_image_get_stride(image))) 515 return picture; 516 517 pixmap = GetScratchPixmapHeader(screen, width, height, 518 PIXMAN_FORMAT_DEPTH(format), 519 PIXMAN_FORMAT_BPP(format), 520 pixman_image_get_stride(image), 521 pixman_image_get_data(image)); 522 if (!pixmap) { 523 FreePicture(picture, 0); 524 return 0; 525 } 526 527 if (((picture->pDrawable->depth << 24) | picture->format) == format) { 528 GCPtr gc; 529 530 gc = GetScratchGC(PIXMAN_FORMAT_DEPTH(format), screen); 531 if (!gc) { 532 FreeScratchPixmapHeader(pixmap); 533 FreePicture(picture, 0); 534 return 0; 535 } 536 ValidateGC(picture->pDrawable, gc); 537 538 (*gc->ops->CopyArea) (&pixmap->drawable, picture->pDrawable, 539 gc, 0, 0, width, height, 0, 0); 540 541 FreeScratchGC(gc); 542 } else { 543 PicturePtr src; 544 int error; 545 546 src = CreatePicture(0, &pixmap->drawable, 547 PictureMatchFormat(screen, 548 PIXMAN_FORMAT_DEPTH(format), 549 format), 550 0, 0, serverClient, &error); 551 if (!src) { 552 FreeScratchPixmapHeader(pixmap); 553 FreePicture(picture, 0); 554 return 0; 555 } 556 ValidatePicture(src); 557 558 if (uxa_prepare_access(picture->pDrawable, NULL, UXA_ACCESS_RW)) { 559 fbComposite(PictOpSrc, src, NULL, picture, 560 0, 0, 0, 0, 0, 0, width, height); 561 uxa_finish_access(picture->pDrawable); 562 } 563 564 FreePicture(src, 0); 565 } 566 FreeScratchPixmapHeader(pixmap); 567 568 return picture; 569} 570 571static PicturePtr 572uxa_create_solid(ScreenPtr screen, uint32_t color) 573{ 574 PixmapPtr pixmap; 575 PicturePtr picture; 576 XID repeat = RepeatNormal; 577 int error = 0; 578 579 pixmap = (*screen->CreatePixmap)(screen, 1, 1, 32, 580 UXA_CREATE_PIXMAP_FOR_MAP); 581 if (!pixmap) 582 return 0; 583 584 if (!uxa_prepare_access((DrawablePtr)pixmap, NULL, UXA_ACCESS_RW)) { 585 (*screen->DestroyPixmap)(pixmap); 586 return 0; 587 } 588 *((uint32_t *)pixmap->devPrivate.ptr) = color; 589 uxa_finish_access((DrawablePtr)pixmap); 590 591 picture = CreatePicture(0, &pixmap->drawable, 592 PictureMatchFormat(screen, 32, PICT_a8r8g8b8), 593 CPRepeat, &repeat, serverClient, &error); 594 (*screen->DestroyPixmap)(pixmap); 595 596 return picture; 597} 598 599static PicturePtr 600uxa_solid_clear(ScreenPtr screen) 601{ 602 uxa_screen_t *uxa_screen = uxa_get_screen(screen); 603 PicturePtr picture; 604 605 if (!uxa_screen->solid_clear) { 606 uxa_screen->solid_clear = uxa_create_solid(screen, 0); 607 if (!uxa_screen->solid_clear) 608 return 0; 609 } 610 picture = uxa_screen->solid_clear; 611 return picture; 612} 613 614PicturePtr 615uxa_acquire_solid(ScreenPtr screen, SourcePict *source) 616{ 617 uxa_screen_t *uxa_screen = uxa_get_screen(screen); 618 PictSolidFill *solid = &source->solidFill; 619 PicturePtr picture; 620 int i; 621 622 if ((solid->color >> 24) == 0) { 623 picture = uxa_solid_clear(screen); 624 if (!picture) 625 return 0; 626 627 goto DONE; 628 } else if (solid->color == 0xff000000) { 629 if (!uxa_screen->solid_black) { 630 uxa_screen->solid_black = uxa_create_solid(screen, 0xff000000); 631 if (!uxa_screen->solid_black) 632 return 0; 633 } 634 picture = uxa_screen->solid_black; 635 goto DONE; 636 } else if (solid->color == 0xffffffff) { 637 if (!uxa_screen->solid_white) { 638 uxa_screen->solid_white = uxa_create_solid(screen, 0xffffffff); 639 if (!uxa_screen->solid_white) 640 return 0; 641 } 642 picture = uxa_screen->solid_white; 643 goto DONE; 644 } 645 646 for (i = 0; i < uxa_screen->solid_cache_size; i++) { 647 if (uxa_screen->solid_cache[i].color == solid->color) { 648 picture = uxa_screen->solid_cache[i].picture; 649 goto DONE; 650 } 651 } 652 653 picture = uxa_create_solid(screen, solid->color); 654 if (!picture) 655 return 0; 656 657 if (uxa_screen->solid_cache_size == UXA_NUM_SOLID_CACHE) { 658 i = rand() % UXA_NUM_SOLID_CACHE; 659 FreePicture(uxa_screen->solid_cache[i].picture, 0); 660 } else 661 uxa_screen->solid_cache_size++; 662 663 uxa_screen->solid_cache[i].picture = picture; 664 uxa_screen->solid_cache[i].color = solid->color; 665 666DONE: 667 picture->refcnt++; 668 return picture; 669} 670 671PicturePtr 672uxa_acquire_pattern(ScreenPtr pScreen, 673 PicturePtr pSrc, 674 pixman_format_code_t format, 675 INT16 x, INT16 y, CARD16 width, CARD16 height) 676{ 677 PicturePtr pDst; 678 679 if (pSrc->pSourcePict) { 680 SourcePict *source = pSrc->pSourcePict; 681 if (source->type == SourcePictTypeSolidFill) 682 return uxa_acquire_solid (pScreen, source); 683 } 684 685 pDst = uxa_picture_for_pixman_format(pScreen, format, width, height); 686 if (!pDst) 687 return 0; 688 689 if (uxa_prepare_access(pDst->pDrawable, NULL, UXA_ACCESS_RW)) { 690 fbComposite(PictOpSrc, pSrc, NULL, pDst, 691 x, y, 0, 0, 0, 0, width, height); 692 uxa_finish_access(pDst->pDrawable); 693 return pDst; 694 } else { 695 FreePicture(pDst, 0); 696 return 0; 697 } 698} 699 700static Bool 701transform_is_integer_translation(PictTransformPtr t, int *tx, int *ty) 702{ 703 if (t == NULL) { 704 *tx = *ty = 0; 705 return TRUE; 706 } 707 708 if (t->matrix[0][0] != IntToxFixed(1) || 709 t->matrix[0][1] != 0 || 710 t->matrix[1][0] != 0 || 711 t->matrix[1][1] != IntToxFixed(1) || 712 t->matrix[2][0] != 0 || 713 t->matrix[2][1] != 0 || 714 t->matrix[2][2] != IntToxFixed(1)) 715 return FALSE; 716 717 if (xFixedFrac(t->matrix[0][2]) != 0 || 718 xFixedFrac(t->matrix[1][2]) != 0) 719 return FALSE; 720 721 *tx = xFixedToInt(t->matrix[0][2]); 722 *ty = xFixedToInt(t->matrix[1][2]); 723 return TRUE; 724} 725 726static PicturePtr 727uxa_render_picture(ScreenPtr screen, 728 PicturePtr src, 729 pixman_format_code_t format, 730 INT16 x, INT16 y, 731 CARD16 width, CARD16 height) 732{ 733 PicturePtr picture; 734 int ret = 0; 735 736 /* XXX we need a mechanism for the card to choose the fallback format */ 737 738 /* force alpha channel in case source does not entirely cover the extents */ 739 if (PIXMAN_FORMAT_A(format) == 0) 740 format = PIXMAN_a8r8g8b8; /* available on all hardware */ 741 742 picture = uxa_picture_for_pixman_format(screen, format, width, height); 743 if (!picture) 744 return 0; 745 746 if (uxa_prepare_access(picture->pDrawable, NULL, UXA_ACCESS_RW)) { 747 if (uxa_prepare_access(src->pDrawable, NULL, UXA_ACCESS_RO)) { 748 ret = 1; 749 fbComposite(PictOpSrc, src, NULL, picture, 750 x, y, 0, 0, 0, 0, width, height); 751 uxa_finish_access(src->pDrawable); 752 } 753 uxa_finish_access(picture->pDrawable); 754 } 755 756 if (!ret) { 757 FreePicture(picture, 0); 758 return 0; 759 } 760 761 return picture; 762} 763 764PicturePtr 765uxa_acquire_drawable(ScreenPtr pScreen, 766 PicturePtr pSrc, 767 INT16 x, INT16 y, 768 CARD16 width, CARD16 height, 769 INT16 * out_x, INT16 * out_y) 770{ 771 PixmapPtr pPixmap; 772 PicturePtr pDst; 773 GCPtr pGC; 774 int depth, error; 775 int tx, ty; 776 777 depth = pSrc->pDrawable->depth; 778 if (depth == 1 || 779 pSrc->filter == PictFilterConvolution || /* XXX */ 780 !transform_is_integer_translation(pSrc->transform, &tx, &ty)) { 781 /* XXX extract the sample extents and do the transformation on the GPU */ 782 pDst = uxa_render_picture(pScreen, pSrc, 783 pSrc->format | (BitsPerPixel(pSrc->pDrawable->depth) << 24), 784 x, y, width, height); 785 786 goto done; 787 } else { 788 if (width == pSrc->pDrawable->width && height == pSrc->pDrawable->depth) { 789 *out_x = x + pSrc->pDrawable->x; 790 *out_y = y + pSrc->pDrawable->y; 791 return pSrc; 792 } 793 } 794 795 pPixmap = pScreen->CreatePixmap(pScreen, 796 width, height, depth, 797 CREATE_PIXMAP_USAGE_SCRATCH); 798 if (!pPixmap) 799 return 0; 800 801 /* Skip the copy if the result remains in memory and not a bo */ 802 if (!uxa_drawable_is_offscreen(&pPixmap->drawable)) { 803 pScreen->DestroyPixmap(pPixmap); 804 return 0; 805 } 806 807 pGC = GetScratchGC(depth, pScreen); 808 if (!pGC) { 809 pScreen->DestroyPixmap(pPixmap); 810 return 0; 811 } 812 813 ValidateGC(&pPixmap->drawable, pGC); 814 pGC->ops->CopyArea(pSrc->pDrawable, &pPixmap->drawable, pGC, 815 x + tx, y + ty, width, height, 0, 0); 816 FreeScratchGC(pGC); 817 818 pDst = CreatePicture(0, &pPixmap->drawable, 819 PictureMatchFormat(pScreen, depth, pSrc->format), 820 0, 0, serverClient, &error); 821 pScreen->DestroyPixmap(pPixmap); 822 ValidatePicture(pDst); 823 824done: 825 pDst->componentAlpha = pSrc->componentAlpha; 826 *out_x = x; 827 *out_y = y; 828 return pDst; 829} 830 831static PicturePtr 832uxa_acquire_picture(ScreenPtr screen, 833 PicturePtr src, 834 pixman_format_code_t format, 835 INT16 x, INT16 y, 836 CARD16 width, CARD16 height, 837 INT16 * out_x, INT16 * out_y) 838{ 839 uxa_screen_t *uxa_screen = uxa_get_screen(screen); 840 841 if (uxa_screen->info->check_composite_texture && 842 uxa_screen->info->check_composite_texture(screen, src)) { 843 if (src->pDrawable) { 844 *out_x = x + src->pDrawable->x; 845 *out_y = y + src->pDrawable->y; 846 } else { 847 *out_x = 0; 848 *out_y = 0; 849 } 850 return src; 851 } 852 853 if (src->pDrawable) { 854 PicturePtr dst; 855 856 dst = uxa_acquire_drawable(screen, src, 857 x, y, width, height, 858 out_x, out_y); 859 if (uxa_screen->info->check_composite_texture && 860 !uxa_screen->info->check_composite_texture(screen, dst)) { 861 if (dst != src) 862 FreePicture(dst, 0); 863 return 0; 864 } 865 866 return dst; 867 } 868 869 *out_x = 0; 870 *out_y = 0; 871 return uxa_acquire_pattern(screen, src, 872 format, x, y, width, height); 873} 874 875static PicturePtr 876uxa_acquire_source(ScreenPtr screen, 877 PicturePtr pict, 878 INT16 x, INT16 y, 879 CARD16 width, CARD16 height, 880 INT16 * out_x, INT16 * out_y) 881{ 882 return uxa_acquire_picture (screen, pict, 883 PIXMAN_a8r8g8b8, 884 x, y, 885 width, height, 886 out_x, out_y); 887} 888 889static PicturePtr 890uxa_acquire_mask(ScreenPtr screen, 891 PicturePtr pict, 892 INT16 x, INT16 y, 893 INT16 width, INT16 height, 894 INT16 * out_x, INT16 * out_y) 895{ 896 return uxa_acquire_picture (screen, pict, 897 PIXMAN_a8, 898 x, y, 899 width, height, 900 out_x, out_y); 901} 902 903static Bool 904_pixman_region_init_rectangles(pixman_region16_t *region, 905 int num_rects, 906 xRectangle *rects, 907 int tx, int ty) 908{ 909 pixman_box16_t stack_boxes[64], *boxes = stack_boxes; 910 pixman_bool_t ret; 911 int i; 912 913 if (num_rects > sizeof(stack_boxes) / sizeof(stack_boxes[0])) { 914 boxes = malloc(sizeof(pixman_box16_t) * num_rects); 915 if (boxes == NULL) 916 return FALSE; 917 } 918 919 for (i = 0; i < num_rects; i++) { 920 boxes[i].x1 = rects[i].x + tx; 921 boxes[i].y1 = rects[i].y + ty; 922 boxes[i].x2 = rects[i].x + tx + rects[i].width; 923 boxes[i].y2 = rects[i].y + ty + rects[i].height; 924 } 925 926 ret = pixman_region_init_rects(region, boxes, num_rects); 927 928 if (boxes != stack_boxes) 929 free(boxes); 930 931 return ret; 932} 933 934void 935uxa_solid_rects (CARD8 op, 936 PicturePtr dst, 937 xRenderColor *color, 938 int num_rects, 939 xRectangle *rects) 940{ 941 ScreenPtr screen = dst->pDrawable->pScreen; 942 uxa_screen_t *uxa_screen = uxa_get_screen(screen); 943 PixmapPtr dst_pixmap, src_pixmap = NULL; 944 pixman_region16_t region; 945 pixman_box16_t *boxes, *extents; 946 PicturePtr src; 947 int dst_x, dst_y; 948 int num_boxes; 949 950 if (!pixman_region_not_empty(dst->pCompositeClip)) 951 return; 952 953 if (dst->alphaMap) 954 goto fallback; 955 956 dst_pixmap = uxa_get_offscreen_pixmap(dst->pDrawable, &dst_x, &dst_y); 957 if (!dst_pixmap) 958 goto fallback; 959 960 if (!_pixman_region_init_rectangles(®ion, 961 num_rects, rects, 962 dst->pDrawable->x, dst->pDrawable->y)) 963 goto fallback; 964 965 if (!pixman_region_intersect(®ion, ®ion, dst->pCompositeClip)) { 966 pixman_region_fini(®ion); 967 return; 968 } 969 970 /* XXX xserver-1.8: CompositeRects is not tracked by Damage, so we must 971 * manually append the damaged regions ourselves. 972 */ 973 DamageRegionAppend(dst->pDrawable, ®ion); 974 975 pixman_region_translate(®ion, dst_x, dst_y); 976 boxes = pixman_region_rectangles(®ion, &num_boxes); 977 extents = pixman_region_extents (®ion); 978 979 if (op == PictOpClear) 980 color->red = color->green = color->blue = color->alpha = 0; 981 if (color->alpha >= 0xff00 && op == PictOpOver) { 982 color->alpha = 0xffff; 983 op = PictOpSrc; 984 } 985 986 /* Using GEM, the relocation costs outweigh the advantages of the blitter */ 987 if (num_boxes == 1 && (op == PictOpSrc || op == PictOpClear)) { 988 CARD32 pixel; 989 990try_solid: 991 if (uxa_screen->info->check_solid && 992 !uxa_screen->info->check_solid(&dst_pixmap->drawable, GXcopy, FB_ALLONES)) 993 goto err_region; 994 995 if (!uxa_get_pixel_from_rgba(&pixel, 996 color->red, 997 color->green, 998 color->blue, 999 color->alpha, 1000 dst->format)) 1001 goto err_region; 1002 1003 if (!uxa_screen->info->prepare_solid(dst_pixmap, GXcopy, FB_ALLONES, pixel)) 1004 goto err_region; 1005 1006 while (num_boxes--) { 1007 uxa_screen->info->solid(dst_pixmap, 1008 boxes->x1, boxes->y1, 1009 boxes->x2, boxes->y2); 1010 boxes++; 1011 } 1012 1013 uxa_screen->info->done_solid(dst_pixmap); 1014 } else { 1015 int error; 1016 1017 src = CreateSolidPicture(0, color, &error); 1018 if (!src) 1019 goto err_region; 1020 1021 if (!uxa_screen->info->check_composite(op, src, NULL, dst, 1022 extents->x2 - extents->x1, 1023 extents->y2 - extents->y1)) { 1024 if (op == PictOpSrc || op == PictOpClear) { 1025 FreePicture(src, 0); 1026 goto try_solid; 1027 } 1028 1029 goto err_src; 1030 } 1031 1032 if (!uxa_screen->info->check_composite_texture || 1033 !uxa_screen->info->check_composite_texture(screen, src)) { 1034 PicturePtr solid; 1035 int src_off_x, src_off_y; 1036 1037 solid = uxa_acquire_solid(screen, src->pSourcePict); 1038 FreePicture(src, 0); 1039 1040 src = solid; 1041 src_pixmap = uxa_get_offscreen_pixmap(src->pDrawable, 1042 &src_off_x, &src_off_y); 1043 if (!src_pixmap) 1044 goto err_src; 1045 } 1046 1047 if (!uxa_screen->info->prepare_composite(op, src, NULL, dst, src_pixmap, NULL, dst_pixmap)) 1048 goto err_src; 1049 1050 while (num_boxes--) { 1051 uxa_screen->info->composite(dst_pixmap, 1052 0, 0, 0, 0, 1053 boxes->x1, 1054 boxes->y1, 1055 boxes->x2 - boxes->x1, 1056 boxes->y2 - boxes->y1); 1057 boxes++; 1058 } 1059 1060 uxa_screen->info->done_composite(dst_pixmap); 1061 FreePicture(src, 0); 1062 } 1063 1064 pixman_region_fini(®ion); 1065 return; 1066 1067err_src: 1068 FreePicture(src, 0); 1069err_region: 1070 pixman_region_fini(®ion); 1071fallback: 1072 uxa_screen->SavedCompositeRects(op, dst, color, num_rects, rects); 1073} 1074 1075static int 1076uxa_try_driver_composite(CARD8 op, 1077 PicturePtr pSrc, 1078 PicturePtr pMask, 1079 PicturePtr pDst, 1080 INT16 xSrc, INT16 ySrc, 1081 INT16 xMask, INT16 yMask, 1082 INT16 xDst, INT16 yDst, 1083 CARD16 width, CARD16 height) 1084{ 1085 ScreenPtr screen = pDst->pDrawable->pScreen; 1086 uxa_screen_t *uxa_screen = uxa_get_screen(screen); 1087 RegionRec region; 1088 BoxPtr pbox; 1089 int nbox; 1090 int xDst_copy = 0, yDst_copy = 0; 1091 int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; 1092 PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix; 1093 PicturePtr localSrc, localMask = NULL; 1094 PicturePtr localDst = pDst; 1095 1096 if (uxa_screen->info->check_composite && 1097 !(*uxa_screen->info->check_composite) (op, pSrc, pMask, pDst, width, height)) 1098 return -1; 1099 1100 if (uxa_screen->info->check_composite_target && 1101 !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) { 1102 int depth = pDst->pDrawable->depth; 1103 PixmapPtr pixmap; 1104 int error; 1105 GCPtr gc; 1106 1107 pixmap = uxa_get_drawable_pixmap(pDst->pDrawable); 1108 if (uxa_screen->info->check_copy && 1109 !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES)) 1110 return -1; 1111 1112 pixmap = screen->CreatePixmap(screen, 1113 width, height, depth, 1114 CREATE_PIXMAP_USAGE_SCRATCH); 1115 if (!pixmap) 1116 return 0; 1117 1118 gc = GetScratchGC(depth, screen); 1119 if (!gc) { 1120 screen->DestroyPixmap(pixmap); 1121 return 0; 1122 } 1123 1124 ValidateGC(&pixmap->drawable, gc); 1125 gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc, 1126 xDst, yDst, width, height, 0, 0); 1127 FreeScratchGC(gc); 1128 1129 xDst_copy = xDst; xDst = 0; 1130 yDst_copy = yDst; yDst = 0; 1131 1132 localDst = CreatePicture(0, &pixmap->drawable, 1133 PictureMatchFormat(screen, depth, pDst->format), 1134 0, 0, serverClient, &error); 1135 screen->DestroyPixmap(pixmap); 1136 1137 if (!localDst) 1138 return 0; 1139 1140 ValidatePicture(localDst); 1141 } 1142 1143 pDstPix = 1144 uxa_get_offscreen_pixmap(localDst->pDrawable, &dst_off_x, &dst_off_y); 1145 if (!pDstPix) { 1146 if (localDst != pDst) 1147 FreePicture(localDst, 0); 1148 return -1; 1149 } 1150 1151 xDst += localDst->pDrawable->x; 1152 yDst += localDst->pDrawable->y; 1153 1154 localSrc = uxa_acquire_source(screen, pSrc, 1155 xSrc, ySrc, 1156 width, height, 1157 &xSrc, &ySrc); 1158 if (!localSrc) { 1159 if (localDst != pDst) 1160 FreePicture(localDst, 0); 1161 return 0; 1162 } 1163 1164 if (pMask) { 1165 localMask = uxa_acquire_mask(screen, pMask, 1166 xMask, yMask, 1167 width, height, 1168 &xMask, &yMask); 1169 if (!localMask) { 1170 if (localSrc != pSrc) 1171 FreePicture(localSrc, 0); 1172 if (localDst != pDst) 1173 FreePicture(localDst, 0); 1174 1175 return 0; 1176 } 1177 } 1178 1179 if (!miComputeCompositeRegion(®ion, localSrc, localMask, localDst, 1180 xSrc, ySrc, xMask, yMask, xDst, yDst, 1181 width, height)) { 1182 if (localSrc != pSrc) 1183 FreePicture(localSrc, 0); 1184 if (localMask && localMask != pMask) 1185 FreePicture(localMask, 0); 1186 if (localDst != pDst) 1187 FreePicture(localDst, 0); 1188 1189 return 1; 1190 } 1191 1192 if (localSrc->pDrawable) { 1193 pSrcPix = uxa_get_offscreen_pixmap(localSrc->pDrawable, 1194 &src_off_x, &src_off_y); 1195 if (!pSrcPix) { 1196 REGION_UNINIT(screen, ®ion); 1197 1198 if (localSrc != pSrc) 1199 FreePicture(localSrc, 0); 1200 if (localMask && localMask != pMask) 1201 FreePicture(localMask, 0); 1202 if (localDst != pDst) 1203 FreePicture(localDst, 0); 1204 1205 return 0; 1206 } 1207 } else { 1208 pSrcPix = NULL; 1209 } 1210 1211 if (localMask) { 1212 if (localMask->pDrawable) { 1213 pMaskPix = uxa_get_offscreen_pixmap(localMask->pDrawable, 1214 &mask_off_x, &mask_off_y); 1215 if (!pMaskPix) { 1216 REGION_UNINIT(screen, ®ion); 1217 1218 if (localSrc != pSrc) 1219 FreePicture(localSrc, 0); 1220 if (localMask && localMask != pMask) 1221 FreePicture(localMask, 0); 1222 if (localDst != pDst) 1223 FreePicture(localDst, 0); 1224 1225 return 0; 1226 } 1227 } else { 1228 pMaskPix = NULL; 1229 } 1230 } 1231 1232 if (!(*uxa_screen->info->prepare_composite) 1233 (op, localSrc, localMask, localDst, pSrcPix, pMaskPix, pDstPix)) { 1234 REGION_UNINIT(screen, ®ion); 1235 1236 if (localSrc != pSrc) 1237 FreePicture(localSrc, 0); 1238 if (localMask && localMask != pMask) 1239 FreePicture(localMask, 0); 1240 if (localDst != pDst) 1241 FreePicture(localDst, 0); 1242 1243 return -1; 1244 } 1245 1246 if (pMask) { 1247 xMask = xMask + mask_off_x - xDst; 1248 yMask = yMask + mask_off_y - yDst; 1249 } 1250 1251 xSrc = xSrc + src_off_x - xDst; 1252 ySrc = ySrc + src_off_y - yDst; 1253 1254 nbox = REGION_NUM_RECTS(®ion); 1255 pbox = REGION_RECTS(®ion); 1256 while (nbox--) { 1257 (*uxa_screen->info->composite) (pDstPix, 1258 pbox->x1 + xSrc, 1259 pbox->y1 + ySrc, 1260 pbox->x1 + xMask, 1261 pbox->y1 + yMask, 1262 pbox->x1 + dst_off_x, 1263 pbox->y1 + dst_off_y, 1264 pbox->x2 - pbox->x1, 1265 pbox->y2 - pbox->y1); 1266 pbox++; 1267 } 1268 (*uxa_screen->info->done_composite) (pDstPix); 1269 1270 REGION_UNINIT(screen, ®ion); 1271 1272 if (localSrc != pSrc) 1273 FreePicture(localSrc, 0); 1274 if (localMask && localMask != pMask) 1275 FreePicture(localMask, 0); 1276 1277 if (localDst != pDst) { 1278 GCPtr gc; 1279 1280 gc = GetScratchGC(pDst->pDrawable->depth, screen); 1281 if (gc) { 1282 ValidateGC(pDst->pDrawable, gc); 1283 gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc, 1284 0, 0, width, height, xDst_copy, yDst_copy); 1285 FreeScratchGC(gc); 1286 } 1287 1288 FreePicture(localDst, 0); 1289 } 1290 1291 return 1; 1292} 1293 1294/** 1295 * uxa_try_magic_two_pass_composite_helper implements PictOpOver using two passes of 1296 * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component 1297 * alpha and limited 1-tmu cards. 1298 * 1299 * From http://anholt.livejournal.com/32058.html: 1300 * 1301 * The trouble is that component-alpha rendering requires two different sources 1302 * for blending: one for the source value to the blender, which is the 1303 * per-channel multiplication of source and mask, and one for the source alpha 1304 * for multiplying with the destination channels, which is the multiplication 1305 * of the source channels by the mask alpha. So the equation for Over is: 1306 * 1307 * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A 1308 * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R 1309 * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G 1310 * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B 1311 * 1312 * But we can do some simpler operations, right? How about PictOpOutReverse, 1313 * which has a source factor of 0 and dest factor of (1 - source alpha). We 1314 * can get the source alpha value (srca.X = src.A * mask.X) out of the texture 1315 * blenders pretty easily. So we can do a component-alpha OutReverse, which 1316 * gets us: 1317 * 1318 * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A 1319 * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R 1320 * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G 1321 * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B 1322 * 1323 * OK. And if an op doesn't use the source alpha value for the destination 1324 * factor, then we can do the channel multiplication in the texture blenders 1325 * to get the source value, and ignore the source alpha that we wouldn't use. 1326 * We've supported this in the Radeon driver for a long time. An example would 1327 * be PictOpAdd, which does: 1328 * 1329 * dst.A = src.A * mask.A + dst.A 1330 * dst.R = src.R * mask.R + dst.R 1331 * dst.G = src.G * mask.G + dst.G 1332 * dst.B = src.B * mask.B + dst.B 1333 * 1334 * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right 1335 * after it, we get: 1336 * 1337 * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A) 1338 * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R) 1339 * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G) 1340 * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B) 1341 */ 1342 1343static int 1344uxa_try_magic_two_pass_composite_helper(CARD8 op, 1345 PicturePtr pSrc, 1346 PicturePtr pMask, 1347 PicturePtr pDst, 1348 INT16 xSrc, INT16 ySrc, 1349 INT16 xMask, INT16 yMask, 1350 INT16 xDst, INT16 yDst, 1351 CARD16 width, CARD16 height) 1352{ 1353 ScreenPtr screen = pDst->pDrawable->pScreen; 1354 uxa_screen_t *uxa_screen = uxa_get_screen(screen); 1355 PicturePtr localDst = pDst; 1356 int xDst_copy = 0, yDst_copy = 0; 1357 1358 assert(op == PictOpOver); 1359 1360 if (uxa_screen->info->check_composite && 1361 (!(*uxa_screen->info->check_composite) (PictOpOutReverse, pSrc, 1362 pMask, pDst, width, height) 1363 || !(*uxa_screen->info->check_composite) (PictOpAdd, pSrc, pMask, 1364 pDst, width, height))) { 1365 return -1; 1366 } 1367 1368 if (uxa_screen->info->check_composite_target && 1369 !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) { 1370 int depth = pDst->pDrawable->depth; 1371 PixmapPtr pixmap; 1372 int error; 1373 GCPtr gc; 1374 1375 pixmap = uxa_get_drawable_pixmap(pDst->pDrawable); 1376 if (uxa_screen->info->check_copy && 1377 !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES)) 1378 return -1; 1379 1380 pixmap = screen->CreatePixmap(screen, 1381 width, height, depth, 1382 CREATE_PIXMAP_USAGE_SCRATCH); 1383 if (!pixmap) 1384 return 0; 1385 1386 gc = GetScratchGC(depth, screen); 1387 if (!gc) { 1388 screen->DestroyPixmap(pixmap); 1389 return 0; 1390 } 1391 1392 ValidateGC(&pixmap->drawable, gc); 1393 gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc, 1394 xDst, yDst, width, height, 0, 0); 1395 FreeScratchGC(gc); 1396 1397 xDst_copy = xDst; xDst = 0; 1398 yDst_copy = yDst; yDst = 0; 1399 1400 localDst = CreatePicture(0, &pixmap->drawable, 1401 PictureMatchFormat(screen, depth, pDst->format), 1402 0, 0, serverClient, &error); 1403 screen->DestroyPixmap(pixmap); 1404 1405 if (!localDst) 1406 return 0; 1407 1408 ValidatePicture(localDst); 1409 } 1410 1411 /* Now, we think we should be able to accelerate this operation. First, 1412 * composite the destination to be the destination times the source alpha 1413 * factors. 1414 */ 1415 uxa_composite(PictOpOutReverse, pSrc, pMask, localDst, 1416 xSrc, ySrc, 1417 xMask, yMask, 1418 xDst, yDst, 1419 width, height); 1420 1421 /* Then, add in the source value times the destination alpha factors (1.0). 1422 */ 1423 uxa_composite(PictOpAdd, pSrc, pMask, localDst, 1424 xSrc, ySrc, 1425 xMask, yMask, 1426 xDst, yDst, 1427 width, height); 1428 1429 if (localDst != pDst) { 1430 GCPtr gc; 1431 1432 gc = GetScratchGC(pDst->pDrawable->depth, screen); 1433 if (gc) { 1434 ValidateGC(pDst->pDrawable, gc); 1435 gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc, 1436 0, 0, width, height, xDst_copy, yDst_copy); 1437 FreeScratchGC(gc); 1438 } 1439 1440 FreePicture(localDst, 0); 1441 } 1442 1443 return 1; 1444} 1445 1446static int 1447compatible_formats (CARD8 op, PicturePtr dst, PicturePtr src) 1448{ 1449 if (op == PictOpSrc) { 1450 if (src->format == dst->format) 1451 return 1; 1452 1453 /* Is the destination an alpha-less version of source? */ 1454 if (dst->format == PICT_FORMAT(PICT_FORMAT_BPP(src->format), 1455 PICT_FORMAT_TYPE(src->format), 1456 0, 1457 PICT_FORMAT_R(src->format), 1458 PICT_FORMAT_G(src->format), 1459 PICT_FORMAT_B(src->format))) 1460 return 1; 1461 1462 /* XXX xrgb is promoted to argb during image upload... */ 1463#if 0 1464 if (dst->format == PICT_a8r8g8b8 && src->format == PICT_x8r8g8b8) 1465 return 1; 1466#endif 1467 } else if (op == PictOpOver) { 1468 if (PICT_FORMAT_A(src->format)) 1469 return 0; 1470 1471 return src->format == dst->format; 1472 } 1473 1474 return 0; 1475} 1476 1477static int 1478drawable_contains (DrawablePtr drawable, int x, int y, int w, int h) 1479{ 1480 if (x < 0 || y < 0) 1481 return FALSE; 1482 1483 if (x + w > drawable->width) 1484 return FALSE; 1485 1486 if (y + h > drawable->height) 1487 return FALSE; 1488 1489 return TRUE; 1490} 1491 1492void 1493uxa_composite(CARD8 op, 1494 PicturePtr pSrc, 1495 PicturePtr pMask, 1496 PicturePtr pDst, 1497 INT16 xSrc, INT16 ySrc, 1498 INT16 xMask, INT16 yMask, 1499 INT16 xDst, INT16 yDst, 1500 CARD16 width, CARD16 height) 1501{ 1502 uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); 1503 int ret = -1; 1504 Bool saveSrcRepeat = pSrc->repeat; 1505 Bool saveMaskRepeat = pMask ? pMask->repeat : 0; 1506 RegionRec region; 1507 int tx, ty; 1508 1509 if (uxa_screen->swappedOut || uxa_screen->force_fallback) 1510 goto fallback; 1511 1512 if (!uxa_drawable_is_offscreen(pDst->pDrawable)) 1513 goto fallback; 1514 1515 if (pDst->alphaMap || pSrc->alphaMap || (pMask && pMask->alphaMap)) 1516 goto fallback; 1517 1518 /* Remove repeat in source if useless */ 1519 if (pSrc->pDrawable && pSrc->repeat && pSrc->filter != PictFilterConvolution && 1520 transform_is_integer_translation(pSrc->transform, &tx, &ty) && 1521 (pSrc->pDrawable->width > 1 || pSrc->pDrawable->height > 1) && 1522 drawable_contains(pSrc->pDrawable, xSrc + tx, ySrc + ty, width, height)) 1523 pSrc->repeat = 0; 1524 1525 if (!pMask) { 1526 if (op == PictOpClear) { 1527 PicturePtr clear = uxa_solid_clear(pDst->pDrawable->pScreen); 1528 if (clear && 1529 uxa_try_driver_solid_fill(clear, pDst, 1530 xSrc, ySrc, 1531 xDst, yDst, 1532 width, height) == 1) 1533 goto done; 1534 } 1535 1536 if (pSrc->pDrawable == NULL) { 1537 if (pSrc->pSourcePict) { 1538 SourcePict *source = pSrc->pSourcePict; 1539 if (source->type == SourcePictTypeSolidFill) { 1540 if (op == PictOpSrc || 1541 (op == PictOpOver && 1542 (source->solidFill.color & 0xff000000) == 0xff000000)) { 1543 ret = uxa_try_driver_solid_fill(pSrc, pDst, 1544 xSrc, ySrc, 1545 xDst, yDst, 1546 width, height); 1547 if (ret == 1) 1548 goto done; 1549 } 1550 } 1551 } 1552 } else if (pSrc->pDrawable->width == 1 && 1553 pSrc->pDrawable->height == 1 && 1554 pSrc->repeat && 1555 (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) { 1556 ret = uxa_try_driver_solid_fill(pSrc, pDst, 1557 xSrc, ySrc, 1558 xDst, yDst, 1559 width, height); 1560 if (ret == 1) 1561 goto done; 1562 } else if (compatible_formats (op, pDst, pSrc) && 1563 pSrc->filter != PictFilterConvolution && 1564 transform_is_integer_translation(pSrc->transform, &tx, &ty)) { 1565 if (!pSrc->repeat && 1566 drawable_contains(pSrc->pDrawable, 1567 xSrc + tx, ySrc + ty, 1568 width, height)) { 1569 xDst += pDst->pDrawable->x; 1570 yDst += pDst->pDrawable->y; 1571 xSrc += pSrc->pDrawable->x + tx; 1572 ySrc += pSrc->pDrawable->y + ty; 1573 1574 if (!miComputeCompositeRegion 1575 (®ion, pSrc, pMask, pDst, xSrc, ySrc, 1576 xMask, yMask, xDst, yDst, width, height)) 1577 goto done; 1578 1579 uxa_copy_n_to_n(pSrc->pDrawable, 1580 pDst->pDrawable, NULL, 1581 REGION_RECTS(®ion), 1582 REGION_NUM_RECTS(®ion), 1583 xSrc - xDst, ySrc - yDst, FALSE, 1584 FALSE, 0, NULL); 1585 REGION_UNINIT(pDst->pDrawable->pScreen, 1586 ®ion); 1587 goto done; 1588 } else if (pSrc->repeat && pSrc->repeatType == RepeatNormal && 1589 pSrc->pDrawable->type == DRAWABLE_PIXMAP) { 1590 DDXPointRec patOrg; 1591 1592 /* Let's see if the driver can do the repeat 1593 * in one go 1594 */ 1595 if (uxa_screen->info->prepare_composite) { 1596 ret = uxa_try_driver_composite(op, pSrc, 1597 pMask, pDst, 1598 xSrc, ySrc, 1599 xMask, yMask, 1600 xDst, yDst, 1601 width, height); 1602 if (ret == 1) 1603 goto done; 1604 } 1605 1606 /* Now see if we can use 1607 * uxa_fill_region_tiled() 1608 */ 1609 xDst += pDst->pDrawable->x; 1610 yDst += pDst->pDrawable->y; 1611 xSrc += pSrc->pDrawable->x + tx; 1612 ySrc += pSrc->pDrawable->y + ty; 1613 1614 if (!miComputeCompositeRegion 1615 (®ion, pSrc, pMask, pDst, xSrc, ySrc, 1616 xMask, yMask, xDst, yDst, width, height)) 1617 goto done; 1618 1619 /* pattern origin is the point in the 1620 * destination drawable 1621 * corresponding to (0,0) in the source */ 1622 patOrg.x = xDst - xSrc; 1623 patOrg.y = yDst - ySrc; 1624 1625 ret = uxa_fill_region_tiled(pDst->pDrawable, 1626 ®ion, 1627 (PixmapPtr) pSrc-> 1628 pDrawable, &patOrg, 1629 FB_ALLONES, GXcopy); 1630 1631 REGION_UNINIT(pDst->pDrawable->pScreen, 1632 ®ion); 1633 1634 if (ret) 1635 goto done; 1636 } 1637 } 1638 } 1639 1640 /* Remove repeat in mask if useless */ 1641 if (pMask && pMask->pDrawable && pMask->repeat && 1642 pMask->filter != PictFilterConvolution && 1643 transform_is_integer_translation(pMask->transform, &tx, &ty) && 1644 (pMask->pDrawable->width > 1 || pMask->pDrawable->height > 1) && 1645 drawable_contains(pMask->pDrawable, xMask + tx, yMask + ty, width, height)) 1646 pMask->repeat = 0; 1647 1648 if (uxa_screen->info->prepare_composite) { 1649 Bool isSrcSolid; 1650 1651 ret = 1652 uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc, ySrc, 1653 xMask, yMask, xDst, yDst, width, 1654 height); 1655 if (ret == 1) 1656 goto done; 1657 1658 /* For generic masks and solid src pictures, mach64 can do 1659 * Over in two passes, similar to the component-alpha case. 1660 */ 1661 1662 isSrcSolid = 1663 pSrc->pDrawable ? 1664 pSrc->pDrawable->width == 1 && 1665 pSrc->pDrawable->height == 1 && 1666 pSrc->repeat : 1667 pSrc->pSourcePict ? 1668 pSrc->pSourcePict->type == SourcePictTypeSolidFill : 1669 0; 1670 1671 /* If we couldn't do the Composite in a single pass, and it 1672 * was a component-alpha Over, see if we can do it in two 1673 * passes with an OutReverse and then an Add. 1674 */ 1675 if (ret == -1 && op == PictOpOver && pMask && 1676 (pMask->componentAlpha || isSrcSolid)) { 1677 ret = 1678 uxa_try_magic_two_pass_composite_helper(op, pSrc, 1679 pMask, pDst, 1680 xSrc, ySrc, 1681 xMask, yMask, 1682 xDst, yDst, 1683 width, height); 1684 if (ret == 1) 1685 goto done; 1686 } 1687 1688 } 1689 1690fallback: 1691 uxa_print_composite_fallback("uxa_composite", 1692 op, pSrc, pMask, pDst); 1693 1694 uxa_check_composite(op, pSrc, pMask, pDst, xSrc, ySrc, 1695 xMask, yMask, xDst, yDst, width, height); 1696 1697done: 1698 pSrc->repeat = saveSrcRepeat; 1699 if (pMask) 1700 pMask->repeat = saveMaskRepeat; 1701} 1702#endif 1703 1704/** 1705 * Same as miCreateAlphaPicture, except it uses uxa_check_poly_fill_rect instead 1706 * of PolyFillRect to initialize the pixmap after creating it, to prevent 1707 * the pixmap from being migrated. 1708 * 1709 * See the comments about uxa_trapezoids and uxa_triangles. 1710 */ 1711static PicturePtr 1712uxa_create_alpha_picture(ScreenPtr pScreen, 1713 PicturePtr pDst, 1714 PictFormatPtr pPictFormat, CARD16 width, CARD16 height) 1715{ 1716 PixmapPtr pPixmap; 1717 PicturePtr pPicture; 1718 int error; 1719 1720 if (width > 32767 || height > 32767) 1721 return 0; 1722 1723 if (!pPictFormat) { 1724 if (pDst->polyEdge == PolyEdgeSharp) 1725 pPictFormat = PictureMatchFormat(pScreen, 1, PICT_a1); 1726 else 1727 pPictFormat = PictureMatchFormat(pScreen, 8, PICT_a8); 1728 if (!pPictFormat) 1729 return 0; 1730 } 1731 1732 pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 1733 pPictFormat->depth, 1734 UXA_CREATE_PIXMAP_FOR_MAP); 1735 if (!pPixmap) 1736 return 0; 1737 pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, 1738 0, 0, serverClient, &error); 1739 (*pScreen->DestroyPixmap) (pPixmap); 1740 return pPicture; 1741} 1742 1743/** 1744 * uxa_trapezoids is essentially a copy of miTrapezoids that uses 1745 * uxa_create_alpha_picture instead of miCreateAlphaPicture. 1746 * 1747 * The problem with miCreateAlphaPicture is that it calls PolyFillRect 1748 * to initialize the contents after creating the pixmap, which 1749 * causes the pixmap to be moved in for acceleration. The subsequent 1750 * call to RasterizeTrapezoid won't be accelerated however, which 1751 * forces the pixmap to be moved out again. 1752 * 1753 * uxa_create_alpha_picture avoids this roundtrip by using 1754 * uxa_check_poly_fill_rect to initialize the contents. 1755 */ 1756void 1757uxa_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst, 1758 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 1759 int ntrap, xTrapezoid * traps) 1760{ 1761 ScreenPtr screen = dst->pDrawable->pScreen; 1762 BoxRec bounds; 1763 Bool direct; 1764 1765 direct = op == PictOpAdd && miIsSolidAlpha(src); 1766 if (maskFormat || direct) { 1767 miTrapezoidBounds(ntrap, traps, &bounds); 1768 1769 if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 1770 return; 1771 } 1772 1773 /* 1774 * Check for solid alpha add 1775 */ 1776 if (direct) { 1777 DrawablePtr pDraw = dst->pDrawable; 1778 PixmapPtr pixmap = uxa_get_drawable_pixmap(pDraw); 1779 int xoff, yoff; 1780 1781 uxa_get_drawable_deltas(pDraw, pixmap, &xoff, &yoff); 1782 1783 xoff += pDraw->x; 1784 yoff += pDraw->y; 1785 1786 if (uxa_prepare_access(pDraw, NULL, UXA_ACCESS_RW)) { 1787 PictureScreenPtr ps = GetPictureScreen(screen); 1788 1789 for (; ntrap; ntrap--, traps++) 1790 (*ps->RasterizeTrapezoid) (dst, traps, 0, 0); 1791 uxa_finish_access(pDraw); 1792 } 1793 } else if (maskFormat) { 1794 PixmapPtr scratch = NULL; 1795 PicturePtr mask; 1796 INT16 xDst, yDst; 1797 INT16 xRel, yRel; 1798 int width, height; 1799 pixman_image_t *image; 1800 pixman_format_code_t format; 1801 1802 xDst = traps[0].left.p1.x >> 16; 1803 yDst = traps[0].left.p1.y >> 16; 1804 1805 width = bounds.x2 - bounds.x1; 1806 height = bounds.y2 - bounds.y1; 1807 1808 format = maskFormat->format | 1809 (BitsPerPixel(maskFormat->depth) << 24); 1810 image = 1811 pixman_image_create_bits(format, width, height, NULL, 0); 1812 if (!image) 1813 return; 1814 1815 for (; ntrap; ntrap--, traps++) 1816 pixman_rasterize_trapezoid(image, 1817 (pixman_trapezoid_t *) traps, 1818 -bounds.x1, -bounds.y1); 1819 if (uxa_drawable_is_offscreen(dst->pDrawable)) { 1820 mask = uxa_picture_from_pixman_image(screen, image, format); 1821 } else { 1822 int error; 1823 1824 scratch = GetScratchPixmapHeader(screen, width, height, 1825 PIXMAN_FORMAT_DEPTH(format), 1826 PIXMAN_FORMAT_BPP(format), 1827 pixman_image_get_stride(image), 1828 pixman_image_get_data(image)); 1829 mask = CreatePicture(0, &scratch->drawable, 1830 PictureMatchFormat(screen, 1831 PIXMAN_FORMAT_DEPTH(format), 1832 format), 1833 0, 0, serverClient, &error); 1834 } 1835 if (!mask) { 1836 if (scratch) 1837 FreeScratchPixmapHeader(scratch); 1838 pixman_image_unref(image); 1839 return; 1840 } 1841 1842 xRel = bounds.x1 + xSrc - xDst; 1843 yRel = bounds.y1 + ySrc - yDst; 1844 CompositePicture(op, src, mask, dst, 1845 xRel, yRel, 1846 0, 0, 1847 bounds.x1, bounds.y1, 1848 width, height); 1849 FreePicture(mask, 0); 1850 1851 if (scratch) 1852 FreeScratchPixmapHeader(scratch); 1853 pixman_image_unref(image); 1854 } else { 1855 if (dst->polyEdge == PolyEdgeSharp) 1856 maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 1857 else 1858 maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 1859 for (; ntrap; ntrap--, traps++) 1860 uxa_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, 1861 1, traps); 1862 } 1863} 1864 1865/** 1866 * uxa_triangles is essentially a copy of miTriangles that uses 1867 * uxa_create_alpha_picture instead of miCreateAlphaPicture. 1868 * 1869 * The problem with miCreateAlphaPicture is that it calls PolyFillRect 1870 * to initialize the contents after creating the pixmap, which 1871 * causes the pixmap to be moved in for acceleration. The subsequent 1872 * call to AddTriangles won't be accelerated however, which forces the pixmap 1873 * to be moved out again. 1874 * 1875 * uxa_create_alpha_picture avoids this roundtrip by using 1876 * uxa_check_poly_fill_rect to initialize the contents. 1877 */ 1878void 1879uxa_triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, 1880 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 1881 int ntri, xTriangle * tris) 1882{ 1883 ScreenPtr pScreen = pDst->pDrawable->pScreen; 1884 PictureScreenPtr ps = GetPictureScreen(pScreen); 1885 BoxRec bounds; 1886 Bool direct = op == PictOpAdd && miIsSolidAlpha(pSrc); 1887 1888 if (maskFormat || direct) { 1889 miTriangleBounds(ntri, tris, &bounds); 1890 1891 if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 1892 return; 1893 } 1894 1895 /* 1896 * Check for solid alpha add 1897 */ 1898 if (direct) { 1899 DrawablePtr pDraw = pDst->pDrawable; 1900 if (uxa_prepare_access(pDraw, NULL, UXA_ACCESS_RW)) { 1901 (*ps->AddTriangles) (pDst, 0, 0, ntri, tris); 1902 uxa_finish_access(pDraw); 1903 } 1904 } else if (maskFormat) { 1905 PicturePtr pPicture; 1906 INT16 xDst, yDst; 1907 INT16 xRel, yRel; 1908 int width = bounds.x2 - bounds.x1; 1909 int height = bounds.y2 - bounds.y1; 1910 GCPtr pGC; 1911 xRectangle rect; 1912 1913 xDst = tris[0].p1.x >> 16; 1914 yDst = tris[0].p1.y >> 16; 1915 1916 pPicture = uxa_create_alpha_picture(pScreen, pDst, maskFormat, 1917 width, height); 1918 if (!pPicture) 1919 return; 1920 1921 /* Clear the alpha picture to 0. */ 1922 pGC = GetScratchGC(pPicture->pDrawable->depth, pScreen); 1923 if (!pGC) { 1924 FreePicture(pPicture, 0); 1925 return; 1926 } 1927 ValidateGC(pPicture->pDrawable, pGC); 1928 rect.x = 0; 1929 rect.y = 0; 1930 rect.width = width; 1931 rect.height = height; 1932 uxa_check_poly_fill_rect(pPicture->pDrawable, pGC, 1, &rect); 1933 FreeScratchGC(pGC); 1934 1935 if (uxa_prepare_access(pPicture->pDrawable, NULL, UXA_ACCESS_RW)) { 1936 (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, 1937 ntri, tris); 1938 uxa_finish_access(pPicture->pDrawable); 1939 } 1940 1941 xRel = bounds.x1 + xSrc - xDst; 1942 yRel = bounds.y1 + ySrc - yDst; 1943 CompositePicture(op, pSrc, pPicture, pDst, 1944 xRel, yRel, 0, 0, bounds.x1, bounds.y1, 1945 bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); 1946 FreePicture(pPicture, 0); 1947 } else { 1948 if (pDst->polyEdge == PolyEdgeSharp) 1949 maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1); 1950 else 1951 maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8); 1952 1953 for (; ntri; ntri--, tris++) 1954 uxa_triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, 1955 tris); 1956 } 1957} 1958