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