1/* 2 * Copyright (c) 2007 David Turner 3 * Copyright (c) 2008 M Joonas Pihlaja 4 * Copyright (c) 2011 Intel Corporation 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 * 25 * Authors: 26 * Chris Wilson <chris@chris-wilson.co.uk> 27 * 28 */ 29 30#ifdef HAVE_CONFIG_H 31#include "config.h" 32#endif 33 34#include "sna.h" 35#include "sna_render.h" 36#include "sna_render_inline.h" 37#include "sna_trapezoids.h" 38#include "fb/fbpict.h" 39 40#include <mipict.h> 41 42/* TODO: Emit unantialiased and MSAA triangles. */ 43 44#ifndef MAX 45#define MAX(x,y) ((x) >= (y) ? (x) : (y)) 46#endif 47 48#ifndef MIN 49#define MIN(x,y) ((x) <= (y) ? (x) : (y)) 50#endif 51 52#define region_count(r) ((r)->data ? (r)->data->numRects : 1) 53#define region_boxes(r) ((r)->data ? (BoxPtr)((r)->data + 1) : &(r)->extents) 54 55#if HAS_DEBUG_FULL 56static void _assert_pixmap_contains_box(PixmapPtr pixmap, BoxPtr box, const char *function) 57{ 58 if (box->x1 < 0 || box->y1 < 0 || 59 box->x2 > pixmap->drawable.width || 60 box->y2 > pixmap->drawable.height) 61 { 62 FatalError("%s: damage box is beyond the pixmap: box=(%d, %d), (%d, %d), pixmap=(%d, %d)\n", 63 function, 64 box->x1, box->y1, box->x2, box->y2, 65 pixmap->drawable.width, 66 pixmap->drawable.height); 67 } 68} 69#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__) 70#else 71#define assert_pixmap_contains_box(p, b) 72#endif 73 74static void apply_damage(struct sna_composite_op *op, RegionPtr region) 75{ 76 DBG(("%s: damage=%p, region=%dx[(%d, %d), (%d, %d)]\n", 77 __FUNCTION__, op->damage, 78 region_num_rects(region), 79 region->extents.x1, region->extents.y1, 80 region->extents.x2, region->extents.y2)); 81 82 if (op->damage == NULL) 83 return; 84 85 RegionTranslate(region, op->dst.x, op->dst.y); 86 87 assert_pixmap_contains_box(op->dst.pixmap, RegionExtents(region)); 88 if (sna_damage_add_to_pixmap(op->damage, region, op->dst.pixmap)) 89 op->damage = NULL; 90} 91 92static void _apply_damage_box(struct sna_composite_op *op, const BoxRec *box) 93{ 94 BoxRec r; 95 96 r.x1 = box->x1 + op->dst.x; 97 r.x2 = box->x2 + op->dst.x; 98 r.y1 = box->y1 + op->dst.y; 99 r.y2 = box->y2 + op->dst.y; 100 101 assert_pixmap_contains_box(op->dst.pixmap, &r); 102 sna_damage_add_box(op->damage, &r); 103} 104 105inline static void apply_damage_box(struct sna_composite_op *op, const BoxRec *box) 106{ 107 if (op->damage) 108 _apply_damage_box(op, box); 109} 110 111bool 112composite_aligned_boxes(struct sna *sna, 113 CARD8 op, 114 PicturePtr src, 115 PicturePtr dst, 116 PictFormatPtr maskFormat, 117 INT16 src_x, INT16 src_y, 118 int ntrap, const xTrapezoid *traps, 119 bool force_fallback) 120{ 121 BoxRec stack_boxes[64], *boxes; 122 pixman_region16_t region, clip; 123 struct sna_composite_op tmp; 124 int16_t dst_x, dst_y; 125 bool ret = true; 126 int dx, dy, n, num_boxes; 127 128 if (NO_ALIGNED_BOXES) 129 return false; 130 131 DBG(("%s: pixmap=%ld, nboxes=%d, dx=(%d, %d)\n", __FUNCTION__, 132 get_drawable_pixmap(dst->pDrawable)->drawable.serialNumber, 133 ntrap, dst->pDrawable->x, dst->pDrawable->y)); 134 135 boxes = stack_boxes; 136 if (ntrap > (int)ARRAY_SIZE(stack_boxes)) { 137 boxes = malloc(sizeof(BoxRec)*ntrap); 138 if (boxes == NULL) 139 return false; 140 } 141 142 dx = dst->pDrawable->x; 143 dy = dst->pDrawable->y; 144 145 region.extents.x1 = region.extents.y1 = 32767; 146 region.extents.x2 = region.extents.y2 = -32767; 147 num_boxes = 0; 148 for (n = 0; n < ntrap; n++) { 149 boxes[num_boxes].x1 = dx + pixman_fixed_to_int(traps[n].left.p1.x + pixman_fixed_1_minus_e/2); 150 boxes[num_boxes].y1 = dy + pixman_fixed_to_int(traps[n].top + pixman_fixed_1_minus_e/2); 151 boxes[num_boxes].x2 = dx + pixman_fixed_to_int(traps[n].right.p2.x + pixman_fixed_1_minus_e/2); 152 boxes[num_boxes].y2 = dy + pixman_fixed_to_int(traps[n].bottom + pixman_fixed_1_minus_e/2); 153 154 if (boxes[num_boxes].x1 >= boxes[num_boxes].x2) 155 continue; 156 if (boxes[num_boxes].y1 >= boxes[num_boxes].y2) 157 continue; 158 159 if (boxes[num_boxes].x1 < region.extents.x1) 160 region.extents.x1 = boxes[num_boxes].x1; 161 if (boxes[num_boxes].x2 > region.extents.x2) 162 region.extents.x2 = boxes[num_boxes].x2; 163 164 if (boxes[num_boxes].y1 < region.extents.y1) 165 region.extents.y1 = boxes[num_boxes].y1; 166 if (boxes[num_boxes].y2 > region.extents.y2) 167 region.extents.y2 = boxes[num_boxes].y2; 168 169 num_boxes++; 170 } 171 172 if (num_boxes == 0) 173 goto free_boxes; 174 175 trapezoid_origin(&traps[0].left, &dst_x, &dst_y); 176 177 DBG(("%s: extents (%d, %d), (%d, %d) offset of (%d, %d), origin (%d, %d)\n", 178 __FUNCTION__, 179 region.extents.x1, region.extents.y1, 180 region.extents.x2, region.extents.y2, 181 region.extents.x1 - boxes[0].x1, 182 region.extents.y1 - boxes[0].y1, 183 dst_x, dst_y)); 184 185 if (!sna_compute_composite_region(&clip, 186 src, NULL, dst, 187 src_x + region.extents.x1 - dst_x - dx, 188 src_y + region.extents.y1 - dst_y - dy, 189 0, 0, 190 region.extents.x1 - dx, region.extents.y1 - dy, 191 region.extents.x2 - region.extents.x1, 192 region.extents.y2 - region.extents.y1)) { 193 DBG(("%s: trapezoids do not intersect drawable clips\n", 194 __FUNCTION__)) ; 195 goto done; 196 } 197 198 if (op == PictOpClear && sna->clear) 199 src = sna->clear; 200 201 DBG(("%s: clipped extents (%d, %d), (%d, %d); now offset by (%d, %d), origin (%d, %d)\n", 202 __FUNCTION__, 203 clip.extents.x1, clip.extents.y1, 204 clip.extents.x2, clip.extents.y2, 205 clip.extents.x1 - boxes[0].x1, 206 clip.extents.y1 - boxes[0].y1, 207 dst_x, dst_y)); 208 209 if (force_fallback || 210 !sna->render.composite(sna, op, src, NULL, dst, 211 src_x + clip.extents.x1 - dst_x, 212 src_y + clip.extents.y1 - dst_y, 213 0, 0, 214 clip.extents.x1, clip.extents.y1, 215 clip.extents.x2 - clip.extents.x1, 216 clip.extents.y2 - clip.extents.y1, 217 (clip.data || num_boxes > 1) ? COMPOSITE_PARTIAL : 0, 218 memset(&tmp, 0, sizeof(tmp)))) { 219 unsigned int flags; 220 const pixman_box16_t *b; 221 int i, count; 222 223 DBG(("%s: composite render op not supported\n", 224 __FUNCTION__)); 225 226 flags = MOVE_READ | MOVE_WRITE; 227 if (op <= PictOpSrc) { 228 flags |= MOVE_INPLACE_HINT; 229 if (n == 1) 230 flags &= ~MOVE_READ; 231 } 232 233 if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &clip, flags)) 234 goto done; 235 if (dst->alphaMap && 236 !sna_drawable_move_to_cpu(dst->alphaMap->pDrawable, 237 MOVE_READ | MOVE_WRITE)) 238 goto done; 239 if (src->pDrawable) { 240 if (!sna_drawable_move_to_cpu(src->pDrawable, 241 MOVE_READ)) 242 goto done; 243 if (src->alphaMap && 244 !sna_drawable_move_to_cpu(src->alphaMap->pDrawable, 245 MOVE_READ)) 246 goto done; 247 } 248 249 DBG(("%s: fbComposite()\n", __FUNCTION__)); 250 src_x -= dst_x - dx; 251 src_y -= dst_y - dy; 252 if (maskFormat) { 253 pixman_region_init_rects(®ion, boxes, num_boxes); 254 RegionIntersect(®ion, ®ion, &clip); 255 256 if (sigtrap_get() == 0) { 257 b = region_rects(®ion); 258 count = region_num_rects(®ion); 259 for (i = 0; i < count; i++) { 260 fbComposite(op, src, NULL, dst, 261 src_x + b[i].x1, 262 src_y + b[i].y1, 263 0, 0, 264 b[i].x1, b[i].y1, 265 b[i].x2 - b[i].x1, b[i].y2 - b[i].y1); 266 } 267 sigtrap_put(); 268 } 269 pixman_region_fini(®ion); 270 } else { 271 for (n = 0; n < num_boxes; n++) { 272 pixman_region_init_rects(®ion, &boxes[n], 1); 273 RegionIntersect(®ion, ®ion, &clip); 274 b = region_rects(®ion); 275 count = region_num_rects(®ion); 276 if (sigtrap_get() == 0) { 277 for (i = 0; i < count; i++) { 278 fbComposite(op, src, NULL, dst, 279 src_x + b[i].x1, 280 src_y + b[i].y1, 281 0, 0, 282 b[i].x1, b[i].y1, 283 b[i].x2 - b[i].x1, b[i].y2 - b[i].y1); 284 } 285 sigtrap_put(); 286 } 287 pixman_region_fini(®ion); 288 pixman_region_fini(®ion); 289 } 290 } 291 ret = true; 292 goto done; 293 } 294 295 if (maskFormat || 296 (op == PictOpSrc || op == PictOpClear) || 297 num_boxes == 1) { 298 pixman_region_init_rects(®ion, boxes, num_boxes); 299 RegionIntersect(®ion, ®ion, &clip); 300 if (region_num_rects(®ion)) { 301 tmp.boxes(sna, &tmp, 302 region_rects(®ion), 303 region_num_rects(®ion)); 304 apply_damage(&tmp, ®ion); 305 } 306 pixman_region_fini(®ion); 307 } else { 308 for (n = 0; n < num_boxes; n++) { 309 pixman_region_init_rects(®ion, &boxes[n], 1); 310 RegionIntersect(®ion, ®ion, &clip); 311 if (region_num_rects(®ion)) { 312 tmp.boxes(sna, &tmp, 313 region_rects(®ion), 314 region_num_rects(®ion)); 315 apply_damage(&tmp, ®ion); 316 } 317 pixman_region_fini(®ion); 318 } 319 } 320 tmp.done(sna, &tmp); 321 322done: 323 REGION_UNINIT(NULL, &clip); 324free_boxes: 325 if (boxes != stack_boxes) 326 free(boxes); 327 328 return ret; 329} 330 331static inline int grid_coverage(int samples, pixman_fixed_t f) 332{ 333 return (samples * pixman_fixed_frac(f) + pixman_fixed_1/2) / pixman_fixed_1; 334} 335 336inline static void 337composite_unaligned_box(struct sna *sna, 338 struct sna_composite_spans_op *tmp, 339 const BoxRec *box, 340 float opacity, 341 pixman_region16_t *clip) 342{ 343 assert(opacity != 0.); 344 345 if (clip) { 346 pixman_region16_t region; 347 348 pixman_region_init_rects(®ion, box, 1); 349 RegionIntersect(®ion, ®ion, clip); 350 if (region_num_rects(®ion)) 351 tmp->boxes(sna, tmp, 352 region_rects(®ion), 353 region_num_rects(®ion), 354 opacity); 355 pixman_region_fini(®ion); 356 } else 357 tmp->box(sna, tmp, box, opacity); 358} 359 360inline static void 361composite_unaligned_trap_row(struct sna *sna, 362 struct sna_composite_spans_op *tmp, 363 const xTrapezoid *trap, int dx, 364 int y1, int y2, int covered, 365 pixman_region16_t *clip) 366{ 367 BoxRec box; 368 int opacity; 369 int x1, x2; 370#define u8_to_float(x) ((x) * (1.f/255)) 371 372 if (covered == 0) 373 return; 374 375 x1 = dx + pixman_fixed_to_int(trap->left.p1.x); 376 x2 = dx + pixman_fixed_to_int(trap->right.p1.x); 377 if (clip) { 378 if (y2 > clip->extents.y2) 379 y2 = clip->extents.y2; 380 if (y1 < clip->extents.y1) 381 y1 = clip->extents.y1; 382 if (y1 >= y2) 383 return; 384 385 if (x2 < clip->extents.x1 || x1 > clip->extents.x2) 386 return; 387 } 388 389 box.y1 = y1; 390 box.y2 = y2; 391 392 if (x1 == x2) { 393 box.x1 = x1; 394 box.x2 = x2 + 1; 395 396 opacity = covered; 397 opacity *= grid_coverage(SAMPLES_X, trap->right.p1.x) - grid_coverage(SAMPLES_X, trap->left.p1.x); 398 399 if (opacity) 400 composite_unaligned_box(sna, tmp, &box, 401 u8_to_float(opacity), clip); 402 } else { 403 if (pixman_fixed_frac(trap->left.p1.x)) { 404 box.x1 = x1; 405 box.x2 = ++x1; 406 407 opacity = covered; 408 opacity *= SAMPLES_X - grid_coverage(SAMPLES_X, trap->left.p1.x); 409 410 if (opacity) 411 composite_unaligned_box(sna, tmp, &box, 412 u8_to_float(opacity), clip); 413 } 414 415 if (x2 > x1) { 416 box.x1 = x1; 417 box.x2 = x2; 418 419 composite_unaligned_box(sna, tmp, &box, 420 covered == SAMPLES_Y ? 1. : u8_to_float(covered*SAMPLES_X), 421 clip); 422 } 423 424 if (pixman_fixed_frac(trap->right.p1.x)) { 425 box.x1 = x2; 426 box.x2 = x2 + 1; 427 428 opacity = covered; 429 opacity *= grid_coverage(SAMPLES_X, trap->right.p1.x); 430 431 if (opacity) 432 composite_unaligned_box(sna, tmp, &box, 433 u8_to_float(opacity), clip); 434 } 435 } 436} 437 438flatten static void 439composite_unaligned_trap(struct sna *sna, 440 struct sna_composite_spans_op *tmp, 441 const xTrapezoid *trap, 442 int dx, int dy, 443 pixman_region16_t *clip) 444{ 445 int y1, y2; 446 447 y1 = dy + pixman_fixed_to_int(trap->top); 448 y2 = dy + pixman_fixed_to_int(trap->bottom); 449 450 DBG(("%s: y1=%d, y2=%d\n", __FUNCTION__, y1, y2)); 451 452 if (y1 == y2) { 453 composite_unaligned_trap_row(sna, tmp, trap, dx, 454 y1, y1 + 1, 455 grid_coverage(SAMPLES_Y, trap->bottom) - grid_coverage(SAMPLES_Y, trap->top), 456 clip); 457 } else { 458 if (pixman_fixed_frac(trap->top)) { 459 composite_unaligned_trap_row(sna, tmp, trap, dx, 460 y1, y1 + 1, 461 SAMPLES_Y - grid_coverage(SAMPLES_Y, trap->top), 462 clip); 463 y1++; 464 } 465 466 if (y2 > y1) 467 composite_unaligned_trap_row(sna, tmp, trap, dx, 468 y1, y2, 469 SAMPLES_Y, 470 clip); 471 472 if (pixman_fixed_frac(trap->bottom)) 473 composite_unaligned_trap_row(sna, tmp, trap, dx, 474 y2, y2 + 1, 475 grid_coverage(SAMPLES_Y, trap->bottom), 476 clip); 477 } 478 479 if (tmp->base.damage) { 480 BoxRec box; 481 482 box.x1 = dx + pixman_fixed_to_int(trap->left.p1.x); 483 box.x2 = dx + pixman_fixed_to_int(trap->right.p1.x + pixman_fixed_1_minus_e); 484 box.y1 = dy + pixman_fixed_to_int(trap->top); 485 box.y2 = dy + pixman_fixed_to_int(trap->bottom + pixman_fixed_1_minus_e); 486 487 if (clip) { 488 pixman_region16_t region; 489 490 pixman_region_init_rects(®ion, &box, 1); 491 RegionIntersect(®ion, ®ion, clip); 492 if (region_num_rects(®ion)) 493 apply_damage(&tmp->base, ®ion); 494 RegionUninit(®ion); 495 } else 496 apply_damage_box(&tmp->base, &box); 497 } 498} 499 500inline static void 501blt_opacity(PixmapPtr scratch, 502 int x1, int x2, 503 int y, int h, 504 uint8_t opacity) 505{ 506 uint8_t *ptr; 507 508 if (opacity == 0xff) 509 return; 510 511 if (x1 < 0) 512 x1 = 0; 513 if (x2 > scratch->drawable.width) 514 x2 = scratch->drawable.width; 515 if (x1 >= x2) 516 return; 517 518 x2 -= x1; 519 520 ptr = scratch->devPrivate.ptr; 521 ptr += scratch->devKind * y; 522 ptr += x1; 523 do { 524 if (x2 == 1) 525 *ptr = opacity; 526 else 527 memset(ptr, opacity, x2); 528 ptr += scratch->devKind; 529 } while (--h); 530} 531 532static void 533blt_unaligned_box_row(PixmapPtr scratch, 534 BoxPtr extents, 535 const xTrapezoid *trap, 536 int y1, int y2, 537 int covered) 538{ 539 int x1, x2; 540 541 if (y2 > scratch->drawable.height) 542 y2 = scratch->drawable.height; 543 if (y1 < 0) 544 y1 = 0; 545 if (y1 >= y2) 546 return; 547 548 y2 -= y1; 549 550 x1 = pixman_fixed_to_int(trap->left.p1.x); 551 x2 = pixman_fixed_to_int(trap->right.p1.x); 552 553 x1 -= extents->x1; 554 x2 -= extents->x1; 555 556 if (x1 == x2) { 557 blt_opacity(scratch, 558 x1, x1+1, 559 y1, y2, 560 covered * (grid_coverage(SAMPLES_X, trap->right.p1.x) - grid_coverage(SAMPLES_X, trap->left.p1.x))); 561 } else { 562 if (pixman_fixed_frac(trap->left.p1.x)) { 563 blt_opacity(scratch, 564 x1, x1 + 1, 565 y1, y2, 566 covered * (SAMPLES_X - grid_coverage(SAMPLES_X, trap->left.p1.x))); 567 x1++; 568 } 569 570 if (x2 > x1) { 571 blt_opacity(scratch, 572 x1, x2, 573 y1, y2, 574 covered*SAMPLES_X); 575 } 576 577 if (pixman_fixed_frac(trap->right.p1.x)) 578 blt_opacity(scratch, 579 x2, x2 + 1, 580 y1, y2, 581 covered * grid_coverage(SAMPLES_X, trap->right.p1.x)); 582 } 583} 584 585inline static void 586lerp32_opacity(PixmapPtr scratch, 587 uint32_t color, 588 int16_t x, int16_t w, 589 int16_t y, int16_t h, 590 uint8_t opacity) 591{ 592 uint32_t *ptr; 593 int stride, i; 594 595 sigtrap_assert_active(); 596 597 ptr = (uint32_t*)((uint8_t *)scratch->devPrivate.ptr + scratch->devKind * y); 598 ptr += x; 599 stride = scratch->devKind / 4; 600 601 if (opacity == 0xff) { 602 if ((w | h) == 1) { 603 *ptr = color; 604 } else { 605 if (w < 16) { 606 do { 607 for (i = 0; i < w; i++) 608 ptr[i] = color; 609 ptr += stride; 610 } while (--h); 611 } else { 612 pixman_fill(ptr, stride, 32, 613 0, 0, w, h, color); 614 } 615 } 616 } else { 617 if ((w | h) == 1) { 618 *ptr = lerp8x4(color, opacity, *ptr); 619 } else if (w == 1) { 620 do { 621 *ptr = lerp8x4(color, opacity, *ptr); 622 ptr += stride; 623 } while (--h); 624 } else{ 625 do { 626 for (i = 0; i < w; i++) 627 ptr[i] = lerp8x4(color, opacity, ptr[i]); 628 ptr += stride; 629 } while (--h); 630 } 631 } 632} 633 634static void 635lerp32_unaligned_box_row(PixmapPtr scratch, uint32_t color, 636 const BoxRec *extents, 637 const xTrapezoid *trap, int16_t dx, 638 int16_t y, int16_t h, 639 uint8_t covered) 640{ 641 int16_t x1 = pixman_fixed_to_int(trap->left.p1.x) + dx; 642 uint16_t fx1 = grid_coverage(SAMPLES_X, trap->left.p1.x); 643 int16_t x2 = pixman_fixed_to_int(trap->right.p2.x) + dx; 644 uint16_t fx2 = grid_coverage(SAMPLES_X, trap->right.p2.x); 645 646 if (x1 < extents->x1) 647 x1 = extents->x1, fx1 = 0; 648 if (x2 >= extents->x2) 649 x2 = extents->x2, fx2 = 0; 650 651 DBG(("%s: x=(%d.%d, %d.%d), y=%dx%d, covered=%d\n", __FUNCTION__, 652 x1, fx1, x2, fx2, y, h, covered)); 653 654 if (x1 < x2) { 655 if (fx1) { 656 lerp32_opacity(scratch, color, 657 x1, 1, 658 y, h, 659 covered * (SAMPLES_X - fx1)); 660 x1++; 661 } 662 663 if (x2 > x1) { 664 lerp32_opacity(scratch, color, 665 x1, x2-x1, 666 y, h, 667 covered*SAMPLES_X); 668 } 669 670 if (fx2) { 671 lerp32_opacity(scratch, color, 672 x2, 1, 673 y, h, 674 covered * fx2); 675 } 676 } else if (x1 == x2 && fx2 > fx1) { 677 lerp32_opacity(scratch, color, 678 x1, 1, 679 y, h, 680 covered * (fx2 - fx1)); 681 } 682} 683 684struct pixman_inplace { 685 pixman_image_t *image, *source, *mask; 686 uint32_t color; 687 uint32_t *bits; 688 int dx, dy; 689 int sx, sy; 690 uint8_t op; 691}; 692 693inline static void 694pixsolid_opacity(struct pixman_inplace *pi, 695 int16_t x, int16_t w, 696 int16_t y, int16_t h, 697 uint8_t opacity) 698{ 699 if (opacity == 0xff) 700 *pi->bits = pi->color; 701 else 702 *pi->bits = mul_4x8_8(pi->color, opacity); 703 sna_image_composite(pi->op, pi->source, NULL, pi->image, 704 0, 0, 0, 0, pi->dx + x, pi->dy + y, w, h); 705} 706 707static void 708pixsolid_unaligned_box_row(struct pixman_inplace *pi, 709 const BoxRec *extents, 710 const xTrapezoid *trap, 711 int16_t y, int16_t h, 712 uint8_t covered) 713{ 714 int16_t x1 = pixman_fixed_to_int(trap->left.p1.x); 715 uint16_t fx1 = grid_coverage(SAMPLES_X, trap->left.p1.x); 716 int16_t x2 = pixman_fixed_to_int(trap->right.p1.x); 717 uint16_t fx2 = grid_coverage(SAMPLES_X, trap->right.p1.x); 718 719 if (x1 < extents->x1) 720 x1 = extents->x1, fx1 = 0; 721 if (x2 >= extents->x2) 722 x2 = extents->x2, fx2 = 0; 723 724 if (x1 < x2) { 725 if (fx1) { 726 pixsolid_opacity(pi, x1, 1, y, h, 727 covered * (SAMPLES_X - fx1)); 728 x1++; 729 } 730 731 if (x2 > x1) 732 pixsolid_opacity(pi, x1, x2-x1, y, h, covered*SAMPLES_X); 733 734 if (fx2) 735 pixsolid_opacity(pi, x2, 1, y, h, covered * fx2); 736 } else if (x1 == x2 && fx2 > fx1) { 737 pixsolid_opacity(pi, x1, 1, y, h, covered * (fx2 - fx1)); 738 } 739} 740 741static bool 742composite_unaligned_boxes_inplace__solid(struct sna *sna, 743 CARD8 op, uint32_t color, 744 PicturePtr dst, 745 int n, const xTrapezoid *t, 746 bool force_fallback) 747{ 748 PixmapPtr pixmap; 749 int16_t dx, dy; 750 751 DBG(("%s: force=%d, is_gpu=%d, op=%d, color=%x\n", __FUNCTION__, 752 force_fallback, is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS), op, color)); 753 754 if (!force_fallback && is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS)) { 755 DBG(("%s: fallback -- can not perform operation in place, destination busy\n", 756 __FUNCTION__)); 757 758 return false; 759 } 760 761 /* XXX a8 boxes */ 762 if (!(dst->format == PICT_a8r8g8b8 || dst->format == PICT_x8r8g8b8)) { 763 DBG(("%s: fallback -- can not perform operation in place, unhanbled format %08lx\n", 764 __FUNCTION__, (long)dst->format)); 765 766 goto pixman; 767 } 768 769 pixmap = get_drawable_pixmap(dst->pDrawable); 770 get_drawable_deltas(dst->pDrawable, pixmap, &dx, &dy); 771 772 if (op == PictOpOver && (color >> 24) == 0xff) 773 op = PictOpSrc; 774 if (op == PictOpOver || op == PictOpAdd) { 775 struct sna_pixmap *priv = sna_pixmap(pixmap); 776 if (priv && priv->clear && priv->clear_color == 0) 777 op = PictOpSrc; 778 } 779 780 switch (op) { 781 case PictOpSrc: 782 break; 783 default: 784 DBG(("%s: fallback -- can not perform op [%d] in place\n", 785 __FUNCTION__, op)); 786 goto pixman; 787 } 788 789 DBG(("%s: inplace operation on argb32 destination x %d\n", 790 __FUNCTION__, n)); 791 do { 792 RegionRec clip; 793 const BoxRec *extents; 794 int count; 795 796 clip.extents.x1 = pixman_fixed_to_int(t->left.p1.x); 797 clip.extents.x2 = pixman_fixed_to_int(t->right.p1.x + pixman_fixed_1_minus_e); 798 clip.extents.y1 = pixman_fixed_to_int(t->top); 799 clip.extents.y2 = pixman_fixed_to_int(t->bottom + pixman_fixed_1_minus_e); 800 clip.data = NULL; 801 802 if (!sna_compute_composite_region(&clip, 803 NULL, NULL, dst, 804 0, 0, 805 0, 0, 806 clip.extents.x1, clip.extents.y1, 807 clip.extents.x2 - clip.extents.x1, 808 clip.extents.y2 - clip.extents.y1)) 809 continue; 810 811 if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &clip, 812 MOVE_WRITE | MOVE_READ)) { 813 RegionUninit(&clip); 814 continue; 815 } 816 817 if (sigtrap_get() == 0) { 818 RegionTranslate(&clip, dx, dy); 819 count = region_num_rects(&clip); 820 extents = region_rects(&clip); 821 while (count--) { 822 int16_t y1 = dy + pixman_fixed_to_int(t->top); 823 uint16_t fy1 = pixman_fixed_frac(t->top); 824 int16_t y2 = dy + pixman_fixed_to_int(t->bottom); 825 uint16_t fy2 = pixman_fixed_frac(t->bottom); 826 827 DBG(("%s: t=(%d, %d), (%d, %d), extents (%d, %d), (%d, %d)\n", 828 __FUNCTION__, 829 pixman_fixed_to_int(t->left.p1.x), 830 pixman_fixed_to_int(t->top), 831 pixman_fixed_to_int(t->right.p2.x), 832 pixman_fixed_to_int(t->bottom), 833 extents->x1, extents->y1, 834 extents->x2, extents->y2)); 835 836 if (y1 < extents->y1) 837 y1 = extents->y1, fy1 = 0; 838 if (y2 >= extents->y2) 839 y2 = extents->y2, fy2 = 0; 840 841 if (y1 < y2) { 842 if (fy1) { 843 lerp32_unaligned_box_row(pixmap, color, extents, 844 t, dx, y1, 1, 845 SAMPLES_Y - grid_coverage(SAMPLES_Y, fy1)); 846 y1++; 847 } 848 849 if (y2 > y1) 850 lerp32_unaligned_box_row(pixmap, color, extents, 851 t, dx, y1, y2 - y1, 852 SAMPLES_Y); 853 854 if (fy2) 855 lerp32_unaligned_box_row(pixmap, color, extents, 856 t, dx, y2, 1, 857 grid_coverage(SAMPLES_Y, fy2)); 858 } else if (y1 == y2 && fy2 > fy1) { 859 lerp32_unaligned_box_row(pixmap, color, extents, 860 t, dx, y1, 1, 861 grid_coverage(SAMPLES_Y, fy2) - grid_coverage(SAMPLES_Y, fy1)); 862 } 863 extents++; 864 } 865 sigtrap_put(); 866 } 867 868 RegionUninit(&clip); 869 } while (--n && t++); 870 871 return true; 872 873pixman: 874 do { 875 struct pixman_inplace pi; 876 RegionRec clip; 877 const BoxRec *extents; 878 int count; 879 880 clip.extents.x1 = pixman_fixed_to_int(t->left.p1.x); 881 clip.extents.x2 = pixman_fixed_to_int(t->right.p1.x + pixman_fixed_1_minus_e); 882 clip.extents.y1 = pixman_fixed_to_int(t->top); 883 clip.extents.y2 = pixman_fixed_to_int(t->bottom + pixman_fixed_1_minus_e); 884 clip.data = NULL; 885 886 if (!sna_compute_composite_region(&clip, 887 NULL, NULL, dst, 888 0, 0, 889 0, 0, 890 clip.extents.x1, clip.extents.y1, 891 clip.extents.x2 - clip.extents.x1, 892 clip.extents.y2 - clip.extents.y1)) 893 continue; 894 895 if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &clip, 896 MOVE_WRITE | MOVE_READ)) { 897 RegionUninit(&clip); 898 continue; 899 } 900 901 pi.image = image_from_pict(dst, false, &pi.dx, &pi.dy); 902 pi.source = pixman_image_create_bits(PIXMAN_a8r8g8b8, 1, 1, NULL, 0); 903 pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL); 904 pi.bits = pixman_image_get_data(pi.source); 905 pi.color = color; 906 pi.op = op; 907 908 if (sigtrap_get() == 0) { 909 count = region_num_rects(&clip); 910 extents = region_rects(&clip); 911 while (count--) { 912 int16_t y1 = pixman_fixed_to_int(t->top); 913 uint16_t fy1 = pixman_fixed_frac(t->top); 914 int16_t y2 = pixman_fixed_to_int(t->bottom); 915 uint16_t fy2 = pixman_fixed_frac(t->bottom); 916 917 if (y1 < extents->y1) 918 y1 = extents->y1, fy1 = 0; 919 if (y2 >= extents->y2) 920 y2 = extents->y2, fy2 = 0; 921 if (y1 < y2) { 922 if (fy1) { 923 pixsolid_unaligned_box_row(&pi, extents, t, y1, 1, 924 SAMPLES_Y - grid_coverage(SAMPLES_Y, fy1)); 925 y1++; 926 } 927 928 if (y2 > y1) 929 pixsolid_unaligned_box_row(&pi, extents, t, y1, y2 - y1, 930 SAMPLES_Y); 931 932 if (fy2) 933 pixsolid_unaligned_box_row(&pi, extents, t, y2, 1, 934 grid_coverage(SAMPLES_Y, fy2)); 935 } else if (y1 == y2 && fy2 > fy1) { 936 pixsolid_unaligned_box_row(&pi, extents, t, y1, 1, 937 grid_coverage(SAMPLES_Y, fy2) - grid_coverage(SAMPLES_Y, fy1)); 938 } 939 extents++; 940 } 941 sigtrap_put(); 942 } 943 944 RegionUninit(&clip); 945 pixman_image_unref(pi.image); 946 pixman_image_unref(pi.source); 947 } while (--n && t++); 948 return true; 949} 950 951inline static void 952pixmask_opacity(struct pixman_inplace *pi, 953 int16_t x, int16_t w, 954 int16_t y, int16_t h, 955 uint8_t opacity) 956{ 957 if (opacity == 0xff) { 958 pixman_image_composite(pi->op, pi->source, NULL, pi->image, 959 pi->sx + x, pi->sy + y, 960 0, 0, 961 pi->dx + x, pi->dy + y, 962 w, h); 963 } else { 964 *pi->bits = opacity; 965 pixman_image_composite(pi->op, pi->source, pi->mask, pi->image, 966 pi->sx + x, pi->sy + y, 967 0, 0, 968 pi->dx + x, pi->dy + y, 969 w, h); 970 } 971} 972 973static void 974pixmask_unaligned_box_row(struct pixman_inplace *pi, 975 const BoxRec *extents, 976 const xTrapezoid *trap, 977 int16_t y, int16_t h, 978 uint8_t covered) 979{ 980 int16_t x1 = pixman_fixed_to_int(trap->left.p1.x); 981 uint16_t fx1 = grid_coverage(SAMPLES_X, trap->left.p1.x); 982 int16_t x2 = pixman_fixed_to_int(trap->right.p1.x); 983 uint16_t fx2 = grid_coverage(SAMPLES_X, trap->right.p1.x); 984 985 if (x1 < extents->x1) 986 x1 = extents->x1, fx1 = 0; 987 if (x2 >= extents->x2) 988 x2 = extents->x2, fx2 = 0; 989 990 if (x1 < x2) { 991 if (fx1) { 992 pixmask_opacity(pi, x1, 1, y, h, 993 covered * (SAMPLES_X - fx1)); 994 x1++; 995 } 996 997 if (x2 > x1) 998 pixmask_opacity(pi, x1, x2-x1, y, h, covered*SAMPLES_X); 999 1000 if (fx2) 1001 pixmask_opacity(pi, x2, 1, y, h, covered * fx2); 1002 } else if (x1 == x2 && fx2 > fx1) { 1003 pixmask_opacity(pi, x1, 1, y, h, covered * (fx2 - fx1)); 1004 } 1005} 1006 1007struct rectilinear_inplace_thread { 1008 pixman_image_t *dst, *src; 1009 const RegionRec *clip; 1010 const xTrapezoid *trap; 1011 int dx, dy, sx, sy; 1012 int y1, y2; 1013 CARD8 op; 1014}; 1015 1016static void rectilinear_inplace_thread(void *arg) 1017{ 1018 struct rectilinear_inplace_thread *thread = arg; 1019 const xTrapezoid *t = thread->trap; 1020 struct pixman_inplace pi; 1021 const BoxRec *extents; 1022 int count; 1023 1024 pi.image = thread->dst; 1025 pi.dx = thread->dx; 1026 pi.dy = thread->dy; 1027 1028 pi.source = thread->src; 1029 pi.sx = thread->sx; 1030 pi.sy = thread->sy; 1031 1032 pi.mask = pixman_image_create_bits(PIXMAN_a8, 1, 1, &pi.color, 4); 1033 pixman_image_set_repeat(pi.mask, PIXMAN_REPEAT_NORMAL); 1034 pi.bits = pixman_image_get_data(pi.mask); 1035 pi.op = thread->op; 1036 1037 count = region_count(thread->clip); 1038 extents = region_boxes(thread->clip); 1039 while (count--) { 1040 int16_t y1 = pixman_fixed_to_int(t->top); 1041 uint16_t fy1 = pixman_fixed_frac(t->top); 1042 int16_t y2 = pixman_fixed_to_int(t->bottom); 1043 uint16_t fy2 = pixman_fixed_frac(t->bottom); 1044 1045 if (y1 < MAX(thread->y1, extents->y1)) 1046 y1 = MAX(thread->y1, extents->y1), fy1 = 0; 1047 if (y2 > MIN(thread->y2, extents->y2)) 1048 y2 = MIN(thread->y2, extents->y2), fy2 = 0; 1049 if (y1 < y2) { 1050 if (fy1) { 1051 pixmask_unaligned_box_row(&pi, extents, t, y1, 1, 1052 SAMPLES_Y - grid_coverage(SAMPLES_Y, fy1)); 1053 y1++; 1054 } 1055 1056 if (y2 > y1) 1057 pixmask_unaligned_box_row(&pi, extents, t, y1, y2 - y1, 1058 SAMPLES_Y); 1059 1060 if (fy2) 1061 pixmask_unaligned_box_row(&pi, extents, t, y2, 1, 1062 grid_coverage(SAMPLES_Y, fy2)); 1063 } else if (y1 == y2 && fy2 > fy1) { 1064 pixmask_unaligned_box_row(&pi, extents, t, y1, 1, 1065 grid_coverage(SAMPLES_Y, fy2) - grid_coverage(SAMPLES_Y, fy1)); 1066 } 1067 extents++; 1068 } 1069 1070 pixman_image_unref(pi.mask); 1071} 1072 1073static bool 1074composite_unaligned_boxes_inplace(struct sna *sna, 1075 CARD8 op, 1076 PicturePtr src, int16_t src_x, int16_t src_y, 1077 PicturePtr dst, int n, const xTrapezoid *t, 1078 bool force_fallback) 1079{ 1080 if (!force_fallback && 1081 (is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS) || 1082 picture_is_gpu(sna, src, PREFER_GPU_SPANS))) { 1083 DBG(("%s: fallback -- not forcing\n", __FUNCTION__)); 1084 return false; 1085 } 1086 1087 DBG(("%s\n", __FUNCTION__)); 1088 1089 src_x -= pixman_fixed_to_int(t[0].left.p1.x); 1090 src_y -= pixman_fixed_to_int(t[0].left.p1.y); 1091 do { 1092 RegionRec clip; 1093 const BoxRec *extents; 1094 int count; 1095 int num_threads; 1096 1097 clip.extents.x1 = pixman_fixed_to_int(t->left.p1.x); 1098 clip.extents.x2 = pixman_fixed_to_int(t->right.p1.x + pixman_fixed_1_minus_e); 1099 clip.extents.y1 = pixman_fixed_to_int(t->top); 1100 clip.extents.y2 = pixman_fixed_to_int(t->bottom + pixman_fixed_1_minus_e); 1101 clip.data = NULL; 1102 1103 if (!sna_compute_composite_region(&clip, 1104 src, NULL, dst, 1105 clip.extents.x1 + src_x, 1106 clip.extents.y1 + src_y, 1107 0, 0, 1108 clip.extents.x1, clip.extents.y1, 1109 clip.extents.x2 - clip.extents.x1, 1110 clip.extents.y2 - clip.extents.y1)) 1111 continue; 1112 1113 if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &clip, 1114 MOVE_WRITE | MOVE_READ)) { 1115 RegionUninit(&clip); 1116 continue; 1117 } 1118 1119 if (src->pDrawable) { 1120 if (!sna_drawable_move_to_cpu(src->pDrawable, 1121 MOVE_READ)) { 1122 RegionUninit(&clip); 1123 continue; 1124 } 1125 if (src->alphaMap) { 1126 if (!sna_drawable_move_to_cpu(src->alphaMap->pDrawable, 1127 MOVE_READ)) { 1128 RegionUninit(&clip); 1129 continue; 1130 } 1131 } 1132 } 1133 1134 num_threads = sna_use_threads(clip.extents.x2 - clip.extents.x1, 1135 clip.extents.y2 - clip.extents.y1, 1136 32); 1137 if (num_threads == 1) { 1138 struct pixman_inplace pi; 1139 1140 pi.image = image_from_pict(dst, false, &pi.dx, &pi.dy); 1141 pi.source = image_from_pict(src, false, &pi.sx, &pi.sy); 1142 pi.sx += src_x; 1143 pi.sy += src_y; 1144 pi.mask = pixman_image_create_bits(PIXMAN_a8, 1, 1, &pi.color, 4); 1145 pixman_image_set_repeat(pi.mask, PIXMAN_REPEAT_NORMAL); 1146 pi.bits = pixman_image_get_data(pi.mask); 1147 pi.op = op; 1148 1149 if (sigtrap_get() == 0) { 1150 count = region_num_rects(&clip); 1151 extents = region_rects(&clip); 1152 while (count--) { 1153 int16_t y1 = pixman_fixed_to_int(t->top); 1154 uint16_t fy1 = pixman_fixed_frac(t->top); 1155 int16_t y2 = pixman_fixed_to_int(t->bottom); 1156 uint16_t fy2 = pixman_fixed_frac(t->bottom); 1157 1158 if (y1 < extents->y1) 1159 y1 = extents->y1, fy1 = 0; 1160 if (y2 > extents->y2) 1161 y2 = extents->y2, fy2 = 0; 1162 if (y1 < y2) { 1163 if (fy1) { 1164 pixmask_unaligned_box_row(&pi, extents, t, y1, 1, 1165 SAMPLES_Y - grid_coverage(SAMPLES_Y, fy1)); 1166 y1++; 1167 } 1168 1169 if (y2 > y1) 1170 pixmask_unaligned_box_row(&pi, extents, t, y1, y2 - y1, 1171 SAMPLES_Y); 1172 1173 if (fy2) 1174 pixmask_unaligned_box_row(&pi, extents, t, y2, 1, 1175 grid_coverage(SAMPLES_Y, fy2)); 1176 } else if (y1 == y2 && fy2 > fy1) { 1177 pixmask_unaligned_box_row(&pi, extents, t, y1, 1, 1178 grid_coverage(SAMPLES_Y, fy2) - grid_coverage(SAMPLES_Y, fy1)); 1179 } 1180 extents++; 1181 } 1182 sigtrap_put(); 1183 } 1184 1185 pixman_image_unref(pi.image); 1186 pixman_image_unref(pi.source); 1187 pixman_image_unref(pi.mask); 1188 } else { 1189 struct rectilinear_inplace_thread thread[num_threads]; 1190 int i, y, dy; 1191 1192 1193 thread[0].trap = t; 1194 thread[0].dst = image_from_pict(dst, false, &thread[0].dx, &thread[0].dy); 1195 thread[0].src = image_from_pict(src, false, &thread[0].sx, &thread[0].sy); 1196 thread[0].sx += src_x; 1197 thread[0].sy += src_y; 1198 1199 thread[0].clip = &clip; 1200 thread[0].op = op; 1201 1202 y = clip.extents.y1; 1203 dy = (clip.extents.y2 - clip.extents.y1 + num_threads - 1) / num_threads; 1204 num_threads = (clip.extents.y2 - clip.extents.y1 + dy - 1) / dy; 1205 1206 if (sigtrap_get() == 0) { 1207 for (i = 1; i < num_threads; i++) { 1208 thread[i] = thread[0]; 1209 thread[i].y1 = y; 1210 thread[i].y2 = y += dy; 1211 sna_threads_run(i, rectilinear_inplace_thread, &thread[i]); 1212 } 1213 1214 assert(y < clip.extents.y2); 1215 thread[0].y1 = y; 1216 thread[0].y2 = clip.extents.y2; 1217 rectilinear_inplace_thread(&thread[0]); 1218 1219 sna_threads_wait(); 1220 sigtrap_put(); 1221 } else 1222 sna_threads_kill(); 1223 1224 pixman_image_unref(thread[0].dst); 1225 pixman_image_unref(thread[0].src); 1226 } 1227 1228 RegionUninit(&clip); 1229 } while (--n && t++); 1230 1231 return true; 1232} 1233 1234static bool 1235composite_unaligned_boxes_fallback(struct sna *sna, 1236 CARD8 op, 1237 PicturePtr src, 1238 PicturePtr dst, 1239 INT16 src_x, INT16 src_y, 1240 int ntrap, const xTrapezoid *traps, 1241 bool force_fallback) 1242{ 1243 ScreenPtr screen = dst->pDrawable->pScreen; 1244 uint32_t color; 1245 int16_t dst_x, dst_y; 1246 int16_t dx, dy; 1247 int n; 1248 1249 if (sna_picture_is_solid(src, &color) && 1250 composite_unaligned_boxes_inplace__solid(sna, op, color, dst, 1251 ntrap, traps, 1252 force_fallback)) 1253 return true; 1254 1255 if (composite_unaligned_boxes_inplace(sna, op, src, src_x, src_y, 1256 dst, ntrap, traps, 1257 force_fallback)) 1258 return true; 1259 1260 trapezoid_origin(&traps[0].left, &dst_x, &dst_y); 1261 dx = dst->pDrawable->x; 1262 dy = dst->pDrawable->y; 1263 for (n = 0; n < ntrap; n++) { 1264 const xTrapezoid *t = &traps[n]; 1265 PixmapPtr scratch; 1266 PicturePtr mask; 1267 BoxRec extents; 1268 int error; 1269 int y1, y2; 1270 1271 extents.x1 = pixman_fixed_to_int(t->left.p1.x); 1272 extents.x2 = pixman_fixed_to_int(t->right.p1.x + pixman_fixed_1_minus_e); 1273 extents.y1 = pixman_fixed_to_int(t->top); 1274 extents.y2 = pixman_fixed_to_int(t->bottom + pixman_fixed_1_minus_e); 1275 1276 if (!sna_compute_composite_extents(&extents, 1277 src, NULL, dst, 1278 src_x, src_y, 1279 0, 0, 1280 extents.x1, extents.y1, 1281 extents.x2 - extents.x1, 1282 extents.y2 - extents.y1)) 1283 continue; 1284 1285 if (force_fallback) 1286 scratch = sna_pixmap_create_unattached(screen, 1287 extents.x2 - extents.x1, 1288 extents.y2 - extents.y1, 1289 8); 1290 else 1291 scratch = sna_pixmap_create_upload(screen, 1292 extents.x2 - extents.x1, 1293 extents.y2 - extents.y1, 1294 8, KGEM_BUFFER_WRITE_INPLACE); 1295 if (!scratch) 1296 continue; 1297 1298 memset(scratch->devPrivate.ptr, 0xff, 1299 scratch->devKind * (extents.y2 - extents.y1)); 1300 1301 extents.x1 -= dx; 1302 extents.x2 -= dx; 1303 extents.y1 -= dy; 1304 extents.y2 -= dy; 1305 1306 y1 = pixman_fixed_to_int(t->top) - extents.y1; 1307 y2 = pixman_fixed_to_int(t->bottom) - extents.y1; 1308 1309 if (y1 == y2) { 1310 blt_unaligned_box_row(scratch, &extents, t, y1, y1 + 1, 1311 grid_coverage(SAMPLES_Y, t->bottom) - grid_coverage(SAMPLES_Y, t->top)); 1312 } else { 1313 if (pixman_fixed_frac(t->top)) { 1314 blt_unaligned_box_row(scratch, &extents, t, y1, y1 + 1, 1315 SAMPLES_Y - grid_coverage(SAMPLES_Y, t->top)); 1316 y1++; 1317 } 1318 1319 if (y2 > y1) 1320 blt_unaligned_box_row(scratch, &extents, t, y1, y2, 1321 SAMPLES_Y); 1322 1323 if (pixman_fixed_frac(t->bottom)) 1324 blt_unaligned_box_row(scratch, &extents, t, y2, y2+1, 1325 grid_coverage(SAMPLES_Y, t->bottom)); 1326 } 1327 1328 mask = CreatePicture(0, &scratch->drawable, 1329 PictureMatchFormat(screen, 8, PICT_a8), 1330 0, 0, serverClient, &error); 1331 if (mask) { 1332 CompositePicture(op, src, mask, dst, 1333 src_x + extents.x1 - dst_x, 1334 src_y + extents.y1 - dst_y, 1335 0, 0, 1336 extents.x1, extents.y1, 1337 extents.x2 - extents.x1, 1338 extents.y2 - extents.y1); 1339 FreePicture(mask, 0); 1340 } 1341 sna_pixmap_destroy(scratch); 1342 } 1343 1344 return true; 1345} 1346 1347bool 1348composite_unaligned_boxes(struct sna *sna, 1349 CARD8 op, 1350 PicturePtr src, 1351 PicturePtr dst, 1352 PictFormatPtr maskFormat, 1353 INT16 src_x, INT16 src_y, 1354 int ntrap, const xTrapezoid *traps, 1355 bool force_fallback) 1356{ 1357 BoxRec extents; 1358 struct sna_composite_spans_op tmp; 1359 struct sna_pixmap *priv; 1360 pixman_region16_t clip, *c; 1361 int16_t dst_x, dst_y; 1362 int dx, dy, n; 1363 1364 if (NO_UNALIGNED_BOXES) 1365 return false; 1366 1367 DBG(("%s: force_fallback=%d, mask=%x, n=%d, op=%d\n", 1368 __FUNCTION__, force_fallback, maskFormat ? (int)maskFormat->format : 0, ntrap, op)); 1369 1370 /* need a span converter to handle overlapping traps */ 1371 if (ntrap > 1 && maskFormat) 1372 return false; 1373 1374 if (force_fallback || 1375 !sna->render.check_composite_spans(sna, op, src, dst, 0, 0, 1376 COMPOSITE_SPANS_RECTILINEAR)) { 1377fallback: 1378 return composite_unaligned_boxes_fallback(sna, op, src, dst, 1379 src_x, src_y, 1380 ntrap, traps, 1381 force_fallback); 1382 } 1383 1384 trapezoid_origin(&traps[0].left, &dst_x, &dst_y); 1385 1386 extents.x1 = pixman_fixed_to_int(traps[0].left.p1.x); 1387 extents.x2 = pixman_fixed_to_int(traps[0].right.p1.x + pixman_fixed_1_minus_e); 1388 extents.y1 = pixman_fixed_to_int(traps[0].top); 1389 extents.y2 = pixman_fixed_to_int(traps[0].bottom + pixman_fixed_1_minus_e); 1390 1391 DBG(("%s: src=(%d, %d), dst=(%d, %d)\n", 1392 __FUNCTION__, src_x, src_y, dst_x, dst_y)); 1393 1394 for (n = 1; n < ntrap; n++) { 1395 int x1 = pixman_fixed_to_int(traps[n].left.p1.x); 1396 int x2 = pixman_fixed_to_int(traps[n].right.p1.x + pixman_fixed_1_minus_e); 1397 int y1 = pixman_fixed_to_int(traps[n].top); 1398 int y2 = pixman_fixed_to_int(traps[n].bottom + pixman_fixed_1_minus_e); 1399 1400 if (x1 < extents.x1) 1401 extents.x1 = x1; 1402 if (x2 > extents.x2) 1403 extents.x2 = x2; 1404 if (y1 < extents.y1) 1405 extents.y1 = y1; 1406 if (y2 > extents.y2) 1407 extents.y2 = y2; 1408 } 1409 1410 DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__, 1411 extents.x1, extents.y1, extents.x2, extents.y2)); 1412 1413 if (!sna_compute_composite_region(&clip, 1414 src, NULL, dst, 1415 src_x + extents.x1 - dst_x, 1416 src_y + extents.y1 - dst_y, 1417 0, 0, 1418 extents.x1, extents.y1, 1419 extents.x2 - extents.x1, 1420 extents.y2 - extents.y1)) { 1421 DBG(("%s: trapezoids do not intersect drawable clips\n", 1422 __FUNCTION__)) ; 1423 return true; 1424 } 1425 1426 if (!sna->render.check_composite_spans(sna, op, src, dst, 1427 clip.extents.x2 - clip.extents.x1, 1428 clip.extents.y2 - clip.extents.y1, 1429 COMPOSITE_SPANS_RECTILINEAR)) { 1430 DBG(("%s: fallback -- composite spans not supported\n", 1431 __FUNCTION__)); 1432 goto fallback; 1433 } 1434 1435 c = NULL; 1436 if (extents.x2 - extents.x1 > clip.extents.x2 - clip.extents.x1 || 1437 extents.y2 - extents.y1 > clip.extents.y2 - clip.extents.y1) { 1438 DBG(("%s: forcing clip\n", __FUNCTION__)); 1439 c = &clip; 1440 } 1441 1442 extents = *RegionExtents(&clip); 1443 dx = dst->pDrawable->x; 1444 dy = dst->pDrawable->y; 1445 1446 DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n", 1447 __FUNCTION__, 1448 extents.x1, extents.y1, 1449 extents.x2, extents.y2, 1450 dx, dy, 1451 src_x + extents.x1 - dst_x - dx, 1452 src_y + extents.y1 - dst_y - dy)); 1453 1454 switch (op) { 1455 case PictOpAdd: 1456 case PictOpOver: 1457 priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable)); 1458 assert(priv != NULL); 1459 if (priv->clear && priv->clear_color == 0) { 1460 DBG(("%s: converting %d to PictOpSrc\n", 1461 __FUNCTION__, op)); 1462 op = PictOpSrc; 1463 } 1464 break; 1465 case PictOpIn: 1466 priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable)); 1467 assert(priv != NULL); 1468 if (priv->clear && priv->clear_color == 0) { 1469 DBG(("%s: clear destination using In, skipping\n", 1470 __FUNCTION__)); 1471 return true; 1472 } 1473 break; 1474 } 1475 1476 if (!sna->render.composite_spans(sna, op, src, dst, 1477 src_x + extents.x1 - dst_x - dx, 1478 src_y + extents.y1 - dst_y - dy, 1479 extents.x1, extents.y1, 1480 extents.x2 - extents.x1, 1481 extents.y2 - extents.y1, 1482 COMPOSITE_SPANS_RECTILINEAR, 1483 memset(&tmp, 0, sizeof(tmp)))) { 1484 DBG(("%s: composite spans render op not supported\n", 1485 __FUNCTION__)); 1486 REGION_UNINIT(NULL, &clip); 1487 goto fallback; 1488 } 1489 1490 for (n = 0; n < ntrap; n++) 1491 composite_unaligned_trap(sna, &tmp, &traps[n], dx, dy, c); 1492 tmp.done(sna, &tmp); 1493 REGION_UNINIT(NULL, &clip); 1494 return true; 1495} 1496