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 55inline static xFixed 56line_x_for_y(const xLineFixed *l, xFixed y, bool ceil) 57{ 58 xFixed_32_32 ex = (xFixed_32_32)(y - l->p1.y) * (l->p2.x - l->p1.x); 59 xFixed d = l->p2.y - l->p1.y; 60 61 if (ceil) 62 ex += (d - 1); 63 64 return l->p1.x + (xFixed) (ex / d); 65} 66 67bool trapezoids_bounds(int n, const xTrapezoid *t, BoxPtr box) 68{ 69 xFixed x1, y1, x2, y2; 70 71 /* XXX need 33 bits... */ 72 x1 = y1 = INT_MAX / 2; 73 x2 = y2 = INT_MIN / 2; 74 75 do { 76 xFixed fx1, fx2, v; 77 78 if (!xTrapezoidValid(t)) { 79 __DBG(("%s: skipping invalid trapezoid: top=%d, bottom=%d, left=(%d, %d), (%d, %d), right=(%d, %d), (%d, %d)\n", 80 __FUNCTION__, 81 t->top, t->bottom, 82 t->left.p1.x, t->left.p1.y, 83 t->left.p2.x, t->left.p2.y, 84 t->right.p1.x, t->right.p1.y, 85 t->right.p2.x, t->right.p2.y)); 86 continue; 87 } 88 89 if (t->top < y1) 90 y1 = t->top; 91 if (t->bottom > y2) 92 y2 = t->bottom; 93 94 if (((t->left.p1.x - x1) | (t->left.p2.x - x1)) < 0) { 95 if (pixman_fixed_floor(t->left.p1.x) == pixman_fixed_floor(t->left.p2.x)) { 96 x1 = pixman_fixed_floor(t->left.p1.x); 97 } else { 98 if (t->left.p1.y == t->top) 99 fx1 = t->left.p1.x; 100 else 101 fx1 = line_x_for_y(&t->left, t->top, false); 102 103 if (t->left.p2.y == t->bottom) 104 fx2 = t->left.p2.x; 105 else 106 fx2 = line_x_for_y(&t->left, t->bottom, false); 107 108 v = min(fx1, fx2); 109 if (v < x1) 110 x1 = pixman_fixed_floor(v); 111 } 112 } 113 114 if (((x2 - t->right.p1.x) | (x2 - t->right.p2.x)) < 0) { 115 if (pixman_fixed_ceil(t->right.p1.x) == pixman_fixed_ceil(t->right.p2.x)) { 116 x2 = pixman_fixed_ceil(t->right.p1.x); 117 } else { 118 if (t->right.p1.y == t->top) 119 fx1 = t->right.p1.x; 120 else 121 fx1 = line_x_for_y(&t->right, t->top, true); 122 123 if (t->right.p2.y == t->bottom) 124 fx2 = t->right.p2.x; 125 else 126 fx2 = line_x_for_y(&t->right, t->bottom, true); 127 128 v = max(fx1, fx2); 129 if (v > x2) 130 x2 = pixman_fixed_ceil(v); 131 } 132 } 133 } while (t++, --n); 134 135 box->x1 = pixman_fixed_to_int(x1); 136 box->x2 = pixman_fixed_to_int(x2); 137 box->y1 = pixman_fixed_integer_floor(y1); 138 box->y2 = pixman_fixed_integer_ceil(y2); 139 140 return box->x2 > box->x1 && box->y2 > box->y1; 141} 142 143static bool 144trapezoids_inplace_fallback(struct sna *sna, 145 CARD8 op, 146 PicturePtr src, PicturePtr dst, PictFormatPtr mask, 147 int ntrap, xTrapezoid *traps) 148{ 149 pixman_image_t *image; 150 BoxRec box; 151 uint32_t color; 152 int dx, dy; 153 154 if (op != PictOpAdd) 155 return false; 156 157 if (is_mono(dst, mask)) { 158 if (dst->format != PICT_a1) 159 return false; 160 } else { 161 if (dst->format != PICT_a8) 162 return false; 163 } 164 165 if (!sna_picture_is_solid(src, &color) || (color >> 24) != 0xff) { 166 DBG(("%s: not an opaque solid source\n", __FUNCTION__)); 167 return false; 168 } 169 170 box.x1 = dst->pDrawable->x; 171 box.y1 = dst->pDrawable->y; 172 box.x2 = dst->pDrawable->width; 173 box.y2 = dst->pDrawable->height; 174 if (pixman_region_contains_rectangle(dst->pCompositeClip, 175 &box) != PIXMAN_REGION_IN) { 176 DBG(("%s: requires clipping, drawable (%d,%d), (%d, %d), clip (%d, %d), (%d, %d)\n", __FUNCTION__, 177 box.x1, box.y1, box.x2, box.y2, 178 dst->pCompositeClip->extents.x1, 179 dst->pCompositeClip->extents.y1, 180 dst->pCompositeClip->extents.x2, 181 dst->pCompositeClip->extents.y2)); 182 return false; 183 } 184 185 if (is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS)) { 186 DBG(("%s: not performing inplace as dst is already on the GPU\n", 187 __FUNCTION__)); 188 return false; 189 } 190 191 DBG(("%s\n", __FUNCTION__)); 192 193 image = NULL; 194 if (sna_drawable_move_to_cpu(dst->pDrawable, MOVE_READ | MOVE_WRITE)) 195 image = image_from_pict(dst, false, &dx, &dy); 196 if (image) { 197 dx += dst->pDrawable->x; 198 dy += dst->pDrawable->y; 199 200 if (sigtrap_get() == 0) { 201 for (; ntrap; ntrap--, traps++) 202 if (xTrapezoidValid(traps)) 203 pixman_rasterize_trapezoid(image, 204 (pixman_trapezoid_t *)traps, 205 dx, dy); 206 sigtrap_put(); 207 } 208 209 pixman_image_unref(image); 210 } 211 212 return true; 213} 214 215struct rasterize_traps_thread { 216 xTrapezoid *traps; 217 char *ptr; 218 int stride; 219 BoxRec bounds; 220 pixman_format_code_t format; 221 int ntrap; 222}; 223 224static void rasterize_traps_thread(void *arg) 225{ 226 struct rasterize_traps_thread *thread = arg; 227 pixman_image_t *image; 228 int width, height, n; 229 230 width = thread->bounds.x2 - thread->bounds.x1; 231 height = thread->bounds.y2 - thread->bounds.y1; 232 233 memset(thread->ptr, 0, thread->stride*height); 234 if (PIXMAN_FORMAT_DEPTH(thread->format) < 8) 235 image = pixman_image_create_bits(thread->format, 236 width, height, 237 NULL, 0); 238 else 239 image = pixman_image_create_bits(thread->format, 240 width, height, 241 (uint32_t *)thread->ptr, 242 thread->stride); 243 if (image == NULL) 244 return; 245 246 for (n = 0; n < thread->ntrap; n++) 247 if (xTrapezoidValid(&thread->traps[n])) 248 pixman_rasterize_trapezoid(image, 249 (pixman_trapezoid_t *)&thread->traps[n], 250 -thread->bounds.x1, -thread->bounds.y1); 251 252 if (PIXMAN_FORMAT_DEPTH(thread->format) < 8) { 253 pixman_image_t *a8; 254 255 a8 = pixman_image_create_bits(PIXMAN_a8, 256 width, height, 257 (uint32_t *)thread->ptr, 258 thread->stride); 259 if (a8) { 260 pixman_image_composite(PIXMAN_OP_SRC, 261 image, NULL, a8, 262 0, 0, 263 0, 0, 264 0, 0, 265 width, height); 266 pixman_image_unref(a8); 267 } 268 } 269 270 pixman_image_unref(image); 271} 272 273static void 274trapezoids_fallback(struct sna *sna, 275 CARD8 op, PicturePtr src, PicturePtr dst, 276 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 277 int ntrap, xTrapezoid * traps) 278{ 279 ScreenPtr screen = dst->pDrawable->pScreen; 280 281 if (maskFormat) { 282 PixmapPtr scratch; 283 PicturePtr mask; 284 INT16 dst_x, dst_y; 285 BoxRec bounds; 286 int width, height, depth; 287 pixman_image_t *image; 288 pixman_format_code_t format; 289 int error; 290 291 trapezoid_origin(&traps[0].left, &dst_x, &dst_y); 292 293 if (!trapezoids_bounds(ntrap, traps, &bounds)) 294 return; 295 296 DBG(("%s: bounds (%d, %d), (%d, %d)\n", __FUNCTION__, 297 bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 298 299 if (!sna_compute_composite_extents(&bounds, 300 src, NULL, dst, 301 xSrc, ySrc, 302 0, 0, 303 bounds.x1, bounds.y1, 304 bounds.x2 - bounds.x1, 305 bounds.y2 - bounds.y1)) 306 return; 307 308 DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__, 309 bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 310 311 width = bounds.x2 - bounds.x1; 312 height = bounds.y2 - bounds.y1; 313 bounds.x1 -= dst->pDrawable->x; 314 bounds.y1 -= dst->pDrawable->y; 315 bounds.x2 -= dst->pDrawable->x; 316 bounds.y2 -= dst->pDrawable->y; 317 depth = maskFormat->depth; 318 if (depth == 1) { 319 format = PIXMAN_a1; 320 } else if (depth <= 4) { 321 format = PIXMAN_a4; 322 depth = 4; 323 } else 324 format = PIXMAN_a8; 325 326 DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n", 327 __FUNCTION__, width, height, depth, format)); 328 if (is_gpu(sna, dst->pDrawable, PREFER_GPU_RENDER) || 329 picture_is_gpu(sna, src, PREFER_GPU_RENDER)) { 330 int num_threads; 331 332 scratch = sna_pixmap_create_upload(screen, 333 width, height, 8, 334 KGEM_BUFFER_WRITE); 335 if (!scratch) 336 return; 337 338 num_threads = sna_use_threads(width, height, 8); 339 if (num_threads == 1) { 340 if (depth < 8) { 341 image = pixman_image_create_bits(format, width, height, 342 NULL, 0); 343 } else { 344 memset(scratch->devPrivate.ptr, 0, scratch->devKind*height); 345 346 image = pixman_image_create_bits(format, width, height, 347 scratch->devPrivate.ptr, 348 scratch->devKind); 349 } 350 if (image) { 351 for (; ntrap; ntrap--, traps++) 352 if (xTrapezoidValid(traps)) 353 pixman_rasterize_trapezoid(image, 354 (pixman_trapezoid_t *)traps, 355 -bounds.x1, -bounds.y1); 356 if (depth < 8) { 357 pixman_image_t *a8; 358 359 a8 = pixman_image_create_bits(PIXMAN_a8, width, height, 360 scratch->devPrivate.ptr, 361 scratch->devKind); 362 if (a8) { 363 pixman_image_composite(PIXMAN_OP_SRC, 364 image, NULL, a8, 365 0, 0, 366 0, 0, 367 0, 0, 368 width, height); 369 format = PIXMAN_a8; 370 depth = 8; 371 pixman_image_unref(a8); 372 } 373 } 374 375 pixman_image_unref(image); 376 } 377 if (format != PIXMAN_a8) { 378 sna_pixmap_destroy(scratch); 379 return; 380 } 381 } else { 382 struct rasterize_traps_thread threads[num_threads]; 383 int y, dy, n; 384 385 threads[0].ptr = scratch->devPrivate.ptr; 386 threads[0].stride = scratch->devKind; 387 threads[0].traps = traps; 388 threads[0].ntrap = ntrap; 389 threads[0].bounds = bounds; 390 threads[0].format = format; 391 392 y = bounds.y1; 393 dy = (height + num_threads - 1) / num_threads; 394 num_threads -= (num_threads-1) * dy >= bounds.y2 - bounds.y1; 395 396 if (sigtrap_get() == 0) { 397 for (n = 1; n < num_threads; n++) { 398 threads[n] = threads[0]; 399 threads[n].ptr += (y - bounds.y1) * threads[n].stride; 400 threads[n].bounds.y1 = y; 401 threads[n].bounds.y2 = y += dy; 402 403 sna_threads_run(n, rasterize_traps_thread, &threads[n]); 404 } 405 406 assert(y < threads[0].bounds.y2); 407 threads[0].ptr += (y - bounds.y1) * threads[0].stride; 408 threads[0].bounds.y1 = y; 409 rasterize_traps_thread(&threads[0]); 410 411 sna_threads_wait(); 412 sigtrap_put(); 413 } else 414 sna_threads_kill(); 415 416 format = PIXMAN_a8; 417 depth = 8; 418 } 419 } else { 420 scratch = sna_pixmap_create_unattached(screen, 421 width, height, 422 depth); 423 if (!scratch) 424 return; 425 426 memset(scratch->devPrivate.ptr, 0, scratch->devKind*height); 427 image = pixman_image_create_bits(format, width, height, 428 scratch->devPrivate.ptr, 429 scratch->devKind); 430 if (image) { 431 for (; ntrap; ntrap--, traps++) 432 if (xTrapezoidValid(traps)) 433 pixman_rasterize_trapezoid(image, 434 (pixman_trapezoid_t *)traps, 435 -bounds.x1, -bounds.y1); 436 pixman_image_unref(image); 437 } 438 } 439 440 mask = CreatePicture(0, &scratch->drawable, 441 PictureMatchFormat(screen, depth, format), 442 0, 0, serverClient, &error); 443 if (mask) { 444 CompositePicture(op, src, mask, dst, 445 xSrc + bounds.x1 - dst_x, 446 ySrc + bounds.y1 - dst_y, 447 0, 0, 448 bounds.x1, bounds.y1, 449 width, height); 450 FreePicture(mask, 0); 451 } 452 sna_pixmap_destroy(scratch); 453 } else { 454 if (dst->polyEdge == PolyEdgeSharp) 455 maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 456 else 457 maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 458 459 for (; ntrap; ntrap--, traps++) 460 trapezoids_fallback(sna, op, 461 src, dst, maskFormat, 462 xSrc, ySrc, 1, traps); 463 } 464} 465 466static bool 467trapezoid_spans_maybe_inplace(struct sna *sna, 468 CARD8 op, PicturePtr src, PicturePtr dst, 469 PictFormatPtr maskFormat) 470{ 471 struct sna_pixmap *priv; 472 473 if (NO_SCAN_CONVERTER) 474 return false; 475 476 if (dst->alphaMap) 477 return false; 478 if (is_mono(dst, maskFormat)) 479 goto out; 480 481 switch ((int)dst->format) { 482 case PICT_a8: 483 if (!sna_picture_is_solid(src, NULL)) 484 return false; 485 486 switch (op) { 487 case PictOpIn: 488 case PictOpAdd: 489 case PictOpSrc: 490 break; 491 default: 492 return false; 493 } 494 break; 495 496 case PICT_x8r8g8b8: 497 case PICT_a8r8g8b8: 498 if (picture_is_gpu(sna, src, 0)) 499 return false; 500 501 switch (op) { 502 case PictOpOver: 503 case PictOpAdd: 504 case PictOpOutReverse: 505 break; 506 case PictOpSrc: 507 if (sna_picture_is_solid(src, NULL)) 508 break; 509 510 if (!sna_drawable_is_clear(dst->pDrawable)) 511 return false; 512 break; 513 default: 514 return false; 515 } 516 break; 517 default: 518 return false; 519 } 520 521out: 522 priv = sna_pixmap_from_drawable(dst->pDrawable); 523 if (priv == NULL) { 524 DBG(("%s? yes -- unattached\n", __FUNCTION__)); 525 return true; 526 } 527 528 if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) { 529 DBG(("%s? no -- CPU bo is busy\n", __FUNCTION__)); 530 return false; 531 } 532 533 if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL) { 534 DBG(("%s? yes -- damaged on CPU only (all? %d)\n", __FUNCTION__, DAMAGE_IS_ALL(priv->cpu_damage))); 535 return true; 536 } 537 538 if (priv->clear) { 539 DBG(("%s? clear, %s\n", __FUNCTION__, 540 dst->pDrawable->width <= TOR_INPLACE_SIZE ? "yes" : "no")); 541 return dst->pDrawable->width <= TOR_INPLACE_SIZE; 542 } 543 544 if (kgem_bo_is_busy(priv->gpu_bo)) { 545 DBG(("%s? no, GPU bo is busy\n", __FUNCTION__)); 546 return false; 547 } 548 549 if (priv->cpu_damage) { 550 DBG(("%s? yes, idle GPU bo and damage on idle CPU\n", __FUNCTION__)); 551 return true; 552 } 553 554 DBG(("%s? small enough? %s\n", __FUNCTION__, 555 dst->pDrawable->width <= TOR_INPLACE_SIZE ? "yes" : "no")); 556 return dst->pDrawable->width <= TOR_INPLACE_SIZE; 557} 558 559void 560sna_composite_trapezoids(CARD8 op, 561 PicturePtr src, 562 PicturePtr dst, 563 PictFormatPtr maskFormat, 564 INT16 xSrc, INT16 ySrc, 565 int ntrap, xTrapezoid *traps) 566{ 567 PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable); 568 struct sna *sna = to_sna_from_pixmap(pixmap); 569 struct sna_pixmap *priv; 570 bool force_fallback = false; 571 bool rectilinear, pixel_aligned; 572 unsigned flags; 573 int n; 574 575 DBG(("%s(op=%d, src=(%d, %d), mask=%08x, ntrap=%d)\n", __FUNCTION__, 576 op, xSrc, ySrc, 577 maskFormat ? (int)maskFormat->format : 0, 578 ntrap)); 579 580 if (ntrap == 0) 581 return; 582 583 if (NO_ACCEL) 584 goto force_fallback; 585 586 if (FORCE_FALLBACK > 0) 587 goto force_fallback; 588 589 if (wedged(sna)) { 590 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 591 goto force_fallback; 592 } 593 594 if (dst->alphaMap) { 595 DBG(("%s: fallback -- dst alpha map\n", __FUNCTION__)); 596 goto force_fallback; 597 } 598 599 priv = sna_pixmap(pixmap); 600 if (priv == NULL) { 601 DBG(("%s: fallback -- dst is unattached\n", __FUNCTION__)); 602 goto force_fallback; 603 } 604 605 if (FORCE_FALLBACK == 0 && 606 !is_gpu_dst(priv) && !picture_is_gpu(sna, src, 0) && untransformed(src)) { 607 DBG(("%s: force fallbacks -- (!gpu dst, %dx%d? %d) && (src-is-cpu? %d && untransformed? %d)\n", 608 __FUNCTION__, dst->pDrawable->width, dst->pDrawable->height, 609 !is_gpu_dst(priv), !picture_is_gpu(sna, src, 0), untransformed(src))); 610 611force_fallback: 612 force_fallback = true; 613 } 614 615 /* scan through for fast rectangles */ 616 rectilinear = pixel_aligned = true; 617 if (is_mono(dst, maskFormat)) { 618 for (n = 0; n < ntrap && rectilinear; n++) { 619 int lx1 = pixman_fixed_to_int(traps[n].left.p1.x + pixman_fixed_1_minus_e/2); 620 int lx2 = pixman_fixed_to_int(traps[n].left.p2.x + pixman_fixed_1_minus_e/2); 621 int rx1 = pixman_fixed_to_int(traps[n].right.p1.x + pixman_fixed_1_minus_e/2); 622 int rx2 = pixman_fixed_to_int(traps[n].right.p2.x + pixman_fixed_1_minus_e/2); 623 rectilinear &= lx1 == lx2 && rx1 == rx2; 624 } 625 } else if (dst->polyMode != PolyModePrecise) { 626 for (n = 0; n < ntrap && rectilinear; n++) { 627 int lx1 = pixman_fixed_to_fast(traps[n].left.p1.x); 628 int lx2 = pixman_fixed_to_fast(traps[n].left.p2.x); 629 int rx1 = pixman_fixed_to_fast(traps[n].right.p1.x); 630 int rx2 = pixman_fixed_to_fast(traps[n].right.p2.x); 631 int top = pixman_fixed_to_fast(traps[n].top); 632 int bot = pixman_fixed_to_fast(traps[n].bottom); 633 634 rectilinear &= lx1 == lx2 && rx1 == rx2; 635 pixel_aligned &= ((top | bot | lx1 | lx2 | rx1 | rx2) & FAST_SAMPLES_mask) == 0; 636 } 637 } else { 638 for (n = 0; n < ntrap && rectilinear; n++) { 639 rectilinear &= 640 traps[n].left.p1.x == traps[n].left.p2.x && 641 traps[n].right.p1.x == traps[n].right.p2.x; 642 pixel_aligned &= 643 ((traps[n].top | traps[n].bottom | 644 traps[n].left.p1.x | traps[n].left.p2.x | 645 traps[n].right.p1.x | traps[n].right.p2.x) 646 & pixman_fixed_1_minus_e) == 0; 647 } 648 } 649 650 DBG(("%s: rectilinear? %d, pixel-aligned? %d, mono? %d precise? %d\n", 651 __FUNCTION__, rectilinear, pixel_aligned, 652 is_mono(dst, maskFormat), is_precise(dst, maskFormat))); 653 654 flags = 0; 655 if (rectilinear) { 656 if (pixel_aligned) { 657 if (composite_aligned_boxes(sna, op, src, dst, 658 maskFormat, 659 xSrc, ySrc, 660 ntrap, traps, 661 force_fallback)) 662 return; 663 } else { 664 if (composite_unaligned_boxes(sna, op, src, dst, 665 maskFormat, 666 xSrc, ySrc, 667 ntrap, traps, 668 force_fallback)) 669 return; 670 } 671 flags |= COMPOSITE_SPANS_RECTILINEAR; 672 } 673 674 if (force_fallback) 675 goto fallback; 676 677 if (is_mono(dst, maskFormat) && 678 mono_trapezoids_span_converter(sna, op, src, dst, 679 xSrc, ySrc, 680 ntrap, traps)) 681 return; 682 683 if (trapezoid_spans_maybe_inplace(sna, op, src, dst, maskFormat)) { 684 flags |= COMPOSITE_SPANS_INPLACE_HINT; 685 if (trapezoid_span_inplace(sna, op, src, dst, maskFormat, flags, 686 xSrc, ySrc, ntrap, traps, 687 false)) 688 return; 689 } 690 691 if (trapezoid_span_converter(sna, op, src, dst, maskFormat, flags, 692 xSrc, ySrc, ntrap, traps)) 693 return; 694 695 if (trapezoid_span_inplace(sna, op, src, dst, maskFormat, flags, 696 xSrc, ySrc, ntrap, traps, 697 false)) 698 return; 699 700 if (trapezoid_mask_converter(op, src, dst, maskFormat, flags, 701 xSrc, ySrc, ntrap, traps)) 702 return; 703 704fallback: 705 if (trapezoid_span_inplace(sna, op, src, dst, maskFormat, flags, 706 xSrc, ySrc, ntrap, traps, 707 true)) 708 return; 709 710 if (trapezoid_span_fallback(op, src, dst, maskFormat, flags, 711 xSrc, ySrc, ntrap, traps)) 712 return; 713 714 if (trapezoids_inplace_fallback(sna, op, src, dst, maskFormat, 715 ntrap, traps)) 716 return; 717 718 DBG(("%s: fallback mask=%08x, ntrap=%d\n", __FUNCTION__, 719 maskFormat ? (unsigned)maskFormat->format : 0, ntrap)); 720 trapezoids_fallback(sna, op, src, dst, maskFormat, 721 xSrc, ySrc, 722 ntrap, traps); 723} 724 725static void mark_damaged(PixmapPtr pixmap, struct sna_pixmap *priv, 726 BoxPtr box, int16_t x, int16_t y) 727{ 728 box->x1 += x; box->x2 += x; 729 box->y1 += y; box->y2 += y; 730 if (box->x1 <= 0 && box->y1 <= 0 && 731 box->x2 >= pixmap->drawable.width && 732 box->y2 >= pixmap->drawable.height) { 733 sna_damage_destroy(&priv->cpu_damage); 734 sna_damage_all(&priv->gpu_damage, pixmap); 735 list_del(&priv->flush_list); 736 } else { 737 sna_damage_add_box(&priv->gpu_damage, box); 738 sna_damage_subtract_box(&priv->cpu_damage, box); 739 } 740} 741 742static bool 743trap_upload(PicturePtr picture, 744 INT16 x, INT16 y, 745 int ntrap, xTrap *trap) 746{ 747 ScreenPtr screen = picture->pDrawable->pScreen; 748 struct sna *sna = to_sna_from_screen(screen); 749 PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable); 750 PixmapPtr scratch; 751 struct sna_pixmap *priv; 752 BoxRec extents; 753 pixman_image_t *image; 754 int width, height, depth; 755 int n; 756 757 priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_WRITE); 758 if (priv == NULL) 759 return false; 760 761 extents = *RegionExtents(picture->pCompositeClip); 762 for (n = 0; n < ntrap; n++) { 763 int v; 764 765 v = x + pixman_fixed_integer_floor (MIN(trap[n].top.l, trap[n].bot.l)); 766 if (v < extents.x1) 767 extents.x1 = v; 768 769 v = x + pixman_fixed_integer_ceil (MAX(trap[n].top.r, trap[n].bot.r)); 770 if (v > extents.x2) 771 extents.x2 = v; 772 773 v = y + pixman_fixed_integer_floor (trap[n].top.y); 774 if (v < extents.y1) 775 extents.y1 = v; 776 777 v = y + pixman_fixed_integer_ceil (trap[n].bot.y); 778 if (v > extents.y2) 779 extents.y2 = v; 780 } 781 782 DBG(("%s: extents (%d, %d), (%d, %d)\n", 783 __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 784 785 width = extents.x2 - extents.x1; 786 height = extents.y2 - extents.y1; 787 depth = picture->pDrawable->depth; 788 789 DBG(("%s: tmp (%dx%d) depth=%d\n", 790 __FUNCTION__, width, height, depth)); 791 scratch = sna_pixmap_create_upload(screen, 792 width, height, depth, 793 KGEM_BUFFER_WRITE); 794 if (!scratch) 795 return true; 796 797 memset(scratch->devPrivate.ptr, 0, scratch->devKind*height); 798 image = pixman_image_create_bits((pixman_format_code_t)picture->format, 799 width, height, 800 scratch->devPrivate.ptr, 801 scratch->devKind); 802 if (image) { 803 pixman_add_traps (image, -extents.x1, -extents.y1, 804 ntrap, (pixman_trap_t *)trap); 805 806 pixman_image_unref(image); 807 } 808 809 /* XXX clip boxes */ 810 get_drawable_deltas(picture->pDrawable, pixmap, &x, &y); 811 sna->render.copy_boxes(sna, GXcopy, 812 &scratch->drawable, __sna_pixmap_get_bo(scratch), -extents.x1, -extents.x1, 813 &pixmap->drawable, priv->gpu_bo, x, y, 814 &extents, 1, 0); 815 mark_damaged(pixmap, priv, &extents, x, y); 816 817 sna_pixmap_destroy(scratch); 818 return true; 819} 820 821void 822sna_add_traps(PicturePtr picture, INT16 x, INT16 y, int n, xTrap *t) 823{ 824 PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable); 825 struct sna *sna = to_sna_from_pixmap(pixmap); 826 struct sna_pixmap *priv = sna_pixmap(pixmap); 827 828 DBG(("%s (%d, %d) x %d\n", __FUNCTION__, x, y, n)); 829 830 if (priv && is_gpu_dst(priv)) { 831 if (trap_span_converter(sna, picture, x, y, n, t)) 832 return; 833 } 834 835 if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER)) { 836 if (trap_mask_converter(sna, picture, x, y, n, t)) 837 return; 838 839 if (trap_upload(picture, x, y, n, t)) 840 return; 841 } 842 843 DBG(("%s -- fallback\n", __FUNCTION__)); 844 if (sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE)) { 845 pixman_image_t *image; 846 int dx, dy; 847 848 if (!(image = image_from_pict(picture, false, &dx, &dy))) 849 return; 850 851 if (sigtrap_get() == 0) { 852 pixman_add_traps(image, x + dx, y + dy, n, (pixman_trap_t *)t); 853 sigtrap_put(); 854 } 855 856 free_pixman_pict(picture, image); 857 } 858} 859 860#if HAS_PIXMAN_TRIANGLES 861static void 862triangles_fallback(CARD8 op, 863 PicturePtr src, 864 PicturePtr dst, 865 PictFormatPtr maskFormat, 866 INT16 xSrc, INT16 ySrc, 867 int n, xTriangle *tri) 868{ 869 ScreenPtr screen = dst->pDrawable->pScreen; 870 871 DBG(("%s op=%d, count=%d\n", __FUNCTION__, op, n)); 872 873 if (maskFormat) { 874 PixmapPtr scratch; 875 PicturePtr mask; 876 INT16 dst_x, dst_y; 877 BoxRec bounds; 878 int width, height, depth; 879 pixman_image_t *image; 880 pixman_format_code_t format; 881 int error; 882 883 dst_x = pixman_fixed_to_int(tri[0].p1.x); 884 dst_y = pixman_fixed_to_int(tri[0].p1.y); 885 886 miTriangleBounds(n, tri, &bounds); 887 DBG(("%s: bounds (%d, %d), (%d, %d)\n", 888 __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 889 890 if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 891 return; 892 893 if (!sna_compute_composite_extents(&bounds, 894 src, NULL, dst, 895 xSrc, ySrc, 896 0, 0, 897 bounds.x1, bounds.y1, 898 bounds.x2 - bounds.x1, 899 bounds.y2 - bounds.y1)) 900 return; 901 902 DBG(("%s: extents (%d, %d), (%d, %d)\n", 903 __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 904 905 width = bounds.x2 - bounds.x1; 906 height = bounds.y2 - bounds.y1; 907 bounds.x1 -= dst->pDrawable->x; 908 bounds.y1 -= dst->pDrawable->y; 909 depth = maskFormat->depth; 910 format = maskFormat->format | (BitsPerPixel(depth) << 24); 911 912 DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n", 913 __FUNCTION__, width, height, depth, format)); 914 scratch = sna_pixmap_create_upload(screen, 915 width, height, depth, 916 KGEM_BUFFER_WRITE); 917 if (!scratch) 918 return; 919 920 memset(scratch->devPrivate.ptr, 0, (size_t)scratch->devKind*height); 921 image = pixman_image_create_bits(format, width, height, 922 scratch->devPrivate.ptr, 923 scratch->devKind); 924 if (image) { 925 pixman_add_triangles(image, 926 -bounds.x1, -bounds.y1, 927 n, (pixman_triangle_t *)tri); 928 pixman_image_unref(image); 929 } 930 931 mask = CreatePicture(0, &scratch->drawable, 932 PictureMatchFormat(screen, depth, format), 933 0, 0, serverClient, &error); 934 if (mask) { 935 CompositePicture(op, src, mask, dst, 936 xSrc + bounds.x1 - dst_x, 937 ySrc + bounds.y1 - dst_y, 938 0, 0, 939 bounds.x1, bounds.y1, 940 width, height); 941 FreePicture(mask, 0); 942 } 943 sna_pixmap_destroy(scratch); 944 } else { 945 if (dst->polyEdge == PolyEdgeSharp) 946 maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 947 else 948 maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 949 950 for (; n--; tri++) 951 triangles_fallback(op, 952 src, dst, maskFormat, 953 xSrc, ySrc, 1, tri); 954 } 955} 956 957void 958sna_composite_triangles(CARD8 op, 959 PicturePtr src, 960 PicturePtr dst, 961 PictFormatPtr maskFormat, 962 INT16 xSrc, INT16 ySrc, 963 int n, xTriangle *tri) 964{ 965 struct sna *sna = to_sna_from_drawable(dst->pDrawable); 966 967 if (triangles_span_converter(sna, op, src, dst, maskFormat, 968 xSrc, ySrc, 969 n, tri)) 970 return; 971 972 if (triangles_mask_converter(op, src, dst, maskFormat, 973 xSrc, ySrc, 974 n, tri)) 975 return; 976 977 triangles_fallback(op, src, dst, maskFormat, xSrc, ySrc, n, tri); 978} 979 980static void 981tristrip_fallback(CARD8 op, 982 PicturePtr src, 983 PicturePtr dst, 984 PictFormatPtr maskFormat, 985 INT16 xSrc, INT16 ySrc, 986 int n, xPointFixed *points) 987{ 988 ScreenPtr screen = dst->pDrawable->pScreen; 989 990 if (maskFormat) { 991 PixmapPtr scratch; 992 PicturePtr mask; 993 INT16 dst_x, dst_y; 994 BoxRec bounds; 995 int width, height, depth; 996 pixman_image_t *image; 997 pixman_format_code_t format; 998 int error; 999 1000 dst_x = pixman_fixed_to_int(points->x); 1001 dst_y = pixman_fixed_to_int(points->y); 1002 1003 miPointFixedBounds(n, points, &bounds); 1004 DBG(("%s: bounds (%d, %d), (%d, %d)\n", 1005 __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 1006 1007 if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 1008 return; 1009 1010 if (!sna_compute_composite_extents(&bounds, 1011 src, NULL, dst, 1012 xSrc, ySrc, 1013 0, 0, 1014 bounds.x1, bounds.y1, 1015 bounds.x2 - bounds.x1, 1016 bounds.y2 - bounds.y1)) 1017 return; 1018 1019 DBG(("%s: extents (%d, %d), (%d, %d)\n", 1020 __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 1021 1022 width = bounds.x2 - bounds.x1; 1023 height = bounds.y2 - bounds.y1; 1024 bounds.x1 -= dst->pDrawable->x; 1025 bounds.y1 -= dst->pDrawable->y; 1026 depth = maskFormat->depth; 1027 format = maskFormat->format | (BitsPerPixel(depth) << 24); 1028 1029 DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n", 1030 __FUNCTION__, width, height, depth, format)); 1031 scratch = sna_pixmap_create_upload(screen, 1032 width, height, depth, 1033 KGEM_BUFFER_WRITE); 1034 if (!scratch) 1035 return; 1036 1037 memset(scratch->devPrivate.ptr, 0, scratch->devKind*height); 1038 image = pixman_image_create_bits(format, width, height, 1039 scratch->devPrivate.ptr, 1040 scratch->devKind); 1041 if (image) { 1042 xTriangle tri; 1043 xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 }; 1044 int i; 1045 1046 *p[0] = points[0]; 1047 *p[1] = points[1]; 1048 *p[2] = points[2]; 1049 pixman_add_triangles(image, 1050 -bounds.x1, -bounds.y1, 1051 1, (pixman_triangle_t *)&tri); 1052 for (i = 3; i < n; i++) { 1053 *p[i%3] = points[i]; 1054 pixman_add_triangles(image, 1055 -bounds.x1, -bounds.y1, 1056 1, (pixman_triangle_t *)&tri); 1057 } 1058 pixman_image_unref(image); 1059 } 1060 1061 mask = CreatePicture(0, &scratch->drawable, 1062 PictureMatchFormat(screen, depth, format), 1063 0, 0, serverClient, &error); 1064 if (mask) { 1065 CompositePicture(op, src, mask, dst, 1066 xSrc + bounds.x1 - dst_x, 1067 ySrc + bounds.y1 - dst_y, 1068 0, 0, 1069 bounds.x1, bounds.y1, 1070 width, height); 1071 FreePicture(mask, 0); 1072 } 1073 sna_pixmap_destroy(scratch); 1074 } else { 1075 xTriangle tri; 1076 xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 }; 1077 int i; 1078 1079 if (dst->polyEdge == PolyEdgeSharp) 1080 maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 1081 else 1082 maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 1083 1084 *p[0] = points[0]; 1085 *p[1] = points[1]; 1086 *p[2] = points[2]; 1087 triangles_fallback(op, 1088 src, dst, maskFormat, 1089 xSrc, ySrc, 1, &tri); 1090 for (i = 3; i < n; i++) { 1091 *p[i%3] = points[i]; 1092 /* Should xSrc,ySrc be updated? */ 1093 triangles_fallback(op, 1094 src, dst, maskFormat, 1095 xSrc, ySrc, 1, &tri); 1096 } 1097 } 1098} 1099 1100void 1101sna_composite_tristrip(CARD8 op, 1102 PicturePtr src, 1103 PicturePtr dst, 1104 PictFormatPtr maskFormat, 1105 INT16 xSrc, INT16 ySrc, 1106 int n, xPointFixed *points) 1107{ 1108 struct sna *sna = to_sna_from_drawable(dst->pDrawable); 1109 1110 if (tristrip_span_converter(sna, op, src, dst, maskFormat, xSrc, ySrc, n, points)) 1111 return; 1112 1113 tristrip_fallback(op, src, dst, maskFormat, xSrc, ySrc, n, points); 1114} 1115 1116static void 1117trifan_fallback(CARD8 op, 1118 PicturePtr src, 1119 PicturePtr dst, 1120 PictFormatPtr maskFormat, 1121 INT16 xSrc, INT16 ySrc, 1122 int n, xPointFixed *points) 1123{ 1124 ScreenPtr screen = dst->pDrawable->pScreen; 1125 1126 if (maskFormat) { 1127 PixmapPtr scratch; 1128 PicturePtr mask; 1129 INT16 dst_x, dst_y; 1130 BoxRec bounds; 1131 int width, height, depth; 1132 pixman_image_t *image; 1133 pixman_format_code_t format; 1134 int error; 1135 1136 dst_x = pixman_fixed_to_int(points->x); 1137 dst_y = pixman_fixed_to_int(points->y); 1138 1139 miPointFixedBounds(n, points, &bounds); 1140 DBG(("%s: bounds (%d, %d), (%d, %d)\n", 1141 __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 1142 1143 if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 1144 return; 1145 1146 if (!sna_compute_composite_extents(&bounds, 1147 src, NULL, dst, 1148 xSrc, ySrc, 1149 0, 0, 1150 bounds.x1, bounds.y1, 1151 bounds.x2 - bounds.x1, 1152 bounds.y2 - bounds.y1)) 1153 return; 1154 1155 DBG(("%s: extents (%d, %d), (%d, %d)\n", 1156 __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 1157 1158 width = bounds.x2 - bounds.x1; 1159 height = bounds.y2 - bounds.y1; 1160 bounds.x1 -= dst->pDrawable->x; 1161 bounds.y1 -= dst->pDrawable->y; 1162 depth = maskFormat->depth; 1163 format = maskFormat->format | (BitsPerPixel(depth) << 24); 1164 1165 DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n", 1166 __FUNCTION__, width, height, depth, format)); 1167 scratch = sna_pixmap_create_upload(screen, 1168 width, height, depth, 1169 KGEM_BUFFER_WRITE); 1170 if (!scratch) 1171 return; 1172 1173 memset(scratch->devPrivate.ptr, 0, scratch->devKind*height); 1174 image = pixman_image_create_bits(format, width, height, 1175 scratch->devPrivate.ptr, 1176 scratch->devKind); 1177 if (image) { 1178 xTriangle tri; 1179 xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 }; 1180 int i; 1181 1182 *p[0] = points[0]; 1183 *p[1] = points[1]; 1184 *p[2] = points[2]; 1185 pixman_add_triangles(image, 1186 -bounds.x1, -bounds.y1, 1187 1, (pixman_triangle_t *)&tri); 1188 for (i = 3; i < n; i++) { 1189 *p[2 - (i&1)] = points[i]; 1190 pixman_add_triangles(image, 1191 -bounds.x1, -bounds.y1, 1192 1, (pixman_triangle_t *)&tri); 1193 } 1194 pixman_image_unref(image); 1195 } 1196 1197 mask = CreatePicture(0, &scratch->drawable, 1198 PictureMatchFormat(screen, depth, format), 1199 0, 0, serverClient, &error); 1200 if (mask) { 1201 CompositePicture(op, src, mask, dst, 1202 xSrc + bounds.x1 - dst_x, 1203 ySrc + bounds.y1 - dst_y, 1204 0, 0, 1205 bounds.x1, bounds.y1, 1206 width, height); 1207 FreePicture(mask, 0); 1208 } 1209 sna_pixmap_destroy(scratch); 1210 } else { 1211 xTriangle tri; 1212 xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 }; 1213 int i; 1214 1215 if (dst->polyEdge == PolyEdgeSharp) 1216 maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 1217 else 1218 maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 1219 1220 *p[0] = points[0]; 1221 *p[1] = points[1]; 1222 *p[2] = points[2]; 1223 triangles_fallback(op, 1224 src, dst, maskFormat, 1225 xSrc, ySrc, 1, &tri); 1226 for (i = 3; i < n; i++) { 1227 *p[2 - (i&1)] = points[i]; 1228 /* Should xSrc,ySrc be updated? */ 1229 triangles_fallback(op, 1230 src, dst, maskFormat, 1231 xSrc, ySrc, 1, &tri); 1232 } 1233 } 1234} 1235 1236void 1237sna_composite_trifan(CARD8 op, 1238 PicturePtr src, 1239 PicturePtr dst, 1240 PictFormatPtr maskFormat, 1241 INT16 xSrc, INT16 ySrc, 1242 int n, xPointFixed *points) 1243{ 1244 trifan_fallback(op, src, dst, maskFormat, xSrc, ySrc, n, points); 1245} 1246#endif 1247