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 42struct quorem { 43 int32_t quo; 44 int64_t rem; 45}; 46 47struct mono_edge { 48 struct mono_edge *next, *prev; 49 50 int32_t height_left; 51 int32_t dir; 52 53 int64_t dy; 54 struct quorem x; 55 struct quorem dxdy; 56}; 57 58struct mono_polygon { 59 int num_edges; 60 struct mono_edge *edges; 61 struct mono_edge **y_buckets; 62 63 struct mono_edge *y_buckets_embedded[64]; 64 struct mono_edge edges_embedded[32]; 65}; 66 67struct mono { 68 /* Leftmost edge on the current scan line. */ 69 struct mono_edge head, tail; 70 int is_vertical; 71 72 struct sna *sna; 73 struct sna_composite_op op; 74 pixman_region16_t clip; 75 const BoxRec *clip_start, *clip_end; 76 77 fastcall void (*span)(struct mono *, int, int, BoxPtr); 78 79 struct mono_polygon polygon; 80}; 81 82#define I(x) pixman_fixed_to_int((x) + pixman_fixed_1_minus_e/2) 83 84static struct quorem 85floored_muldivrem(int32_t x, int32_t a, int32_t b) 86{ 87 struct quorem qr; 88 int64_t xa = (int64_t)x*a; 89 qr.quo = xa/b; 90 qr.rem = xa%b; 91 if (qr.rem < 0) { 92 qr.quo -= 1; 93 qr.rem += b; 94 } 95 return qr; 96} 97 98#if HAS_DEBUG_FULL 99static void _assert_pixmap_contains_box(PixmapPtr pixmap, BoxPtr box, const char *function) 100{ 101 if (box->x1 < 0 || box->y1 < 0 || 102 box->x2 > pixmap->drawable.width || 103 box->y2 > pixmap->drawable.height) 104 FatalError("%s: damage box is beyond the pixmap: box=(%d, %d), (%d, %d), pixmap=(%d, %d)\n", 105 __FUNCTION__, 106 box->x1, box->y1, box->x2, box->y2, 107 pixmap->drawable.width, 108 pixmap->drawable.height); 109} 110#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__) 111#else 112#define assert_pixmap_contains_box(p, b) 113#endif 114 115static void apply_damage(struct sna_composite_op *op, RegionPtr region) 116{ 117 DBG(("%s: damage=%p, region=%dx[(%d, %d), (%d, %d)]\n", 118 __FUNCTION__, op->damage, 119 region_num_rects(region), 120 region->extents.x1, region->extents.y1, 121 region->extents.x2, region->extents.y2)); 122 123 if (op->damage == NULL) 124 return; 125 126 RegionTranslate(region, op->dst.x, op->dst.y); 127 128 assert_pixmap_contains_box(op->dst.pixmap, RegionExtents(region)); 129 sna_damage_add(op->damage, region); 130} 131 132static void _apply_damage_box(struct sna_composite_op *op, const BoxRec *box) 133{ 134 BoxRec r; 135 136 r.x1 = box->x1 + op->dst.x; 137 r.x2 = box->x2 + op->dst.x; 138 r.y1 = box->y1 + op->dst.y; 139 r.y2 = box->y2 + op->dst.y; 140 141 assert_pixmap_contains_box(op->dst.pixmap, &r); 142 sna_damage_add_box(op->damage, &r); 143} 144 145inline static void apply_damage_box(struct sna_composite_op *op, const BoxRec *box) 146{ 147 if (op->damage) 148 _apply_damage_box(op, box); 149} 150 151static bool 152mono_polygon_init(struct mono_polygon *polygon, BoxPtr box, int num_edges) 153{ 154 unsigned h = box->y2 - box->y1; 155 156 polygon->y_buckets = polygon->y_buckets_embedded; 157 if (h > ARRAY_SIZE (polygon->y_buckets_embedded)) { 158 polygon->y_buckets = malloc (h * sizeof (struct mono_edge *)); 159 if (unlikely (NULL == polygon->y_buckets)) 160 return false; 161 } 162 163 polygon->num_edges = 0; 164 polygon->edges = polygon->edges_embedded; 165 if (num_edges > (int)ARRAY_SIZE (polygon->edges_embedded)) { 166 polygon->edges = malloc (num_edges * sizeof (struct mono_edge)); 167 if (unlikely (polygon->edges == NULL)) { 168 if (polygon->y_buckets != polygon->y_buckets_embedded) 169 free(polygon->y_buckets); 170 return false; 171 } 172 } 173 174 memset(polygon->y_buckets, 0, h * sizeof (struct edge *)); 175 return true; 176} 177 178static void 179mono_polygon_fini(struct mono_polygon *polygon) 180{ 181 if (polygon->y_buckets != polygon->y_buckets_embedded) 182 free(polygon->y_buckets); 183 184 if (polygon->edges != polygon->edges_embedded) 185 free(polygon->edges); 186} 187 188static void 189mono_add_line(struct mono *mono, 190 int dst_x, int dst_y, 191 xFixed top, xFixed bottom, 192 const xPointFixed *p1, const xPointFixed *p2, 193 int dir) 194{ 195 struct mono_polygon *polygon = &mono->polygon; 196 struct mono_edge *e; 197 int y, ytop, ybot; 198 199 __DBG(("%s: top=%d, bottom=%d, line=(%d, %d), (%d, %d) delta=%dx%d, dir=%d\n", 200 __FUNCTION__, 201 (int)top, (int)bottom, 202 (int)p1->x, (int)p1->y, (int)p2->x, (int)p2->y, 203 dst_x, dst_y, 204 dir)); 205 206 if (top > bottom) { 207 const xPointFixed *t; 208 209 y = top; 210 top = bottom; 211 bottom = y; 212 213 t = p1; 214 p1 = p2; 215 p2 = t; 216 217 dir = -dir; 218 } 219 220 y = I(top) + dst_y; 221 ytop = MAX(y, mono->clip.extents.y1); 222 223 y = I(bottom) + dst_y; 224 ybot = MIN(y, mono->clip.extents.y2); 225 226 __DBG(("%s: edge height [%d, %d] = %d\n", 227 __FUNCTION__, ytop, ybot, ybot - ytop)); 228 if (ybot <= ytop) { 229 __DBG(("discard clipped line\n")); 230 return; 231 } 232 233 e = polygon->edges + polygon->num_edges++; 234 e->height_left = ybot - ytop; 235 e->dir = dir; 236 237 if (I(p1->x) == I(p2->x)) { 238 __DBG(("%s: vertical edge x:%d\n", __FUNCTION__, I(p1->x))); 239 e->x.quo = p1->x; 240 e->x.rem = 0; 241 e->dxdy.quo = 0; 242 e->dxdy.rem = 0; 243 e->dy = 0; 244 } else { 245 int64_t dx = (int64_t)p2->x - p1->x; 246 int64_t dy = (int64_t)p2->y - p1->y; 247 248 __DBG(("%s: diagonal edge (%d, %d), x:[%d, %d]\n", __FUNCTION__, dx, dy, I(p1->x), I(p2->x))); 249 assert(dy > 0); 250 251 e->dxdy = floored_muldivrem(dx, pixman_fixed_1, dy); 252 253 e->x = floored_muldivrem((ytop - dst_y) * pixman_fixed_1 + pixman_fixed_1/2 - p1->y, 254 dx, dy); 255 e->x.quo += p1->x; 256 e->x.rem -= dy; 257 258 e->dy = dy; 259 } 260 e->x.quo += dst_x*pixman_fixed_1; 261 __DBG(("%s: initial x=%d [%d.%d/%d] + dxdy=%d.%d/%d\n", 262 __FUNCTION__, 263 I(e->x.quo), e->x.quo, e->x.rem, e->dy, 264 e->dxdy.quo, e->dxdy.rem, e->dy)); 265 266 { 267 struct mono_edge **ptail = &polygon->y_buckets[ytop - mono->clip.extents.y1]; 268 assert(ytop - mono->clip.extents.y1 < mono->clip.extents.y2 - mono->clip.extents.y1); 269 if (*ptail) 270 (*ptail)->prev = e; 271 e->next = *ptail; 272 e->prev = NULL; 273 *ptail = e; 274 } 275} 276 277static struct mono_edge * 278mono_merge_sorted_edges(struct mono_edge *head_a, struct mono_edge *head_b) 279{ 280 struct mono_edge *head, **next, *prev; 281 int32_t x; 282 283 if (head_b == NULL) 284 return head_a; 285 286 prev = head_a->prev; 287 next = &head; 288 if (head_a->x.quo <= head_b->x.quo) { 289 head = head_a; 290 } else { 291 head = head_b; 292 head_b->prev = prev; 293 goto start_with_b; 294 } 295 296 do { 297 x = head_b->x.quo; 298 while (head_a != NULL && head_a->x.quo <= x) { 299 prev = head_a; 300 next = &head_a->next; 301 head_a = head_a->next; 302 } 303 304 head_b->prev = prev; 305 *next = head_b; 306 if (head_a == NULL) 307 return head; 308 309start_with_b: 310 x = head_a->x.quo; 311 while (head_b != NULL && head_b->x.quo <= x) { 312 prev = head_b; 313 next = &head_b->next; 314 head_b = head_b->next; 315 } 316 317 head_a->prev = prev; 318 *next = head_a; 319 if (head_b == NULL) 320 return head; 321 } while (1); 322} 323 324static struct mono_edge * 325mono_sort_edges(struct mono_edge *list, 326 unsigned int level, 327 struct mono_edge **head_out) 328{ 329 struct mono_edge *head_other, *remaining; 330 unsigned int i; 331 332 head_other = list->next; 333 334 if (head_other == NULL) { 335 *head_out = list; 336 return NULL; 337 } 338 339 remaining = head_other->next; 340 if (list->x.quo <= head_other->x.quo) { 341 *head_out = list; 342 head_other->next = NULL; 343 } else { 344 *head_out = head_other; 345 head_other->prev = list->prev; 346 head_other->next = list; 347 list->prev = head_other; 348 list->next = NULL; 349 } 350 351 for (i = 0; i < level && remaining; i++) { 352 remaining = mono_sort_edges(remaining, i, &head_other); 353 *head_out = mono_merge_sorted_edges(*head_out, head_other); 354 } 355 356 return remaining; 357} 358 359static struct mono_edge *mono_filter(struct mono_edge *edges) 360{ 361 struct mono_edge *e; 362 363 e = edges; 364 while (e->next) { 365 struct mono_edge *n = e->next; 366 if (e->dir == -n->dir && 367 e->height_left == n->height_left && 368 e->x.quo == n->x.quo && 369 e->x.rem == n->x.rem && 370 e->dxdy.quo == n->dxdy.quo && 371 e->dxdy.rem == n->dxdy.rem) { 372 assert(e->dy == n->dy); 373 __DBG(("%s: discarding cancellation pair (%d.%d) + (%d.%d)\n", 374 __FUNCTION__, e->x.quo, e->x.rem, e->dxdy.quo, e->dxdy.rem)); 375 376 if (e->prev) 377 e->prev->next = n->next; 378 else 379 edges = n->next; 380 if (n->next) 381 n->next->prev = e->prev; 382 else 383 break; 384 385 e = n->next; 386 } else { 387 __DBG(("%s: adding edge (%d.%d) + (%d.%d)/%d, height=%d\n", 388 __FUNCTION__, n->x.quo, n->x.rem, n->dxdy.quo, n->dxdy.rem, n->dy, n->height_left)); 389 e = n; 390 } 391 } 392 393 return edges; 394} 395 396static struct mono_edge * 397mono_merge_unsorted_edges(struct mono_edge *head, struct mono_edge *unsorted) 398{ 399 mono_sort_edges(unsorted, UINT_MAX, &unsorted); 400 return mono_merge_sorted_edges(head, mono_filter(unsorted)); 401} 402 403#if 0 404static inline void 405__dbg_mono_edges(const char *function, struct mono_edge *edges) 406{ 407 DBG(("%s: ", function)); 408 while (edges) { 409 if (edges->x.quo < INT16_MAX << 16) { 410 DBG(("(%d.%06d)+(%d.%06d)x%d, ", 411 edges->x.quo, edges->x.rem, 412 edges->dxdy.quo, edges->dxdy.rem, 413 edges->dy*edges->dir)); 414 } 415 edges = edges->next; 416 } 417 DBG(("\n")); 418} 419#define DBG_MONO_EDGES(x) __dbg_mono_edges(__FUNCTION__, x) 420static inline void 421VALIDATE_MONO_EDGES(struct mono_edge *edges) 422{ 423 int prev_x = edges->x.quo; 424 while ((edges = edges->next)) { 425 assert(edges->x.quo >= prev_x); 426 prev_x = edges->x.quo; 427 } 428} 429 430#else 431#define DBG_MONO_EDGES(x) 432#define VALIDATE_MONO_EDGES(x) 433#endif 434 435inline static void 436mono_merge_edges(struct mono *c, struct mono_edge *edges) 437{ 438 struct mono_edge *e; 439 440 DBG_MONO_EDGES(edges); 441 442 for (e = edges; c->is_vertical && e; e = e->next) 443 c->is_vertical = e->dy == 0; 444 445 c->head.next = mono_merge_unsorted_edges(c->head.next, edges); 446} 447 448fastcall static void 449mono_span(struct mono *c, int x1, int x2, BoxPtr box) 450{ 451 __DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2)); 452 453 box->x1 = x1; 454 box->x2 = x2; 455 456 if (c->clip.data) { 457 pixman_region16_t region; 458 459 pixman_region_init_rects(®ion, box, 1); 460 RegionIntersect(®ion, ®ion, &c->clip); 461 if (region_num_rects(®ion)) { 462 c->op.boxes(c->sna, &c->op, 463 region_rects(®ion), 464 region_num_rects(®ion)); 465 apply_damage(&c->op, ®ion); 466 } 467 pixman_region_fini(®ion); 468 } else { 469 c->op.box(c->sna, &c->op, box); 470 apply_damage_box(&c->op, box); 471 } 472} 473 474fastcall static void 475mono_span__fast(struct mono *c, int x1, int x2, BoxPtr box) 476{ 477 __DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2)); 478 479 box->x1 = x1; 480 box->x2 = x2; 481 482 c->op.box(c->sna, &c->op, box); 483} 484 485fastcall static void 486mono_span__clipped(struct mono *c, int x1, int x2, BoxPtr box) 487{ 488 const BoxRec *b; 489 490 __DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2)); 491 492 c->clip_start = 493 find_clip_box_for_y(c->clip_start, c->clip_end, box->y1); 494 495 b = c->clip_start; 496 while (b != c->clip_end) { 497 BoxRec clipped; 498 499 if (box->y2 <= b->y1) 500 break; 501 502 clipped.x1 = x1; 503 clipped.x2 = x2; 504 clipped.y1 = box->y1; 505 clipped.y2 = box->y2; 506 if (!box_intersect(&clipped, b++)) 507 continue; 508 509 c->op.box(c->sna, &c->op, &clipped); 510 } 511} 512 513struct mono_span_thread_boxes { 514 const struct sna_composite_op *op; 515#define MONO_SPAN_MAX_BOXES (8192/sizeof(BoxRec)) 516 BoxRec boxes[MONO_SPAN_MAX_BOXES]; 517 int num_boxes; 518}; 519 520inline static void 521thread_mono_span_add_box(struct mono *c, const BoxRec *box) 522{ 523 struct mono_span_thread_boxes *b = c->op.priv; 524 525 if (unlikely(b->num_boxes == MONO_SPAN_MAX_BOXES)) { 526 b->op->thread_boxes(c->sna, b->op, b->boxes, b->num_boxes); 527 b->num_boxes = 0; 528 } 529 530 b->boxes[b->num_boxes++] = *box; 531 assert(b->num_boxes <= MONO_SPAN_MAX_BOXES); 532} 533 534fastcall static void 535thread_mono_span_clipped(struct mono *c, int x1, int x2, BoxPtr box) 536{ 537 const BoxRec *b; 538 539 __DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2)); 540 541 c->clip_start = 542 find_clip_box_for_y(c->clip_start, c->clip_end, box->y1); 543 544 b = c->clip_start; 545 while (b != c->clip_end) { 546 BoxRec clipped; 547 548 if (box->y2 <= b->y1) 549 break; 550 551 clipped.x1 = x1; 552 clipped.x2 = x2; 553 clipped.y1 = box->y1; 554 clipped.y2 = box->y2; 555 if (!box_intersect(&clipped, b++)) 556 continue; 557 558 thread_mono_span_add_box(c, &clipped); 559 } 560} 561 562fastcall static void 563thread_mono_span(struct mono *c, int x1, int x2, BoxPtr box) 564{ 565 __DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2)); 566 567 box->x1 = x1; 568 box->x2 = x2; 569 thread_mono_span_add_box(c, box); 570} 571 572inline static void 573mono_row(struct mono *c, int16_t y, int16_t h) 574{ 575 struct mono_edge *edge = c->head.next; 576 int prev_x = INT_MIN; 577 int16_t xstart = INT16_MIN; 578 int winding = 0; 579 BoxRec box; 580 581 __DBG(("%s: y=%d, h=%d\n", __FUNCTION__, y, h)); 582 583 DBG_MONO_EDGES(edge); 584 VALIDATE_MONO_EDGES(&c->head); 585 586 box.y1 = c->clip.extents.y1 + y; 587 box.y2 = box.y1 + h; 588 589 while (&c->tail != edge) { 590 struct mono_edge *next = edge->next; 591 int16_t xend = I(edge->x.quo); 592 593 __DBG(("%s: adding edge dir=%d [winding=%d], x=%d [%d]\n", 594 __FUNCTION__, edge->dir, winding + edge->dir, xend, edge->x.quo)); 595 if (--edge->height_left) { 596 if (edge->dy) { 597 edge->x.quo += edge->dxdy.quo; 598 edge->x.rem += edge->dxdy.rem; 599 if (edge->x.rem >= 0) { 600 ++edge->x.quo; 601 edge->x.rem -= edge->dy; 602 } 603 __DBG(("%s: stepped edge (%d.%d) + (%d.%d)/%d, height=%d, prev_x=%d\n", 604 __FUNCTION__, edge->x.quo, edge->x.rem, edge->dxdy.quo, edge->dxdy.rem, edge->dy, edge->height_left, edge->x.quo)); 605 } 606 607 if (edge->x.quo < prev_x) { 608 struct mono_edge *pos = edge->prev; 609 pos->next = next; 610 next->prev = pos; 611 do { 612 pos = pos->prev; 613 } while (edge->x.quo < pos->x.quo); 614 pos->next->prev = edge; 615 edge->next = pos->next; 616 edge->prev = pos; 617 pos->next = edge; 618 } else 619 prev_x = edge->x.quo; 620 } else { 621 edge->prev->next = next; 622 next->prev = edge->prev; 623 } 624 625 winding += edge->dir; 626 if (winding == 0) { 627 assert(I(next->x.quo) >= xend); 628 if (I(next->x.quo) > xend) { 629 __DBG(("%s: end span: %d\n", __FUNCTION__, xend)); 630 if (xstart < c->clip.extents.x1) 631 xstart = c->clip.extents.x1; 632 if (xend > c->clip.extents.x2) 633 xend = c->clip.extents.x2; 634 if (xend > xstart) { 635 __DBG(("%s: emit span [%d, %d]\n", __FUNCTION__, xstart, xend)); 636 c->span(c, xstart, xend, &box); 637 } 638 xstart = INT16_MIN; 639 } 640 } else if (xstart == INT16_MIN) { 641 __DBG(("%s: starting new span: %d\n", __FUNCTION__, xend)); 642 xstart = xend; 643 } 644 645 edge = next; 646 } 647 648 DBG_MONO_EDGES(c->head.next); 649 VALIDATE_MONO_EDGES(&c->head); 650} 651 652static bool 653mono_init(struct mono *c, int num_edges) 654{ 655 if (!mono_polygon_init(&c->polygon, &c->clip.extents, num_edges)) 656 return false; 657 658 c->head.dy = 0; 659 c->head.height_left = INT_MAX; 660 c->head.x.quo = INT16_MIN << 16; 661 c->head.prev = NULL; 662 c->head.next = &c->tail; 663 c->tail.prev = &c->head; 664 c->tail.next = NULL; 665 c->tail.x.quo = INT16_MAX << 16; 666 c->tail.height_left = INT_MAX; 667 c->tail.dy = 0; 668 669 c->is_vertical = 1; 670 671 return true; 672} 673 674static void 675mono_fini(struct mono *mono) 676{ 677 mono_polygon_fini(&mono->polygon); 678} 679 680static void 681mono_step_edges(struct mono *c, int count) 682{ 683 struct mono_edge *edge; 684 685 for (edge = c->head.next; edge != &c->tail; edge = edge->next) { 686 edge->height_left -= count; 687 if (! edge->height_left) { 688 edge->prev->next = edge->next; 689 edge->next->prev = edge->prev; 690 } 691 } 692} 693 694flatten static void 695mono_render(struct mono *mono) 696{ 697 struct mono_polygon *polygon = &mono->polygon; 698 int i, j, h = mono->clip.extents.y2 - mono->clip.extents.y1; 699 700 assert(mono->span); 701 702 for (i = 0; i < h; i = j) { 703 j = i + 1; 704 705 __DBG(("%s: row=%d, new edges? %d\n", __FUNCTION__, 706 i, polygon->y_buckets[i] != NULL)); 707 708 if (polygon->y_buckets[i]) 709 mono_merge_edges(mono, polygon->y_buckets[i]); 710 711 __DBG(("%s: row=%d, vertical? %d\n", __FUNCTION__, 712 i, mono->is_vertical)); 713 if (mono->is_vertical) { 714 struct mono_edge *e = mono->head.next; 715 int min_height = h - i; 716 717 while (e != &mono->tail) { 718 if (e->height_left < min_height) 719 min_height = e->height_left; 720 e = e->next; 721 } 722 723 while (--min_height >= 1 && polygon->y_buckets[j] == NULL) 724 j++; 725 if (j != i + 1) 726 mono_step_edges(mono, j - (i + 1)); 727 __DBG(("%s: %d vertical rows\n", __FUNCTION__, j-i)); 728 } 729 730 mono_row(mono, i, j-i); 731 732 /* XXX recompute after dropping edges? */ 733 if (mono->head.next == &mono->tail) 734 mono->is_vertical = 1; 735 } 736} 737 738static int operator_is_bounded(uint8_t op) 739{ 740 switch (op) { 741 case PictOpOver: 742 case PictOpOutReverse: 743 case PictOpAdd: 744 return true; 745 default: 746 return false; 747 } 748} 749 750struct mono_span_thread { 751 struct sna *sna; 752 const xTrapezoid *traps; 753 const struct sna_composite_op *op; 754 RegionPtr clip; 755 int ntrap; 756 BoxRec extents; 757 int dx, dy; 758}; 759 760static void 761mono_span_thread(void *arg) 762{ 763 struct mono_span_thread *thread = arg; 764 struct mono mono; 765 struct mono_span_thread_boxes boxes; 766 const xTrapezoid *t; 767 int n; 768 769 mono.sna = thread->sna; 770 771 mono.clip.extents = thread->extents; 772 mono.clip.data = NULL; 773 if (thread->clip->data) { 774 RegionIntersect(&mono.clip, &mono.clip, thread->clip); 775 if (RegionNil(&mono.clip)) 776 return; 777 } 778 region_get_boxes(&mono.clip, &mono.clip_start, &mono.clip_end); 779 780 boxes.op = thread->op; 781 boxes.num_boxes = 0; 782 mono.op.priv = &boxes; 783 784 if (!mono_init(&mono, 2*thread->ntrap)) { 785 RegionUninit(&mono.clip); 786 return; 787 } 788 789 for (n = thread->ntrap, t = thread->traps; n--; t++) { 790 if (!xTrapezoidValid(t)) 791 continue; 792 793 if (pixman_fixed_to_int(t->top) + thread->dy >= thread->extents.y2 || 794 pixman_fixed_to_int(t->bottom) + thread->dy <= thread->extents.y1) 795 continue; 796 797 mono_add_line(&mono, thread->dx, thread->dy, 798 t->top, t->bottom, 799 &t->left.p1, &t->left.p2, 1); 800 mono_add_line(&mono, thread->dx, thread->dy, 801 t->top, t->bottom, 802 &t->right.p1, &t->right.p2, -1); 803 } 804 805 if (mono.clip.data == NULL) 806 mono.span = thread_mono_span; 807 else 808 mono.span = thread_mono_span_clipped; 809 810 mono_render(&mono); 811 mono_fini(&mono); 812 813 if (boxes.num_boxes) 814 thread->op->thread_boxes(thread->sna, thread->op, 815 boxes.boxes, boxes.num_boxes); 816 RegionUninit(&mono.clip); 817} 818 819bool 820mono_trapezoids_span_converter(struct sna *sna, 821 CARD8 op, PicturePtr src, PicturePtr dst, 822 INT16 src_x, INT16 src_y, 823 int ntrap, xTrapezoid *traps) 824{ 825 struct mono mono; 826 BoxRec extents; 827 int16_t dst_x, dst_y; 828 int16_t dx, dy; 829 bool unbounded; 830 int num_threads, n; 831 832 if (NO_SCAN_CONVERTER) 833 return false; 834 835 trapezoid_origin(&traps[0].left, &dst_x, &dst_y); 836 837 if (!trapezoids_bounds(ntrap, traps, &extents)) 838 return true; 839 840 DBG(("%s: extents (%d, %d), (%d, %d)\n", 841 __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 842 843 if (!sna_compute_composite_region(&mono.clip, 844 src, NULL, dst, 845 src_x + extents.x1 - dst_x, 846 src_y + extents.y1 - dst_y, 847 0, 0, 848 extents.x1, extents.y1, 849 extents.x2 - extents.x1, 850 extents.y2 - extents.y1)) { 851 DBG(("%s: trapezoids do not intersect drawable clips\n", 852 __FUNCTION__)) ; 853 return true; 854 } 855 856 dx = dst->pDrawable->x; 857 dy = dst->pDrawable->y; 858 859 DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n", 860 __FUNCTION__, 861 mono.clip.extents.x1, mono.clip.extents.y1, 862 mono.clip.extents.x2, mono.clip.extents.y2, 863 dx, dy, 864 src_x + mono.clip.extents.x1 - dst_x - dx, 865 src_y + mono.clip.extents.y1 - dst_y - dy)); 866 867 unbounded = (!sna_drawable_is_clear(dst->pDrawable) && 868 !operator_is_bounded(op)); 869 870 if (op == PictOpClear && sna->clear) 871 src = sna->clear; 872 873 mono.sna = sna; 874 if (!mono.sna->render.composite(mono.sna, op, src, NULL, dst, 875 src_x + mono.clip.extents.x1 - dst_x - dx, 876 src_y + mono.clip.extents.y1 - dst_y - dy, 877 0, 0, 878 mono.clip.extents.x1, mono.clip.extents.y1, 879 mono.clip.extents.x2 - mono.clip.extents.x1, 880 mono.clip.extents.y2 - mono.clip.extents.y1, 881 COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) 882 return false; 883 884 num_threads = 1; 885 if (!NO_GPU_THREADS && 886 mono.op.thread_boxes && 887 mono.op.damage == NULL && 888 !unbounded) 889 num_threads = sna_use_threads(mono.clip.extents.x2 - mono.clip.extents.x1, 890 mono.clip.extents.y2 - mono.clip.extents.y1, 891 32); 892 if (num_threads > 1) { 893 struct mono_span_thread threads[num_threads]; 894 int y, h; 895 896 DBG(("%s: using %d threads for mono span compositing %dx%d\n", 897 __FUNCTION__, num_threads, 898 mono.clip.extents.x2 - mono.clip.extents.x1, 899 mono.clip.extents.y2 - mono.clip.extents.y1)); 900 901 threads[0].sna = mono.sna; 902 threads[0].op = &mono.op; 903 threads[0].traps = traps; 904 threads[0].ntrap = ntrap; 905 threads[0].extents = mono.clip.extents; 906 threads[0].clip = &mono.clip; 907 threads[0].dx = dx; 908 threads[0].dy = dy; 909 910 y = extents.y1; 911 h = extents.y2 - extents.y1; 912 h = (h + num_threads - 1) / num_threads; 913 num_threads -= (num_threads-1) * h >= extents.y2 - extents.y1; 914 915 for (n = 1; n < num_threads; n++) { 916 threads[n] = threads[0]; 917 threads[n].extents.y1 = y; 918 threads[n].extents.y2 = y += h; 919 920 sna_threads_run(n, mono_span_thread, &threads[n]); 921 } 922 923 threads[0].extents.y1 = y; 924 threads[0].extents.y2 = extents.y2; 925 mono_span_thread(&threads[0]); 926 927 sna_threads_wait(); 928 mono.op.done(mono.sna, &mono.op); 929 return true; 930 } 931 932 if (!mono_init(&mono, 2*ntrap)) 933 return false; 934 935 for (n = 0; n < ntrap; n++) { 936 if (!xTrapezoidValid(&traps[n])) 937 continue; 938 939 if (pixman_fixed_integer_floor(traps[n].top) + dy >= mono.clip.extents.y2 || 940 pixman_fixed_integer_ceil(traps[n].bottom) + dy <= mono.clip.extents.y1) 941 continue; 942 943 mono_add_line(&mono, dx, dy, 944 traps[n].top, traps[n].bottom, 945 &traps[n].left.p1, &traps[n].left.p2, 1); 946 mono_add_line(&mono, dx, dy, 947 traps[n].top, traps[n].bottom, 948 &traps[n].right.p1, &traps[n].right.p2, -1); 949 } 950 951 if (mono.clip.data == NULL && mono.op.damage == NULL) 952 mono.span = mono_span__fast; 953 else if (mono.clip.data != NULL && mono.op.damage == NULL) 954 mono.span = mono_span__clipped; 955 else 956 mono.span = mono_span; 957 958 region_get_boxes(&mono.clip, &mono.clip_start, &mono.clip_end); 959 mono_render(&mono); 960 mono.op.done(mono.sna, &mono.op); 961 mono_fini(&mono); 962 963 if (unbounded) { 964 xPointFixed p1, p2; 965 966 if (!mono_init(&mono, 2+2*ntrap)) 967 return false; 968 969 p1.y = mono.clip.extents.y1 * pixman_fixed_1; 970 p2.y = mono.clip.extents.y2 * pixman_fixed_1; 971 972 p1.x = mono.clip.extents.x1 * pixman_fixed_1; 973 p2.x = mono.clip.extents.x1 * pixman_fixed_1; 974 mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, -1); 975 976 p1.x = mono.clip.extents.x2 * pixman_fixed_1; 977 p2.x = mono.clip.extents.x2 * pixman_fixed_1; 978 mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, 1); 979 980 for (n = 0; n < ntrap; n++) { 981 if (!xTrapezoidValid(&traps[n])) 982 continue; 983 984 if (pixman_fixed_to_int(traps[n].top) + dy >= mono.clip.extents.y2 || 985 pixman_fixed_to_int(traps[n].bottom) + dy < mono.clip.extents.y1) 986 continue; 987 988 mono_add_line(&mono, dx, dy, 989 traps[n].top, traps[n].bottom, 990 &traps[n].left.p1, &traps[n].left.p2, 1); 991 mono_add_line(&mono, dx, dy, 992 traps[n].top, traps[n].bottom, 993 &traps[n].right.p1, &traps[n].right.p2, -1); 994 } 995 if (mono.sna->render.composite(mono.sna, 996 PictOpClear, 997 mono.sna->clear, NULL, dst, 998 0, 0, 999 0, 0, 1000 mono.clip.extents.x1, mono.clip.extents.y1, 1001 mono.clip.extents.x2 - mono.clip.extents.x1, 1002 mono.clip.extents.y2 - mono.clip.extents.y1, 1003 COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) { 1004 region_get_boxes(&mono.clip, &mono.clip_start, &mono.clip_end); 1005 mono_render(&mono); 1006 mono.op.done(mono.sna, &mono.op); 1007 } 1008 mono_fini(&mono); 1009 } 1010 1011 REGION_UNINIT(NULL, &mono.clip); 1012 return true; 1013} 1014 1015struct mono_inplace_composite { 1016 pixman_image_t *src, *dst; 1017 int dx, dy; 1018 int sx, sy; 1019 int op; 1020}; 1021struct mono_inplace_fill { 1022 uint32_t *data, stride; 1023 uint32_t color; 1024 int bpp; 1025}; 1026 1027fastcall static void 1028mono_inplace_fill_box(struct sna *sna, 1029 const struct sna_composite_op *op, 1030 const BoxRec *box) 1031{ 1032 struct mono_inplace_fill *fill = op->priv; 1033 1034 DBG(("(%s: (%d, %d)x(%d, %d):%08x\n", 1035 __FUNCTION__, 1036 box->x1, box->y1, 1037 box->x2 - box->x1, 1038 box->y2 - box->y1, 1039 fill->color)); 1040 sigtrap_assert_active(); 1041 pixman_fill(fill->data, fill->stride, fill->bpp, 1042 box->x1, box->y1, 1043 box->x2 - box->x1, 1044 box->y2 - box->y1, 1045 fill->color); 1046} 1047 1048static void 1049mono_inplace_fill_boxes(struct sna *sna, 1050 const struct sna_composite_op *op, 1051 const BoxRec *box, int nbox) 1052{ 1053 struct mono_inplace_fill *fill = op->priv; 1054 1055 do { 1056 DBG(("(%s: (%d, %d)x(%d, %d):%08x\n", 1057 __FUNCTION__, 1058 box->x1, box->y1, 1059 box->x2 - box->x1, 1060 box->y2 - box->y1, 1061 fill->color)); 1062 sigtrap_assert_active(); 1063 pixman_fill(fill->data, fill->stride, fill->bpp, 1064 box->x1, box->y1, 1065 box->x2 - box->x1, 1066 box->y2 - box->y1, 1067 fill->color); 1068 box++; 1069 } while (--nbox); 1070} 1071 1072fastcall static void 1073mono_inplace_composite_box(struct sna *sna, 1074 const struct sna_composite_op *op, 1075 const BoxRec *box) 1076{ 1077 struct mono_inplace_composite *c = op->priv; 1078 1079 pixman_image_composite(c->op, c->src, NULL, c->dst, 1080 box->x1 + c->sx, box->y1 + c->sy, 1081 0, 0, 1082 box->x1 + c->dx, box->y1 + c->dy, 1083 box->x2 - box->x1, 1084 box->y2 - box->y1); 1085} 1086 1087static void 1088mono_inplace_composite_boxes(struct sna *sna, 1089 const struct sna_composite_op *op, 1090 const BoxRec *box, int nbox) 1091{ 1092 struct mono_inplace_composite *c = op->priv; 1093 1094 do { 1095 pixman_image_composite(c->op, c->src, NULL, c->dst, 1096 box->x1 + c->sx, box->y1 + c->sy, 1097 0, 0, 1098 box->x1 + c->dx, box->y1 + c->dy, 1099 box->x2 - box->x1, 1100 box->y2 - box->y1); 1101 box++; 1102 } while (--nbox); 1103} 1104 1105bool 1106mono_trapezoid_span_inplace(struct sna *sna, 1107 CARD8 op, 1108 PicturePtr src, 1109 PicturePtr dst, 1110 INT16 src_x, INT16 src_y, 1111 int ntrap, xTrapezoid *traps) 1112{ 1113 struct mono mono; 1114 union { 1115 struct mono_inplace_fill fill; 1116 struct mono_inplace_composite composite; 1117 } inplace; 1118 int was_clear; 1119 int x, y, n; 1120 1121 if (!trapezoids_bounds(ntrap, traps, &mono.clip.extents)) 1122 return true; 1123 1124 DBG(("%s: extents (%d, %d), (%d, %d)\n", 1125 __FUNCTION__, 1126 mono.clip.extents.x1, mono.clip.extents.y1, 1127 mono.clip.extents.x2, mono.clip.extents.y2)); 1128 1129 if (!sna_compute_composite_region(&mono.clip, 1130 src, NULL, dst, 1131 src_x, src_y, 1132 0, 0, 1133 mono.clip.extents.x1, mono.clip.extents.y1, 1134 mono.clip.extents.x2 - mono.clip.extents.x1, 1135 mono.clip.extents.y2 - mono.clip.extents.y1)) { 1136 DBG(("%s: trapezoids do not intersect drawable clips\n", 1137 __FUNCTION__)) ; 1138 return true; 1139 } 1140 1141 DBG(("%s: clipped extents (%d, %d), (%d, %d)\n", 1142 __FUNCTION__, 1143 mono.clip.extents.x1, mono.clip.extents.y1, 1144 mono.clip.extents.x2, mono.clip.extents.y2)); 1145 1146 was_clear = sna_drawable_is_clear(dst->pDrawable); 1147 if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &mono.clip, 1148 MOVE_WRITE | MOVE_READ)) 1149 return true; 1150 1151 mono.sna = sna; 1152 if (!mono_init(&mono, 2*ntrap)) 1153 return false; 1154 1155 mono.op.damage = NULL; 1156 1157 x = dst->pDrawable->x; 1158 y = dst->pDrawable->y; 1159 1160 for (n = 0; n < ntrap; n++) { 1161 if (!xTrapezoidValid(&traps[n])) 1162 continue; 1163 1164 if (pixman_fixed_to_int(traps[n].top) + y >= mono.clip.extents.y2 || 1165 pixman_fixed_to_int(traps[n].bottom) + y < mono.clip.extents.y1) 1166 continue; 1167 1168 mono_add_line(&mono, x, y, 1169 traps[n].top, traps[n].bottom, 1170 &traps[n].left.p1, &traps[n].left.p2, 1); 1171 mono_add_line(&mono, x, y, 1172 traps[n].top, traps[n].bottom, 1173 &traps[n].right.p1, &traps[n].right.p2, -1); 1174 } 1175 1176 if (sna_picture_is_solid(src, &inplace.fill.color) && 1177 (op == PictOpSrc || op == PictOpClear || 1178 (was_clear && (op == PictOpOver || op == PictOpAdd)) || 1179 (op == PictOpOver && inplace.fill.color >> 24 == 0xff))) { 1180 PixmapPtr pixmap; 1181 int16_t dx, dy; 1182 uint8_t *ptr; 1183 1184unbounded_pass: 1185 pixmap = get_drawable_pixmap(dst->pDrawable); 1186 1187 ptr = pixmap->devPrivate.ptr; 1188 if (get_drawable_deltas(dst->pDrawable, pixmap, &dx, &dy)) 1189 ptr += dy * pixmap->devKind + dx * pixmap->drawable.bitsPerPixel / 8; 1190 inplace.fill.data = (uint32_t *)ptr; 1191 inplace.fill.stride = pixmap->devKind / sizeof(uint32_t); 1192 inplace.fill.bpp = pixmap->drawable.bitsPerPixel; 1193 1194 if (op == PictOpClear) 1195 inplace.fill.color = 0; 1196 else if (dst->format != PICT_a8r8g8b8) 1197 inplace.fill.color = sna_rgba_to_color(inplace.fill.color, dst->format); 1198 1199 DBG(("%s: fill %x\n", __FUNCTION__, inplace.fill.color)); 1200 1201 mono.op.priv = &inplace.fill; 1202 mono.op.box = mono_inplace_fill_box; 1203 mono.op.boxes = mono_inplace_fill_boxes; 1204 1205 op = 0; 1206 } else { 1207 if (src->pDrawable) { 1208 if (!sna_drawable_move_to_cpu(src->pDrawable, 1209 MOVE_READ)) { 1210 mono_fini(&mono); 1211 return false; 1212 } 1213 if (src->alphaMap && 1214 !sna_drawable_move_to_cpu(src->alphaMap->pDrawable, 1215 MOVE_READ)) { 1216 mono_fini(&mono); 1217 return false; 1218 } 1219 } 1220 1221 inplace.composite.dst = image_from_pict(dst, false, 1222 &inplace.composite.dx, 1223 &inplace.composite.dy); 1224 inplace.composite.src = image_from_pict(src, false, 1225 &inplace.composite.sx, 1226 &inplace.composite.sy); 1227 inplace.composite.sx += 1228 src_x - pixman_fixed_to_int(traps[0].left.p1.x), 1229 inplace.composite.sy += 1230 src_y - pixman_fixed_to_int(traps[0].left.p1.y), 1231 inplace.composite.op = op; 1232 1233 mono.op.priv = &inplace.composite; 1234 mono.op.box = mono_inplace_composite_box; 1235 mono.op.boxes = mono_inplace_composite_boxes; 1236 } 1237 1238 if (mono.clip.data == NULL && mono.op.damage == NULL) 1239 mono.span = mono_span__fast; 1240 else 1241 mono.span = mono_span; 1242 if (sigtrap_get() == 0) { 1243 mono_render(&mono); 1244 sigtrap_put(); 1245 } 1246 mono_fini(&mono); 1247 1248 if (op) { 1249 free_pixman_pict(src, inplace.composite.src); 1250 free_pixman_pict(dst, inplace.composite.dst); 1251 1252 if (!was_clear && !operator_is_bounded(op)) { 1253 xPointFixed p1, p2; 1254 1255 DBG(("%s: unbounded fixup\n", __FUNCTION__)); 1256 1257 if (!mono_init(&mono, 2+2*ntrap)) 1258 return false; 1259 1260 p1.y = mono.clip.extents.y1 * pixman_fixed_1; 1261 p2.y = mono.clip.extents.y2 * pixman_fixed_1; 1262 1263 p1.x = mono.clip.extents.x1 * pixman_fixed_1; 1264 p2.x = mono.clip.extents.x1 * pixman_fixed_1; 1265 mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, -1); 1266 1267 p1.x = mono.clip.extents.x2 * pixman_fixed_1; 1268 p2.x = mono.clip.extents.x2 * pixman_fixed_1; 1269 mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, 1); 1270 1271 for (n = 0; n < ntrap; n++) { 1272 if (!xTrapezoidValid(&traps[n])) 1273 continue; 1274 1275 if (pixman_fixed_to_int(traps[n].top) + x >= mono.clip.extents.y2 || 1276 pixman_fixed_to_int(traps[n].bottom) + y < mono.clip.extents.y1) 1277 continue; 1278 1279 mono_add_line(&mono, x, y, 1280 traps[n].top, traps[n].bottom, 1281 &traps[n].left.p1, &traps[n].left.p2, 1); 1282 mono_add_line(&mono, x, y, 1283 traps[n].top, traps[n].bottom, 1284 &traps[n].right.p1, &traps[n].right.p2, -1); 1285 } 1286 1287 op = PictOpClear; 1288 goto unbounded_pass; 1289 } 1290 } 1291 1292 return true; 1293} 1294 1295bool 1296mono_trap_span_converter(struct sna *sna, 1297 PicturePtr dst, 1298 INT16 x, INT16 y, 1299 int ntrap, xTrap *traps) 1300{ 1301 struct mono mono; 1302 xRenderColor white; 1303 PicturePtr src; 1304 int error; 1305 int n; 1306 1307 white.red = white.green = white.blue = white.alpha = 0xffff; 1308 src = CreateSolidPicture(0, &white, &error); 1309 if (src == NULL) 1310 return true; 1311 1312 mono.clip = *dst->pCompositeClip; 1313 x += dst->pDrawable->x; 1314 y += dst->pDrawable->y; 1315 1316 DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d)\n", 1317 __FUNCTION__, 1318 mono.clip.extents.x1, mono.clip.extents.y1, 1319 mono.clip.extents.x2, mono.clip.extents.y2, 1320 x, y)); 1321 1322 mono.sna = sna; 1323 if (!mono_init(&mono, 2*ntrap)) 1324 return false; 1325 1326 for (n = 0; n < ntrap; n++) { 1327 xPointFixed p1, p2; 1328 1329 if (pixman_fixed_to_int(traps[n].top.y) + y >= mono.clip.extents.y2 || 1330 pixman_fixed_to_int(traps[n].bot.y) + y < mono.clip.extents.y1) 1331 continue; 1332 1333 p1.y = traps[n].top.y; 1334 p2.y = traps[n].bot.y; 1335 1336 p1.x = traps[n].top.l; 1337 p2.x = traps[n].bot.l; 1338 mono_add_line(&mono, x, y, 1339 traps[n].top.y, traps[n].bot.y, 1340 &p1, &p2, 1); 1341 1342 p1.x = traps[n].top.r; 1343 p2.x = traps[n].bot.r; 1344 mono_add_line(&mono, x, y, 1345 traps[n].top.y, traps[n].bot.y, 1346 &p1, &p2, -1); 1347 } 1348 1349 if (mono.sna->render.composite(mono.sna, PictOpAdd, src, NULL, dst, 1350 0, 0, 1351 0, 0, 1352 mono.clip.extents.x1, mono.clip.extents.y1, 1353 mono.clip.extents.x2 - mono.clip.extents.x1, 1354 mono.clip.extents.y2 - mono.clip.extents.y1, 1355 COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) { 1356 if (mono.clip.data == NULL && mono.op.damage == NULL) 1357 mono.span = mono_span__fast; 1358 else 1359 mono.span = mono_span; 1360 mono_render(&mono); 1361 mono.op.done(mono.sna, &mono.op); 1362 } 1363 1364 mono_fini(&mono); 1365 FreePicture(src, 0); 1366 return true; 1367} 1368 1369bool 1370mono_triangles_span_converter(struct sna *sna, 1371 CARD8 op, PicturePtr src, PicturePtr dst, 1372 INT16 src_x, INT16 src_y, 1373 int count, xTriangle *tri) 1374{ 1375 struct mono mono; 1376 BoxRec extents; 1377 int16_t dst_x, dst_y; 1378 int16_t dx, dy; 1379 bool was_clear; 1380 int n; 1381 1382 mono.sna = sna; 1383 1384 dst_x = pixman_fixed_to_int(tri[0].p1.x); 1385 dst_y = pixman_fixed_to_int(tri[0].p1.y); 1386 1387 miTriangleBounds(count, tri, &extents); 1388 DBG(("%s: extents (%d, %d), (%d, %d)\n", 1389 __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 1390 1391 if (extents.y1 >= extents.y2 || extents.x1 >= extents.x2) 1392 return true; 1393 1394 if (!sna_compute_composite_region(&mono.clip, 1395 src, NULL, dst, 1396 src_x + extents.x1 - dst_x, 1397 src_y + extents.y1 - dst_y, 1398 0, 0, 1399 extents.x1, extents.y1, 1400 extents.x2 - extents.x1, 1401 extents.y2 - extents.y1)) { 1402 DBG(("%s: triangles do not intersect drawable clips\n", 1403 __FUNCTION__)) ; 1404 return true; 1405 } 1406 1407 dx = dst->pDrawable->x; 1408 dy = dst->pDrawable->y; 1409 1410 DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n", 1411 __FUNCTION__, 1412 mono.clip.extents.x1, mono.clip.extents.y1, 1413 mono.clip.extents.x2, mono.clip.extents.y2, 1414 dx, dy, 1415 src_x + mono.clip.extents.x1 - dst_x - dx, 1416 src_y + mono.clip.extents.y1 - dst_y - dy)); 1417 1418 was_clear = sna_drawable_is_clear(dst->pDrawable); 1419 1420 if (!mono_init(&mono, 3*count)) 1421 return false; 1422 1423 for (n = 0; n < count; n++) { 1424 mono_add_line(&mono, dx, dy, 1425 tri[n].p1.y, tri[n].p2.y, 1426 &tri[n].p1, &tri[n].p2, 1); 1427 mono_add_line(&mono, dx, dy, 1428 tri[n].p2.y, tri[n].p3.y, 1429 &tri[n].p2, &tri[n].p3, 1); 1430 mono_add_line(&mono, dx, dy, 1431 tri[n].p3.y, tri[n].p1.y, 1432 &tri[n].p3, &tri[n].p1, 1); 1433 } 1434 1435 if (mono.sna->render.composite(mono.sna, op, src, NULL, dst, 1436 src_x + mono.clip.extents.x1 - dst_x - dx, 1437 src_y + mono.clip.extents.y1 - dst_y - dy, 1438 0, 0, 1439 mono.clip.extents.x1, mono.clip.extents.y1, 1440 mono.clip.extents.x2 - mono.clip.extents.x1, 1441 mono.clip.extents.y2 - mono.clip.extents.y1, 1442 COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) { 1443 if (mono.clip.data == NULL && mono.op.damage == NULL) 1444 mono.span = mono_span__fast; 1445 else 1446 mono.span = mono_span; 1447 mono_render(&mono); 1448 mono.op.done(mono.sna, &mono.op); 1449 } 1450 mono_fini(&mono); 1451 1452 if (!was_clear && !operator_is_bounded(op)) { 1453 xPointFixed p1, p2; 1454 1455 DBG(("%s: performing unbounded clear\n", __FUNCTION__)); 1456 1457 if (!mono_init(&mono, 2+3*count)) 1458 return false; 1459 1460 p1.y = mono.clip.extents.y1 * pixman_fixed_1; 1461 p2.y = mono.clip.extents.y2 * pixman_fixed_1; 1462 1463 p1.x = mono.clip.extents.x1 * pixman_fixed_1; 1464 p2.x = mono.clip.extents.x1 * pixman_fixed_1; 1465 mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, -1); 1466 1467 p1.x = mono.clip.extents.x2 * pixman_fixed_1; 1468 p2.x = mono.clip.extents.x2 * pixman_fixed_1; 1469 mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, 1); 1470 1471 for (n = 0; n < count; n++) { 1472 mono_add_line(&mono, dx, dy, 1473 tri[n].p1.y, tri[n].p2.y, 1474 &tri[n].p1, &tri[n].p2, 1); 1475 mono_add_line(&mono, dx, dy, 1476 tri[n].p2.y, tri[n].p3.y, 1477 &tri[n].p2, &tri[n].p3, 1); 1478 mono_add_line(&mono, dx, dy, 1479 tri[n].p3.y, tri[n].p1.y, 1480 &tri[n].p3, &tri[n].p1, 1); 1481 } 1482 1483 if (mono.sna->render.composite(mono.sna, 1484 PictOpClear, 1485 mono.sna->clear, NULL, dst, 1486 0, 0, 1487 0, 0, 1488 mono.clip.extents.x1, mono.clip.extents.y1, 1489 mono.clip.extents.x2 - mono.clip.extents.x1, 1490 mono.clip.extents.y2 - mono.clip.extents.y1, 1491 COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) { 1492 if (mono.clip.data == NULL && mono.op.damage == NULL) 1493 mono.span = mono_span__fast; 1494 else 1495 mono.span = mono_span; 1496 mono_render(&mono); 1497 mono.op.done(mono.sna, &mono.op); 1498 } 1499 mono_fini(&mono); 1500 } 1501 1502 REGION_UNINIT(NULL, &mono.clip); 1503 return true; 1504} 1505 1506bool 1507mono_tristrip_span_converter(struct sna *sna, 1508 CARD8 op, PicturePtr src, PicturePtr dst, 1509 INT16 src_x, INT16 src_y, 1510 int count, xPointFixed *points) 1511{ 1512 struct mono mono; 1513 BoxRec extents; 1514 int16_t dst_x, dst_y; 1515 int16_t dx, dy; 1516 bool was_clear; 1517 int n; 1518 1519 mono.sna = sna; 1520 1521 dst_x = pixman_fixed_to_int(points[0].x); 1522 dst_y = pixman_fixed_to_int(points[0].y); 1523 1524 miPointFixedBounds(count, points, &extents); 1525 DBG(("%s: extents (%d, %d), (%d, %d)\n", 1526 __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 1527 1528 if (extents.y1 >= extents.y2 || extents.x1 >= extents.x2) 1529 return true; 1530 1531 if (!sna_compute_composite_region(&mono.clip, 1532 src, NULL, dst, 1533 src_x + extents.x1 - dst_x, 1534 src_y + extents.y1 - dst_y, 1535 0, 0, 1536 extents.x1, extents.y1, 1537 extents.x2 - extents.x1, 1538 extents.y2 - extents.y1)) { 1539 DBG(("%s: triangles do not intersect drawable clips\n", 1540 __FUNCTION__)) ; 1541 return true; 1542 } 1543 1544 dx = dst->pDrawable->x; 1545 dy = dst->pDrawable->y; 1546 1547 DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n", 1548 __FUNCTION__, 1549 mono.clip.extents.x1, mono.clip.extents.y1, 1550 mono.clip.extents.x2, mono.clip.extents.y2, 1551 dx, dy, 1552 src_x + mono.clip.extents.x1 - dst_x - dx, 1553 src_y + mono.clip.extents.y1 - dst_y - dy)); 1554 1555 was_clear = sna_drawable_is_clear(dst->pDrawable); 1556 1557 if (!mono_init(&mono, 2*count)) 1558 return false; 1559 1560 mono_add_line(&mono, dx, dy, 1561 points[0].y, points[1].y, 1562 &points[0], &points[1], -1); 1563 n = 2; 1564 do { 1565 mono_add_line(&mono, dx, dy, 1566 points[n-2].y, points[n].y, 1567 &points[n-2], &points[n], 1); 1568 if (++n == count) 1569 break; 1570 1571 mono_add_line(&mono, dx, dy, 1572 points[n-2].y, points[n].y, 1573 &points[n-2], &points[n], -1); 1574 if (++n == count) 1575 break; 1576 } while (1); 1577 mono_add_line(&mono, dx, dy, 1578 points[n-2].y, points[n-1].y, 1579 &points[n-2], &points[n-1], 1); 1580 1581 if (mono.sna->render.composite(mono.sna, op, src, NULL, dst, 1582 src_x + mono.clip.extents.x1 - dst_x - dx, 1583 src_y + mono.clip.extents.y1 - dst_y - dy, 1584 0, 0, 1585 mono.clip.extents.x1, mono.clip.extents.y1, 1586 mono.clip.extents.x2 - mono.clip.extents.x1, 1587 mono.clip.extents.y2 - mono.clip.extents.y1, 1588 COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) { 1589 if (mono.clip.data == NULL && mono.op.damage == NULL) 1590 mono.span = mono_span__fast; 1591 else 1592 mono.span = mono_span; 1593 mono_render(&mono); 1594 mono.op.done(mono.sna, &mono.op); 1595 } 1596 1597 if (!was_clear && !operator_is_bounded(op)) { 1598 xPointFixed p1, p2; 1599 1600 if (!mono_init(&mono, 2+2*count)) 1601 return false; 1602 1603 p1.y = mono.clip.extents.y1 * pixman_fixed_1; 1604 p2.y = mono.clip.extents.y2 * pixman_fixed_1; 1605 1606 p1.x = mono.clip.extents.x1 * pixman_fixed_1; 1607 p2.x = mono.clip.extents.x1 * pixman_fixed_1; 1608 mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, -1); 1609 1610 p1.x = mono.clip.extents.x2 * pixman_fixed_1; 1611 p2.x = mono.clip.extents.x2 * pixman_fixed_1; 1612 mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, 1); 1613 1614 mono_add_line(&mono, dx, dy, 1615 points[0].y, points[1].y, 1616 &points[0], &points[1], -1); 1617 n = 2; 1618 do { 1619 mono_add_line(&mono, dx, dy, 1620 points[n-2].y, points[n].y, 1621 &points[n-2], &points[n], 1); 1622 if (++n == count) 1623 break; 1624 1625 mono_add_line(&mono, dx, dy, 1626 points[n-2].y, points[n].y, 1627 &points[n-2], &points[n], -1); 1628 if (++n == count) 1629 break; 1630 } while (1); 1631 mono_add_line(&mono, dx, dy, 1632 points[n-2].y, points[n-1].y, 1633 &points[n-2], &points[n-1], 1); 1634 1635 if (mono.sna->render.composite(mono.sna, 1636 PictOpClear, 1637 mono.sna->clear, NULL, dst, 1638 0, 0, 1639 0, 0, 1640 mono.clip.extents.x1, mono.clip.extents.y1, 1641 mono.clip.extents.x2 - mono.clip.extents.x1, 1642 mono.clip.extents.y2 - mono.clip.extents.y1, 1643 COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) { 1644 if (mono.clip.data == NULL && mono.op.damage == NULL) 1645 mono.span = mono_span__fast; 1646 else 1647 mono.span = mono_span; 1648 mono_render(&mono); 1649 mono.op.done(mono.sna, &mono.op); 1650 } 1651 mono_fini(&mono); 1652 } 1653 1654 mono_fini(&mono); 1655 REGION_UNINIT(NULL, &mono.clip); 1656 return true; 1657} 1658