1428d7b3dSmrg/* 2428d7b3dSmrg * Copyright (c) 2007 David Turner 3428d7b3dSmrg * Copyright (c) 2008 M Joonas Pihlaja 4428d7b3dSmrg * Copyright (c) 2011 Intel Corporation 5428d7b3dSmrg * 6428d7b3dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 7428d7b3dSmrg * copy of this software and associated documentation files (the "Software"), 8428d7b3dSmrg * to deal in the Software without restriction, including without limitation 9428d7b3dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10428d7b3dSmrg * and/or sell copies of the Software, and to permit persons to whom the 11428d7b3dSmrg * Software is furnished to do so, subject to the following conditions: 12428d7b3dSmrg * 13428d7b3dSmrg * The above copyright notice and this permission notice (including the next 14428d7b3dSmrg * paragraph) shall be included in all copies or substantial portions of the 15428d7b3dSmrg * Software. 16428d7b3dSmrg * 17428d7b3dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18428d7b3dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19428d7b3dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20428d7b3dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21428d7b3dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22428d7b3dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23428d7b3dSmrg * SOFTWARE. 24428d7b3dSmrg * 25428d7b3dSmrg * Authors: 26428d7b3dSmrg * Chris Wilson <chris@chris-wilson.co.uk> 27428d7b3dSmrg * 28428d7b3dSmrg */ 29428d7b3dSmrg 30428d7b3dSmrg#ifdef HAVE_CONFIG_H 31428d7b3dSmrg#include "config.h" 32428d7b3dSmrg#endif 33428d7b3dSmrg 34428d7b3dSmrg#include "sna.h" 35428d7b3dSmrg#include "sna_render.h" 36428d7b3dSmrg#include "sna_render_inline.h" 37428d7b3dSmrg#include "sna_trapezoids.h" 38428d7b3dSmrg#include "fb/fbpict.h" 39428d7b3dSmrg 40428d7b3dSmrg#include <mipict.h> 41428d7b3dSmrg 42428d7b3dSmrgstruct quorem { 43428d7b3dSmrg int32_t quo; 44428d7b3dSmrg int64_t rem; 45428d7b3dSmrg}; 46428d7b3dSmrg 47428d7b3dSmrgstruct mono_edge { 48428d7b3dSmrg struct mono_edge *next, *prev; 49428d7b3dSmrg 50428d7b3dSmrg int32_t height_left; 51428d7b3dSmrg int32_t dir; 52428d7b3dSmrg 53428d7b3dSmrg int64_t dy; 54428d7b3dSmrg struct quorem x; 55428d7b3dSmrg struct quorem dxdy; 56428d7b3dSmrg}; 57428d7b3dSmrg 58428d7b3dSmrgstruct mono_polygon { 59428d7b3dSmrg int num_edges; 60428d7b3dSmrg struct mono_edge *edges; 61428d7b3dSmrg struct mono_edge **y_buckets; 62428d7b3dSmrg 63428d7b3dSmrg struct mono_edge *y_buckets_embedded[64]; 64428d7b3dSmrg struct mono_edge edges_embedded[32]; 65428d7b3dSmrg}; 66428d7b3dSmrg 67428d7b3dSmrgstruct mono { 68428d7b3dSmrg /* Leftmost edge on the current scan line. */ 69428d7b3dSmrg struct mono_edge head, tail; 70428d7b3dSmrg int is_vertical; 71428d7b3dSmrg 72428d7b3dSmrg struct sna *sna; 73428d7b3dSmrg struct sna_composite_op op; 74428d7b3dSmrg pixman_region16_t clip; 75428d7b3dSmrg 76428d7b3dSmrg fastcall void (*span)(struct mono *, int, int, BoxPtr); 77428d7b3dSmrg 78428d7b3dSmrg struct mono_polygon polygon; 79428d7b3dSmrg}; 80428d7b3dSmrg 81428d7b3dSmrg#define I(x) pixman_fixed_to_int ((x) + pixman_fixed_1_minus_e/2) 82428d7b3dSmrg 83428d7b3dSmrgstatic struct quorem 84428d7b3dSmrgfloored_muldivrem(int32_t x, int32_t a, int32_t b) 85428d7b3dSmrg{ 86428d7b3dSmrg struct quorem qr; 87428d7b3dSmrg int64_t xa = (int64_t)x*a; 88428d7b3dSmrg qr.quo = xa/b; 89428d7b3dSmrg qr.rem = xa%b; 90428d7b3dSmrg if (qr.rem < 0) { 91428d7b3dSmrg qr.quo -= 1; 92428d7b3dSmrg qr.rem += b; 93428d7b3dSmrg } 94428d7b3dSmrg return qr; 95428d7b3dSmrg} 96428d7b3dSmrg 97428d7b3dSmrg#if HAS_DEBUG_FULL 98428d7b3dSmrgstatic void _assert_pixmap_contains_box(PixmapPtr pixmap, BoxPtr box, const char *function) 99428d7b3dSmrg{ 100428d7b3dSmrg if (box->x1 < 0 || box->y1 < 0 || 101428d7b3dSmrg box->x2 > pixmap->drawable.width || 102428d7b3dSmrg box->y2 > pixmap->drawable.height) 103428d7b3dSmrg FatalError("%s: damage box is beyond the pixmap: box=(%d, %d), (%d, %d), pixmap=(%d, %d)\n", 104428d7b3dSmrg __FUNCTION__, 105428d7b3dSmrg box->x1, box->y1, box->x2, box->y2, 106428d7b3dSmrg pixmap->drawable.width, 107428d7b3dSmrg pixmap->drawable.height); 108428d7b3dSmrg} 109428d7b3dSmrg#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__) 110428d7b3dSmrg#else 111428d7b3dSmrg#define assert_pixmap_contains_box(p, b) 112428d7b3dSmrg#endif 113428d7b3dSmrg 114428d7b3dSmrgstatic void apply_damage(struct sna_composite_op *op, RegionPtr region) 115428d7b3dSmrg{ 116428d7b3dSmrg DBG(("%s: damage=%p, region=%dx[(%d, %d), (%d, %d)]\n", 117428d7b3dSmrg __FUNCTION__, op->damage, 118428d7b3dSmrg region_num_rects(region), 119428d7b3dSmrg region->extents.x1, region->extents.y1, 120428d7b3dSmrg region->extents.x2, region->extents.y2)); 121428d7b3dSmrg 122428d7b3dSmrg if (op->damage == NULL) 123428d7b3dSmrg return; 124428d7b3dSmrg 125428d7b3dSmrg RegionTranslate(region, op->dst.x, op->dst.y); 126428d7b3dSmrg 127428d7b3dSmrg assert_pixmap_contains_box(op->dst.pixmap, RegionExtents(region)); 128428d7b3dSmrg sna_damage_add(op->damage, region); 129428d7b3dSmrg} 130428d7b3dSmrg 131428d7b3dSmrgstatic void _apply_damage_box(struct sna_composite_op *op, const BoxRec *box) 132428d7b3dSmrg{ 133428d7b3dSmrg BoxRec r; 134428d7b3dSmrg 135428d7b3dSmrg r.x1 = box->x1 + op->dst.x; 136428d7b3dSmrg r.x2 = box->x2 + op->dst.x; 137428d7b3dSmrg r.y1 = box->y1 + op->dst.y; 138428d7b3dSmrg r.y2 = box->y2 + op->dst.y; 139428d7b3dSmrg 140428d7b3dSmrg assert_pixmap_contains_box(op->dst.pixmap, &r); 141428d7b3dSmrg sna_damage_add_box(op->damage, &r); 142428d7b3dSmrg} 143428d7b3dSmrg 144428d7b3dSmrginline static void apply_damage_box(struct sna_composite_op *op, const BoxRec *box) 145428d7b3dSmrg{ 146428d7b3dSmrg if (op->damage) 147428d7b3dSmrg _apply_damage_box(op, box); 148428d7b3dSmrg} 149428d7b3dSmrg 150428d7b3dSmrgstatic bool 151428d7b3dSmrgmono_polygon_init(struct mono_polygon *polygon, BoxPtr box, int num_edges) 152428d7b3dSmrg{ 153428d7b3dSmrg unsigned h = box->y2 - box->y1; 154428d7b3dSmrg 155428d7b3dSmrg polygon->y_buckets = polygon->y_buckets_embedded; 156428d7b3dSmrg if (h > ARRAY_SIZE (polygon->y_buckets_embedded)) { 157428d7b3dSmrg polygon->y_buckets = malloc (h * sizeof (struct mono_edge *)); 158428d7b3dSmrg if (unlikely (NULL == polygon->y_buckets)) 159428d7b3dSmrg return false; 160428d7b3dSmrg } 161428d7b3dSmrg 162428d7b3dSmrg polygon->num_edges = 0; 163428d7b3dSmrg polygon->edges = polygon->edges_embedded; 164428d7b3dSmrg if (num_edges > (int)ARRAY_SIZE (polygon->edges_embedded)) { 165428d7b3dSmrg polygon->edges = malloc (num_edges * sizeof (struct mono_edge)); 166428d7b3dSmrg if (unlikely (polygon->edges == NULL)) { 167428d7b3dSmrg if (polygon->y_buckets != polygon->y_buckets_embedded) 168428d7b3dSmrg free(polygon->y_buckets); 169428d7b3dSmrg return false; 170428d7b3dSmrg } 171428d7b3dSmrg } 172428d7b3dSmrg 173428d7b3dSmrg memset(polygon->y_buckets, 0, h * sizeof (struct edge *)); 174428d7b3dSmrg return true; 175428d7b3dSmrg} 176428d7b3dSmrg 177428d7b3dSmrgstatic void 178428d7b3dSmrgmono_polygon_fini(struct mono_polygon *polygon) 179428d7b3dSmrg{ 180428d7b3dSmrg if (polygon->y_buckets != polygon->y_buckets_embedded) 181428d7b3dSmrg free(polygon->y_buckets); 182428d7b3dSmrg 183428d7b3dSmrg if (polygon->edges != polygon->edges_embedded) 184428d7b3dSmrg free(polygon->edges); 185428d7b3dSmrg} 186428d7b3dSmrg 187428d7b3dSmrgstatic void 188428d7b3dSmrgmono_add_line(struct mono *mono, 189428d7b3dSmrg int dst_x, int dst_y, 190428d7b3dSmrg xFixed top, xFixed bottom, 191428d7b3dSmrg const xPointFixed *p1, const xPointFixed *p2, 192428d7b3dSmrg int dir) 193428d7b3dSmrg{ 194428d7b3dSmrg struct mono_polygon *polygon = &mono->polygon; 195428d7b3dSmrg struct mono_edge *e; 196428d7b3dSmrg int y, ytop, ybot; 197428d7b3dSmrg 198428d7b3dSmrg __DBG(("%s: top=%d, bottom=%d, line=(%d, %d), (%d, %d) delta=%dx%d, dir=%d\n", 199428d7b3dSmrg __FUNCTION__, 200428d7b3dSmrg (int)top, (int)bottom, 201428d7b3dSmrg (int)p1->x, (int)p1->y, (int)p2->x, (int)p2->y, 202428d7b3dSmrg dst_x, dst_y, 203428d7b3dSmrg dir)); 204428d7b3dSmrg 205428d7b3dSmrg if (top > bottom) { 206428d7b3dSmrg const xPointFixed *t; 207428d7b3dSmrg 208428d7b3dSmrg y = top; 209428d7b3dSmrg top = bottom; 210428d7b3dSmrg bottom = y; 211428d7b3dSmrg 212428d7b3dSmrg t = p1; 213428d7b3dSmrg p1 = p2; 214428d7b3dSmrg p2 = t; 215428d7b3dSmrg 216428d7b3dSmrg dir = -dir; 217428d7b3dSmrg } 218428d7b3dSmrg 219428d7b3dSmrg y = I(top) + dst_y; 220428d7b3dSmrg ytop = MAX(y, mono->clip.extents.y1); 221428d7b3dSmrg 222428d7b3dSmrg y = I(bottom) + dst_y; 223428d7b3dSmrg ybot = MIN(y, mono->clip.extents.y2); 224428d7b3dSmrg 225428d7b3dSmrg __DBG(("%s: edge height [%d, %d] = %d\n", 226428d7b3dSmrg __FUNCTION__, ytop, ybot, ybot - ytop)); 227428d7b3dSmrg if (ybot <= ytop) { 228428d7b3dSmrg __DBG(("discard clipped line\n")); 229428d7b3dSmrg return; 230428d7b3dSmrg } 231428d7b3dSmrg 232428d7b3dSmrg e = polygon->edges + polygon->num_edges++; 233428d7b3dSmrg e->height_left = ybot - ytop; 234428d7b3dSmrg e->dir = dir; 235428d7b3dSmrg 236428d7b3dSmrg if (I(p1->x) == I(p2->x)) { 237428d7b3dSmrg __DBG(("%s: vertical edge x:%d\n", __FUNCTION__, I(p1->x))); 238428d7b3dSmrg e->x.quo = p1->x; 239428d7b3dSmrg e->x.rem = 0; 240428d7b3dSmrg e->dxdy.quo = 0; 241428d7b3dSmrg e->dxdy.rem = 0; 242428d7b3dSmrg e->dy = 0; 243428d7b3dSmrg } else { 244428d7b3dSmrg int64_t dx = (int64_t)p2->x - p1->x; 245428d7b3dSmrg int64_t dy = (int64_t)p2->y - p1->y; 246428d7b3dSmrg 247428d7b3dSmrg __DBG(("%s: diagonal edge (%d, %d), x:[%d, %d]\n", __FUNCTION__, dx, dy, I(p1->x), I(p2->x))); 248428d7b3dSmrg assert(dy > 0); 249428d7b3dSmrg 250428d7b3dSmrg e->dxdy = floored_muldivrem(dx, pixman_fixed_1, dy); 251428d7b3dSmrg 252428d7b3dSmrg e->x = floored_muldivrem((ytop - dst_y) * pixman_fixed_1 + pixman_fixed_1_minus_e/2 - p1->y, 253428d7b3dSmrg dx, dy); 254428d7b3dSmrg e->x.quo += p1->x; 255428d7b3dSmrg e->x.rem -= dy; 256428d7b3dSmrg 257428d7b3dSmrg e->dy = dy; 258428d7b3dSmrg 259428d7b3dSmrg __DBG(("%s: initial x=%d [%d.%d/%d] + dxdy=%d.%d/%d\n", 260428d7b3dSmrg __FUNCTION__, 261428d7b3dSmrg I(e->x.quo), e->x.quo, e->x.rem, e->dy, 262428d7b3dSmrg e->dxdy.quo, e->dxdy.rem, e->dy)); 263428d7b3dSmrg } 264428d7b3dSmrg e->x.quo += dst_x*pixman_fixed_1; 265428d7b3dSmrg 266428d7b3dSmrg { 267428d7b3dSmrg struct mono_edge **ptail = &polygon->y_buckets[ytop - mono->clip.extents.y1]; 268428d7b3dSmrg if (*ptail) 269428d7b3dSmrg (*ptail)->prev = e; 270428d7b3dSmrg e->next = *ptail; 271428d7b3dSmrg e->prev = NULL; 272428d7b3dSmrg *ptail = e; 273428d7b3dSmrg } 274428d7b3dSmrg} 275428d7b3dSmrg 276428d7b3dSmrgstatic struct mono_edge * 277428d7b3dSmrgmono_merge_sorted_edges(struct mono_edge *head_a, struct mono_edge *head_b) 278428d7b3dSmrg{ 279428d7b3dSmrg struct mono_edge *head, **next, *prev; 280428d7b3dSmrg int32_t x; 281428d7b3dSmrg 282428d7b3dSmrg if (head_b == NULL) 283428d7b3dSmrg return head_a; 284428d7b3dSmrg 285428d7b3dSmrg prev = head_a->prev; 286428d7b3dSmrg next = &head; 287428d7b3dSmrg if (head_a->x.quo <= head_b->x.quo) { 288428d7b3dSmrg head = head_a; 289428d7b3dSmrg } else { 290428d7b3dSmrg head = head_b; 291428d7b3dSmrg head_b->prev = prev; 292428d7b3dSmrg goto start_with_b; 293428d7b3dSmrg } 294428d7b3dSmrg 295428d7b3dSmrg do { 296428d7b3dSmrg x = head_b->x.quo; 297428d7b3dSmrg while (head_a != NULL && head_a->x.quo <= x) { 298428d7b3dSmrg prev = head_a; 299428d7b3dSmrg next = &head_a->next; 300428d7b3dSmrg head_a = head_a->next; 301428d7b3dSmrg } 302428d7b3dSmrg 303428d7b3dSmrg head_b->prev = prev; 304428d7b3dSmrg *next = head_b; 305428d7b3dSmrg if (head_a == NULL) 306428d7b3dSmrg return head; 307428d7b3dSmrg 308428d7b3dSmrgstart_with_b: 309428d7b3dSmrg x = head_a->x.quo; 310428d7b3dSmrg while (head_b != NULL && head_b->x.quo <= x) { 311428d7b3dSmrg prev = head_b; 312428d7b3dSmrg next = &head_b->next; 313428d7b3dSmrg head_b = head_b->next; 314428d7b3dSmrg } 315428d7b3dSmrg 316428d7b3dSmrg head_a->prev = prev; 317428d7b3dSmrg *next = head_a; 318428d7b3dSmrg if (head_b == NULL) 319428d7b3dSmrg return head; 320428d7b3dSmrg } while (1); 321428d7b3dSmrg} 322428d7b3dSmrg 323428d7b3dSmrgstatic struct mono_edge * 324428d7b3dSmrgmono_sort_edges(struct mono_edge *list, 325428d7b3dSmrg unsigned int level, 326428d7b3dSmrg struct mono_edge **head_out) 327428d7b3dSmrg{ 328428d7b3dSmrg struct mono_edge *head_other, *remaining; 329428d7b3dSmrg unsigned int i; 330428d7b3dSmrg 331428d7b3dSmrg head_other = list->next; 332428d7b3dSmrg 333428d7b3dSmrg if (head_other == NULL) { 334428d7b3dSmrg *head_out = list; 335428d7b3dSmrg return NULL; 336428d7b3dSmrg } 337428d7b3dSmrg 338428d7b3dSmrg remaining = head_other->next; 339428d7b3dSmrg if (list->x.quo <= head_other->x.quo) { 340428d7b3dSmrg *head_out = list; 341428d7b3dSmrg head_other->next = NULL; 342428d7b3dSmrg } else { 343428d7b3dSmrg *head_out = head_other; 344428d7b3dSmrg head_other->prev = list->prev; 345428d7b3dSmrg head_other->next = list; 346428d7b3dSmrg list->prev = head_other; 347428d7b3dSmrg list->next = NULL; 348428d7b3dSmrg } 349428d7b3dSmrg 350428d7b3dSmrg for (i = 0; i < level && remaining; i++) { 351428d7b3dSmrg remaining = mono_sort_edges(remaining, i, &head_other); 352428d7b3dSmrg *head_out = mono_merge_sorted_edges(*head_out, head_other); 353428d7b3dSmrg } 354428d7b3dSmrg 355428d7b3dSmrg return remaining; 356428d7b3dSmrg} 357428d7b3dSmrg 358428d7b3dSmrgstatic struct mono_edge *mono_filter(struct mono_edge *edges) 359428d7b3dSmrg{ 360428d7b3dSmrg struct mono_edge *e; 361428d7b3dSmrg 362428d7b3dSmrg e = edges; 363428d7b3dSmrg while (e->next) { 364428d7b3dSmrg struct mono_edge *n = e->next; 365428d7b3dSmrg if (e->dir == -n->dir && 366428d7b3dSmrg e->height_left == n->height_left && 367428d7b3dSmrg e->x.quo == n->x.quo && 368428d7b3dSmrg e->x.rem == n->x.rem && 369428d7b3dSmrg e->dxdy.quo == n->dxdy.quo && 370428d7b3dSmrg e->dxdy.rem == n->dxdy.rem) { 371428d7b3dSmrg if (e->prev) 372428d7b3dSmrg e->prev->next = n->next; 373428d7b3dSmrg else 374428d7b3dSmrg edges = n->next; 375428d7b3dSmrg if (n->next) 376428d7b3dSmrg n->next->prev = e->prev; 377428d7b3dSmrg else 378428d7b3dSmrg break; 379428d7b3dSmrg 380428d7b3dSmrg e = n->next; 381428d7b3dSmrg } else 382428d7b3dSmrg e = n; 383428d7b3dSmrg } 384428d7b3dSmrg 385428d7b3dSmrg return edges; 386428d7b3dSmrg} 387428d7b3dSmrg 388428d7b3dSmrgstatic struct mono_edge * 389428d7b3dSmrgmono_merge_unsorted_edges(struct mono_edge *head, struct mono_edge *unsorted) 390428d7b3dSmrg{ 391428d7b3dSmrg mono_sort_edges(unsorted, UINT_MAX, &unsorted); 392428d7b3dSmrg return mono_merge_sorted_edges(head, mono_filter(unsorted)); 393428d7b3dSmrg} 394428d7b3dSmrg 395428d7b3dSmrg#if 0 396428d7b3dSmrgstatic inline void 397428d7b3dSmrg__dbg_mono_edges(const char *function, struct mono_edge *edges) 398428d7b3dSmrg{ 399428d7b3dSmrg DBG(("%s: ", function)); 400428d7b3dSmrg while (edges) { 401428d7b3dSmrg if (edges->x.quo < INT16_MAX << 16) { 402428d7b3dSmrg DBG(("(%d.%06d)+(%d.%06d)x%d, ", 403428d7b3dSmrg edges->x.quo, edges->x.rem, 404428d7b3dSmrg edges->dxdy.quo, edges->dxdy.rem, 405428d7b3dSmrg edges->dy*edges->dir)); 406428d7b3dSmrg } 407428d7b3dSmrg edges = edges->next; 408428d7b3dSmrg } 409428d7b3dSmrg DBG(("\n")); 410428d7b3dSmrg} 411428d7b3dSmrg#define DBG_MONO_EDGES(x) __dbg_mono_edges(__FUNCTION__, x) 412428d7b3dSmrgstatic inline void 413428d7b3dSmrgVALIDATE_MONO_EDGES(struct mono_edge *edges) 414428d7b3dSmrg{ 415428d7b3dSmrg int prev_x = edges->x.quo; 416428d7b3dSmrg while ((edges = edges->next)) { 417428d7b3dSmrg assert(edges->x.quo >= prev_x); 418428d7b3dSmrg prev_x = edges->x.quo; 419428d7b3dSmrg } 420428d7b3dSmrg} 421428d7b3dSmrg 422428d7b3dSmrg#else 423428d7b3dSmrg#define DBG_MONO_EDGES(x) 424428d7b3dSmrg#define VALIDATE_MONO_EDGES(x) 425428d7b3dSmrg#endif 426428d7b3dSmrg 427428d7b3dSmrginline static void 428428d7b3dSmrgmono_merge_edges(struct mono *c, struct mono_edge *edges) 429428d7b3dSmrg{ 430428d7b3dSmrg struct mono_edge *e; 431428d7b3dSmrg 432428d7b3dSmrg DBG_MONO_EDGES(edges); 433428d7b3dSmrg 434428d7b3dSmrg for (e = edges; c->is_vertical && e; e = e->next) 435428d7b3dSmrg c->is_vertical = e->dy == 0; 436428d7b3dSmrg 437428d7b3dSmrg c->head.next = mono_merge_unsorted_edges(c->head.next, edges); 438428d7b3dSmrg} 439428d7b3dSmrg 440428d7b3dSmrgfastcall static void 441428d7b3dSmrgmono_span(struct mono *c, int x1, int x2, BoxPtr box) 442428d7b3dSmrg{ 443428d7b3dSmrg __DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2)); 444428d7b3dSmrg 445428d7b3dSmrg box->x1 = x1; 446428d7b3dSmrg box->x2 = x2; 447428d7b3dSmrg 448428d7b3dSmrg if (c->clip.data) { 449428d7b3dSmrg pixman_region16_t region; 450428d7b3dSmrg 451428d7b3dSmrg pixman_region_init_rects(®ion, box, 1); 452428d7b3dSmrg RegionIntersect(®ion, ®ion, &c->clip); 453428d7b3dSmrg if (region_num_rects(®ion)) { 454428d7b3dSmrg c->op.boxes(c->sna, &c->op, 455428d7b3dSmrg region_rects(®ion), 456428d7b3dSmrg region_num_rects(®ion)); 457428d7b3dSmrg apply_damage(&c->op, ®ion); 458428d7b3dSmrg } 459428d7b3dSmrg pixman_region_fini(®ion); 460428d7b3dSmrg } else { 461428d7b3dSmrg c->op.box(c->sna, &c->op, box); 462428d7b3dSmrg apply_damage_box(&c->op, box); 463428d7b3dSmrg } 464428d7b3dSmrg} 465428d7b3dSmrg 466428d7b3dSmrgfastcall static void 467428d7b3dSmrgmono_span__fast(struct mono *c, int x1, int x2, BoxPtr box) 468428d7b3dSmrg{ 469428d7b3dSmrg __DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2)); 470428d7b3dSmrg 471428d7b3dSmrg box->x1 = x1; 472428d7b3dSmrg box->x2 = x2; 473428d7b3dSmrg 474428d7b3dSmrg c->op.box(c->sna, &c->op, box); 475428d7b3dSmrg} 476428d7b3dSmrg 477428d7b3dSmrgstruct mono_span_thread_boxes { 478428d7b3dSmrg const struct sna_composite_op *op; 479428d7b3dSmrg#define MONO_SPAN_MAX_BOXES (8192/sizeof(BoxRec)) 480428d7b3dSmrg BoxRec boxes[MONO_SPAN_MAX_BOXES]; 481428d7b3dSmrg int num_boxes; 482428d7b3dSmrg}; 483428d7b3dSmrg 484428d7b3dSmrginline static void 485428d7b3dSmrgthread_mono_span_add_boxes(struct mono *c, const BoxRec *box, int count) 486428d7b3dSmrg{ 487428d7b3dSmrg struct mono_span_thread_boxes *b = c->op.priv; 488428d7b3dSmrg 489428d7b3dSmrg assert(count > 0 && count <= MONO_SPAN_MAX_BOXES); 490428d7b3dSmrg if (unlikely(b->num_boxes + count > MONO_SPAN_MAX_BOXES)) { 491428d7b3dSmrg b->op->thread_boxes(c->sna, b->op, b->boxes, b->num_boxes); 492428d7b3dSmrg b->num_boxes = 0; 493428d7b3dSmrg } 494428d7b3dSmrg 495428d7b3dSmrg memcpy(b->boxes + b->num_boxes, box, count*sizeof(BoxRec)); 496428d7b3dSmrg b->num_boxes += count; 497428d7b3dSmrg assert(b->num_boxes <= MONO_SPAN_MAX_BOXES); 498428d7b3dSmrg} 499428d7b3dSmrg 500428d7b3dSmrgfastcall static void 501428d7b3dSmrgthread_mono_span_clipped(struct mono *c, int x1, int x2, BoxPtr box) 502428d7b3dSmrg{ 503428d7b3dSmrg pixman_region16_t region; 504428d7b3dSmrg 505428d7b3dSmrg __DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2)); 506428d7b3dSmrg 507428d7b3dSmrg box->x1 = x1; 508428d7b3dSmrg box->x2 = x2; 509428d7b3dSmrg 510428d7b3dSmrg assert(c->clip.data); 511428d7b3dSmrg 512428d7b3dSmrg pixman_region_init_rects(®ion, box, 1); 513428d7b3dSmrg RegionIntersect(®ion, ®ion, &c->clip); 514428d7b3dSmrg if (region_num_rects(®ion)) 515428d7b3dSmrg thread_mono_span_add_boxes(c, 516428d7b3dSmrg region_rects(®ion), 517428d7b3dSmrg region_num_rects(®ion)); 518428d7b3dSmrg pixman_region_fini(®ion); 519428d7b3dSmrg} 520428d7b3dSmrg 521428d7b3dSmrgfastcall static void 522428d7b3dSmrgthread_mono_span(struct mono *c, int x1, int x2, BoxPtr box) 523428d7b3dSmrg{ 524428d7b3dSmrg __DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2)); 525428d7b3dSmrg 526428d7b3dSmrg box->x1 = x1; 527428d7b3dSmrg box->x2 = x2; 528428d7b3dSmrg thread_mono_span_add_boxes(c, box, 1); 529428d7b3dSmrg} 530428d7b3dSmrg 531428d7b3dSmrginline static void 532428d7b3dSmrgmono_row(struct mono *c, int16_t y, int16_t h) 533428d7b3dSmrg{ 534428d7b3dSmrg struct mono_edge *edge = c->head.next; 535428d7b3dSmrg int prev_x = INT_MIN; 536428d7b3dSmrg int16_t xstart = INT16_MIN; 537428d7b3dSmrg int winding = 0; 538428d7b3dSmrg BoxRec box; 539428d7b3dSmrg 540428d7b3dSmrg DBG_MONO_EDGES(edge); 541428d7b3dSmrg VALIDATE_MONO_EDGES(&c->head); 542428d7b3dSmrg 543428d7b3dSmrg box.y1 = c->clip.extents.y1 + y; 544428d7b3dSmrg box.y2 = box.y1 + h; 545428d7b3dSmrg 546428d7b3dSmrg while (&c->tail != edge) { 547428d7b3dSmrg struct mono_edge *next = edge->next; 548428d7b3dSmrg int16_t xend = I(edge->x.quo); 549428d7b3dSmrg 550428d7b3dSmrg if (--edge->height_left) { 551428d7b3dSmrg if (edge->dy) { 552428d7b3dSmrg edge->x.quo += edge->dxdy.quo; 553428d7b3dSmrg edge->x.rem += edge->dxdy.rem; 554428d7b3dSmrg if (edge->x.rem >= 0) { 555428d7b3dSmrg ++edge->x.quo; 556428d7b3dSmrg edge->x.rem -= edge->dy; 557428d7b3dSmrg } 558428d7b3dSmrg } 559428d7b3dSmrg 560428d7b3dSmrg if (edge->x.quo < prev_x) { 561428d7b3dSmrg struct mono_edge *pos = edge->prev; 562428d7b3dSmrg pos->next = next; 563428d7b3dSmrg next->prev = pos; 564428d7b3dSmrg do { 565428d7b3dSmrg pos = pos->prev; 566428d7b3dSmrg } while (edge->x.quo < pos->x.quo); 567428d7b3dSmrg pos->next->prev = edge; 568428d7b3dSmrg edge->next = pos->next; 569428d7b3dSmrg edge->prev = pos; 570428d7b3dSmrg pos->next = edge; 571428d7b3dSmrg } else 572428d7b3dSmrg prev_x = edge->x.quo; 573428d7b3dSmrg } else { 574428d7b3dSmrg edge->prev->next = next; 575428d7b3dSmrg next->prev = edge->prev; 576428d7b3dSmrg } 577428d7b3dSmrg 578428d7b3dSmrg winding += edge->dir; 579428d7b3dSmrg if (winding == 0) { 580428d7b3dSmrg assert(I(next->x.quo) >= xend); 581428d7b3dSmrg if (I(next->x.quo) > xend + 1) { 582428d7b3dSmrg if (xstart < c->clip.extents.x1) 583428d7b3dSmrg xstart = c->clip.extents.x1; 584428d7b3dSmrg if (xend > c->clip.extents.x2) 585428d7b3dSmrg xend = c->clip.extents.x2; 586428d7b3dSmrg if (xend > xstart) 587428d7b3dSmrg c->span(c, xstart, xend, &box); 588428d7b3dSmrg xstart = INT16_MIN; 589428d7b3dSmrg } 590428d7b3dSmrg } else if (xstart == INT16_MIN) 591428d7b3dSmrg xstart = xend; 592428d7b3dSmrg 593428d7b3dSmrg edge = next; 594428d7b3dSmrg } 595428d7b3dSmrg 596428d7b3dSmrg DBG_MONO_EDGES(c->head.next); 597428d7b3dSmrg VALIDATE_MONO_EDGES(&c->head); 598428d7b3dSmrg} 599428d7b3dSmrg 600428d7b3dSmrgstatic bool 601428d7b3dSmrgmono_init(struct mono *c, int num_edges) 602428d7b3dSmrg{ 603428d7b3dSmrg if (!mono_polygon_init(&c->polygon, &c->clip.extents, num_edges)) 604428d7b3dSmrg return false; 605428d7b3dSmrg 606428d7b3dSmrg c->head.dy = 0; 607428d7b3dSmrg c->head.height_left = INT_MAX; 608428d7b3dSmrg c->head.x.quo = INT16_MIN << 16; 609428d7b3dSmrg c->head.prev = NULL; 610428d7b3dSmrg c->head.next = &c->tail; 611428d7b3dSmrg c->tail.prev = &c->head; 612428d7b3dSmrg c->tail.next = NULL; 613428d7b3dSmrg c->tail.x.quo = INT16_MAX << 16; 614428d7b3dSmrg c->tail.height_left = INT_MAX; 615428d7b3dSmrg c->tail.dy = 0; 616428d7b3dSmrg 617428d7b3dSmrg c->is_vertical = 1; 618428d7b3dSmrg 619428d7b3dSmrg return true; 620428d7b3dSmrg} 621428d7b3dSmrg 622428d7b3dSmrgstatic void 623428d7b3dSmrgmono_fini(struct mono *mono) 624428d7b3dSmrg{ 625428d7b3dSmrg mono_polygon_fini(&mono->polygon); 626428d7b3dSmrg} 627428d7b3dSmrg 628428d7b3dSmrgstatic void 629428d7b3dSmrgmono_step_edges(struct mono *c, int count) 630428d7b3dSmrg{ 631428d7b3dSmrg struct mono_edge *edge; 632428d7b3dSmrg 633428d7b3dSmrg for (edge = c->head.next; edge != &c->tail; edge = edge->next) { 634428d7b3dSmrg edge->height_left -= count; 635428d7b3dSmrg if (! edge->height_left) { 636428d7b3dSmrg edge->prev->next = edge->next; 637428d7b3dSmrg edge->next->prev = edge->prev; 638428d7b3dSmrg } 639428d7b3dSmrg } 640428d7b3dSmrg} 641428d7b3dSmrg 642428d7b3dSmrgflatten static void 643428d7b3dSmrgmono_render(struct mono *mono) 644428d7b3dSmrg{ 645428d7b3dSmrg struct mono_polygon *polygon = &mono->polygon; 646428d7b3dSmrg int i, j, h = mono->clip.extents.y2 - mono->clip.extents.y1; 647428d7b3dSmrg 648428d7b3dSmrg assert(mono->span); 649428d7b3dSmrg 650428d7b3dSmrg for (i = 0; i < h; i = j) { 651428d7b3dSmrg j = i + 1; 652428d7b3dSmrg 653428d7b3dSmrg if (polygon->y_buckets[i]) 654428d7b3dSmrg mono_merge_edges(mono, polygon->y_buckets[i]); 655428d7b3dSmrg 656428d7b3dSmrg if (mono->is_vertical) { 657428d7b3dSmrg struct mono_edge *e = mono->head.next; 658428d7b3dSmrg int min_height = h - i; 659428d7b3dSmrg 660428d7b3dSmrg while (e != &mono->tail) { 661428d7b3dSmrg if (e->height_left < min_height) 662428d7b3dSmrg min_height = e->height_left; 663428d7b3dSmrg e = e->next; 664428d7b3dSmrg } 665428d7b3dSmrg 666428d7b3dSmrg while (--min_height >= 1 && polygon->y_buckets[j] == NULL) 667428d7b3dSmrg j++; 668428d7b3dSmrg if (j != i + 1) 669428d7b3dSmrg mono_step_edges(mono, j - (i + 1)); 670428d7b3dSmrg } 671428d7b3dSmrg 672428d7b3dSmrg mono_row(mono, i, j-i); 673428d7b3dSmrg 674428d7b3dSmrg /* XXX recompute after dropping edges? */ 675428d7b3dSmrg if (mono->head.next == &mono->tail) 676428d7b3dSmrg mono->is_vertical = 1; 677428d7b3dSmrg } 678428d7b3dSmrg} 679428d7b3dSmrg 680428d7b3dSmrgstatic int operator_is_bounded(uint8_t op) 681428d7b3dSmrg{ 682428d7b3dSmrg switch (op) { 683428d7b3dSmrg case PictOpOver: 684428d7b3dSmrg case PictOpOutReverse: 685428d7b3dSmrg case PictOpAdd: 686428d7b3dSmrg return true; 687428d7b3dSmrg default: 688428d7b3dSmrg return false; 689428d7b3dSmrg } 690428d7b3dSmrg} 691428d7b3dSmrg 692428d7b3dSmrgstruct mono_span_thread { 693428d7b3dSmrg struct sna *sna; 694428d7b3dSmrg const xTrapezoid *traps; 695428d7b3dSmrg const struct sna_composite_op *op; 696428d7b3dSmrg RegionPtr clip; 697428d7b3dSmrg int ntrap; 698428d7b3dSmrg BoxRec extents; 699428d7b3dSmrg int dx, dy; 700428d7b3dSmrg}; 701428d7b3dSmrg 702428d7b3dSmrgstatic void 703428d7b3dSmrgmono_span_thread(void *arg) 704428d7b3dSmrg{ 705428d7b3dSmrg struct mono_span_thread *thread = arg; 706428d7b3dSmrg struct mono mono; 707428d7b3dSmrg struct mono_span_thread_boxes boxes; 708428d7b3dSmrg const xTrapezoid *t; 709428d7b3dSmrg int n; 710428d7b3dSmrg 711428d7b3dSmrg mono.sna = thread->sna; 712428d7b3dSmrg 713428d7b3dSmrg mono.clip.extents = thread->extents; 714428d7b3dSmrg mono.clip.data = NULL; 715428d7b3dSmrg if (thread->clip->data) { 716428d7b3dSmrg RegionIntersect(&mono.clip, &mono.clip, thread->clip); 717428d7b3dSmrg if (RegionNil(&mono.clip)) 718428d7b3dSmrg return; 719428d7b3dSmrg } 720428d7b3dSmrg 721428d7b3dSmrg boxes.op = thread->op; 722428d7b3dSmrg boxes.num_boxes = 0; 723428d7b3dSmrg mono.op.priv = &boxes; 724428d7b3dSmrg 725428d7b3dSmrg if (!mono_init(&mono, 2*thread->ntrap)) { 726428d7b3dSmrg RegionUninit(&mono.clip); 727428d7b3dSmrg return; 728428d7b3dSmrg } 729428d7b3dSmrg 730428d7b3dSmrg for (n = thread->ntrap, t = thread->traps; n--; t++) { 731428d7b3dSmrg if (!xTrapezoidValid(t)) 732428d7b3dSmrg continue; 733428d7b3dSmrg 734428d7b3dSmrg if (pixman_fixed_to_int(t->top) + thread->dy >= thread->extents.y2 || 735428d7b3dSmrg pixman_fixed_to_int(t->bottom) + thread->dy <= thread->extents.y1) 736428d7b3dSmrg continue; 737428d7b3dSmrg 738428d7b3dSmrg mono_add_line(&mono, thread->dx, thread->dy, 739428d7b3dSmrg t->top, t->bottom, 740428d7b3dSmrg &t->left.p1, &t->left.p2, 1); 741428d7b3dSmrg mono_add_line(&mono, thread->dx, thread->dy, 742428d7b3dSmrg t->top, t->bottom, 743428d7b3dSmrg &t->right.p1, &t->right.p2, -1); 744428d7b3dSmrg } 745428d7b3dSmrg 746428d7b3dSmrg if (mono.clip.data == NULL) 747428d7b3dSmrg mono.span = thread_mono_span; 748428d7b3dSmrg else 749428d7b3dSmrg mono.span = thread_mono_span_clipped; 750428d7b3dSmrg 751428d7b3dSmrg mono_render(&mono); 752428d7b3dSmrg mono_fini(&mono); 753428d7b3dSmrg 754428d7b3dSmrg if (boxes.num_boxes) 755428d7b3dSmrg thread->op->thread_boxes(thread->sna, thread->op, 756428d7b3dSmrg boxes.boxes, boxes.num_boxes); 757428d7b3dSmrg RegionUninit(&mono.clip); 758428d7b3dSmrg} 759428d7b3dSmrg 760428d7b3dSmrgbool 761428d7b3dSmrgmono_trapezoids_span_converter(struct sna *sna, 762428d7b3dSmrg CARD8 op, PicturePtr src, PicturePtr dst, 763428d7b3dSmrg INT16 src_x, INT16 src_y, 764428d7b3dSmrg int ntrap, xTrapezoid *traps) 765428d7b3dSmrg{ 766428d7b3dSmrg struct mono mono; 767428d7b3dSmrg BoxRec extents; 768428d7b3dSmrg int16_t dst_x, dst_y; 769428d7b3dSmrg int16_t dx, dy; 770428d7b3dSmrg bool unbounded; 771428d7b3dSmrg int num_threads, n; 772428d7b3dSmrg 773428d7b3dSmrg if (NO_SCAN_CONVERTER) 774428d7b3dSmrg return false; 775428d7b3dSmrg 776428d7b3dSmrg trapezoid_origin(&traps[0].left, &dst_x, &dst_y); 777428d7b3dSmrg 778428d7b3dSmrg if (!trapezoids_bounds(ntrap, traps, &extents)) 779428d7b3dSmrg return true; 780428d7b3dSmrg 781428d7b3dSmrg DBG(("%s: extents (%d, %d), (%d, %d)\n", 782428d7b3dSmrg __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 783428d7b3dSmrg 784428d7b3dSmrg if (!sna_compute_composite_region(&mono.clip, 785428d7b3dSmrg src, NULL, dst, 786428d7b3dSmrg src_x + extents.x1 - dst_x, 787428d7b3dSmrg src_y + extents.y1 - dst_y, 788428d7b3dSmrg 0, 0, 789428d7b3dSmrg extents.x1, extents.y1, 790428d7b3dSmrg extents.x2 - extents.x1, 791428d7b3dSmrg extents.y2 - extents.y1)) { 792428d7b3dSmrg DBG(("%s: trapezoids do not intersect drawable clips\n", 793428d7b3dSmrg __FUNCTION__)) ; 794428d7b3dSmrg return true; 795428d7b3dSmrg } 796428d7b3dSmrg 797428d7b3dSmrg dx = dst->pDrawable->x; 798428d7b3dSmrg dy = dst->pDrawable->y; 799428d7b3dSmrg 800428d7b3dSmrg DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n", 801428d7b3dSmrg __FUNCTION__, 802428d7b3dSmrg mono.clip.extents.x1, mono.clip.extents.y1, 803428d7b3dSmrg mono.clip.extents.x2, mono.clip.extents.y2, 804428d7b3dSmrg dx, dy, 805428d7b3dSmrg src_x + mono.clip.extents.x1 - dst_x - dx, 806428d7b3dSmrg src_y + mono.clip.extents.y1 - dst_y - dy)); 807428d7b3dSmrg 808428d7b3dSmrg unbounded = (!sna_drawable_is_clear(dst->pDrawable) && 809428d7b3dSmrg !operator_is_bounded(op)); 810428d7b3dSmrg 811428d7b3dSmrg if (op == PictOpClear && sna->clear) 812428d7b3dSmrg src = sna->clear; 813428d7b3dSmrg 814428d7b3dSmrg mono.sna = sna; 815428d7b3dSmrg if (!mono.sna->render.composite(mono.sna, op, src, NULL, dst, 816428d7b3dSmrg src_x + mono.clip.extents.x1 - dst_x - dx, 817428d7b3dSmrg src_y + mono.clip.extents.y1 - dst_y - dy, 818428d7b3dSmrg 0, 0, 819428d7b3dSmrg mono.clip.extents.x1, mono.clip.extents.y1, 820428d7b3dSmrg mono.clip.extents.x2 - mono.clip.extents.x1, 821428d7b3dSmrg mono.clip.extents.y2 - mono.clip.extents.y1, 822428d7b3dSmrg COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) 823428d7b3dSmrg return false; 824428d7b3dSmrg 825428d7b3dSmrg num_threads = 1; 826428d7b3dSmrg if (!NO_GPU_THREADS && 827428d7b3dSmrg mono.op.thread_boxes && 828428d7b3dSmrg mono.op.damage == NULL && 829428d7b3dSmrg !unbounded) 830428d7b3dSmrg num_threads = sna_use_threads(mono.clip.extents.x2 - mono.clip.extents.x1, 831428d7b3dSmrg mono.clip.extents.y2 - mono.clip.extents.y1, 832428d7b3dSmrg 32); 833428d7b3dSmrg if (num_threads > 1) { 834428d7b3dSmrg struct mono_span_thread threads[num_threads]; 835428d7b3dSmrg int y, h; 836428d7b3dSmrg 837428d7b3dSmrg DBG(("%s: using %d threads for mono span compositing %dx%d\n", 838428d7b3dSmrg __FUNCTION__, num_threads, 839428d7b3dSmrg mono.clip.extents.x2 - mono.clip.extents.x1, 840428d7b3dSmrg mono.clip.extents.y2 - mono.clip.extents.y1)); 841428d7b3dSmrg 842428d7b3dSmrg threads[0].sna = mono.sna; 843428d7b3dSmrg threads[0].op = &mono.op; 844428d7b3dSmrg threads[0].traps = traps; 845428d7b3dSmrg threads[0].ntrap = ntrap; 846428d7b3dSmrg threads[0].extents = mono.clip.extents; 847428d7b3dSmrg threads[0].clip = &mono.clip; 848428d7b3dSmrg threads[0].dx = dx; 849428d7b3dSmrg threads[0].dy = dy; 850428d7b3dSmrg 851428d7b3dSmrg y = extents.y1; 852428d7b3dSmrg h = extents.y2 - extents.y1; 853428d7b3dSmrg h = (h + num_threads - 1) / num_threads; 854428d7b3dSmrg num_threads -= (num_threads-1) * h >= extents.y2 - extents.y1; 855428d7b3dSmrg 856428d7b3dSmrg for (n = 1; n < num_threads; n++) { 857428d7b3dSmrg threads[n] = threads[0]; 858428d7b3dSmrg threads[n].extents.y1 = y; 859428d7b3dSmrg threads[n].extents.y2 = y += h; 860428d7b3dSmrg 861428d7b3dSmrg sna_threads_run(n, mono_span_thread, &threads[n]); 862428d7b3dSmrg } 863428d7b3dSmrg 864428d7b3dSmrg threads[0].extents.y1 = y; 865428d7b3dSmrg threads[0].extents.y2 = extents.y2; 866428d7b3dSmrg mono_span_thread(&threads[0]); 867428d7b3dSmrg 868428d7b3dSmrg sna_threads_wait(); 869428d7b3dSmrg mono.op.done(mono.sna, &mono.op); 870428d7b3dSmrg return true; 871428d7b3dSmrg } 872428d7b3dSmrg 873428d7b3dSmrg if (!mono_init(&mono, 2*ntrap)) 874428d7b3dSmrg return false; 875428d7b3dSmrg 876428d7b3dSmrg for (n = 0; n < ntrap; n++) { 877428d7b3dSmrg if (!xTrapezoidValid(&traps[n])) 878428d7b3dSmrg continue; 879428d7b3dSmrg 880428d7b3dSmrg if (pixman_fixed_integer_floor(traps[n].top) + dy >= mono.clip.extents.y2 || 881428d7b3dSmrg pixman_fixed_integer_ceil(traps[n].bottom) + dy <= mono.clip.extents.y1) 882428d7b3dSmrg continue; 883428d7b3dSmrg 884428d7b3dSmrg mono_add_line(&mono, dx, dy, 885428d7b3dSmrg traps[n].top, traps[n].bottom, 886428d7b3dSmrg &traps[n].left.p1, &traps[n].left.p2, 1); 887428d7b3dSmrg mono_add_line(&mono, dx, dy, 888428d7b3dSmrg traps[n].top, traps[n].bottom, 889428d7b3dSmrg &traps[n].right.p1, &traps[n].right.p2, -1); 890428d7b3dSmrg } 891428d7b3dSmrg 892428d7b3dSmrg if (mono.clip.data == NULL && mono.op.damage == NULL) 893428d7b3dSmrg mono.span = mono_span__fast; 894428d7b3dSmrg else 895428d7b3dSmrg mono.span = mono_span; 896428d7b3dSmrg 897428d7b3dSmrg mono_render(&mono); 898428d7b3dSmrg mono.op.done(mono.sna, &mono.op); 899428d7b3dSmrg mono_fini(&mono); 900428d7b3dSmrg 901428d7b3dSmrg if (unbounded) { 902428d7b3dSmrg xPointFixed p1, p2; 903428d7b3dSmrg 904428d7b3dSmrg if (!mono_init(&mono, 2+2*ntrap)) 905428d7b3dSmrg return false; 906428d7b3dSmrg 907428d7b3dSmrg p1.y = mono.clip.extents.y1 * pixman_fixed_1; 908428d7b3dSmrg p2.y = mono.clip.extents.y2 * pixman_fixed_1; 909428d7b3dSmrg 910428d7b3dSmrg p1.x = mono.clip.extents.x1 * pixman_fixed_1; 911428d7b3dSmrg p2.x = mono.clip.extents.x1 * pixman_fixed_1; 912428d7b3dSmrg mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, -1); 913428d7b3dSmrg 914428d7b3dSmrg p1.x = mono.clip.extents.x2 * pixman_fixed_1; 915428d7b3dSmrg p2.x = mono.clip.extents.x2 * pixman_fixed_1; 916428d7b3dSmrg mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, 1); 917428d7b3dSmrg 918428d7b3dSmrg for (n = 0; n < ntrap; n++) { 919428d7b3dSmrg if (!xTrapezoidValid(&traps[n])) 920428d7b3dSmrg continue; 921428d7b3dSmrg 922428d7b3dSmrg if (pixman_fixed_to_int(traps[n].top) + dy >= mono.clip.extents.y2 || 923428d7b3dSmrg pixman_fixed_to_int(traps[n].bottom) + dy < mono.clip.extents.y1) 924428d7b3dSmrg continue; 925428d7b3dSmrg 926428d7b3dSmrg mono_add_line(&mono, dx, dy, 927428d7b3dSmrg traps[n].top, traps[n].bottom, 928428d7b3dSmrg &traps[n].left.p1, &traps[n].left.p2, 1); 929428d7b3dSmrg mono_add_line(&mono, dx, dy, 930428d7b3dSmrg traps[n].top, traps[n].bottom, 931428d7b3dSmrg &traps[n].right.p1, &traps[n].right.p2, -1); 932428d7b3dSmrg } 933428d7b3dSmrg if (mono.sna->render.composite(mono.sna, 934428d7b3dSmrg PictOpClear, 935428d7b3dSmrg mono.sna->clear, NULL, dst, 936428d7b3dSmrg 0, 0, 937428d7b3dSmrg 0, 0, 938428d7b3dSmrg mono.clip.extents.x1, mono.clip.extents.y1, 939428d7b3dSmrg mono.clip.extents.x2 - mono.clip.extents.x1, 940428d7b3dSmrg mono.clip.extents.y2 - mono.clip.extents.y1, 941428d7b3dSmrg COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) { 942428d7b3dSmrg mono_render(&mono); 943428d7b3dSmrg mono.op.done(mono.sna, &mono.op); 944428d7b3dSmrg } 945428d7b3dSmrg mono_fini(&mono); 946428d7b3dSmrg } 947428d7b3dSmrg 948428d7b3dSmrg REGION_UNINIT(NULL, &mono.clip); 949428d7b3dSmrg return true; 950428d7b3dSmrg} 951428d7b3dSmrg 952428d7b3dSmrgstruct mono_inplace_composite { 953428d7b3dSmrg pixman_image_t *src, *dst; 954428d7b3dSmrg int dx, dy; 955428d7b3dSmrg int sx, sy; 956428d7b3dSmrg int op; 957428d7b3dSmrg}; 958428d7b3dSmrgstruct mono_inplace_fill { 959428d7b3dSmrg uint32_t *data, stride; 960428d7b3dSmrg uint32_t color; 961428d7b3dSmrg int bpp; 962428d7b3dSmrg}; 963428d7b3dSmrg 964428d7b3dSmrgfastcall static void 965428d7b3dSmrgmono_inplace_fill_box(struct sna *sna, 966428d7b3dSmrg const struct sna_composite_op *op, 967428d7b3dSmrg const BoxRec *box) 968428d7b3dSmrg{ 969428d7b3dSmrg struct mono_inplace_fill *fill = op->priv; 970428d7b3dSmrg 971428d7b3dSmrg DBG(("(%s: (%d, %d)x(%d, %d):%08x\n", 972428d7b3dSmrg __FUNCTION__, 973428d7b3dSmrg box->x1, box->y1, 974428d7b3dSmrg box->x2 - box->x1, 975428d7b3dSmrg box->y2 - box->y1, 976428d7b3dSmrg fill->color)); 977428d7b3dSmrg pixman_fill(fill->data, fill->stride, fill->bpp, 978428d7b3dSmrg box->x1, box->y1, 979428d7b3dSmrg box->x2 - box->x1, 980428d7b3dSmrg box->y2 - box->y1, 981428d7b3dSmrg fill->color); 982428d7b3dSmrg} 983428d7b3dSmrg 984428d7b3dSmrgstatic void 985428d7b3dSmrgmono_inplace_fill_boxes(struct sna *sna, 986428d7b3dSmrg const struct sna_composite_op *op, 987428d7b3dSmrg const BoxRec *box, int nbox) 988428d7b3dSmrg{ 989428d7b3dSmrg struct mono_inplace_fill *fill = op->priv; 990428d7b3dSmrg 991428d7b3dSmrg do { 992428d7b3dSmrg DBG(("(%s: (%d, %d)x(%d, %d):%08x\n", 993428d7b3dSmrg __FUNCTION__, 994428d7b3dSmrg box->x1, box->y1, 995428d7b3dSmrg box->x2 - box->x1, 996428d7b3dSmrg box->y2 - box->y1, 997428d7b3dSmrg fill->color)); 998428d7b3dSmrg pixman_fill(fill->data, fill->stride, fill->bpp, 999428d7b3dSmrg box->x1, box->y1, 1000428d7b3dSmrg box->x2 - box->x1, 1001428d7b3dSmrg box->y2 - box->y1, 1002428d7b3dSmrg fill->color); 1003428d7b3dSmrg box++; 1004428d7b3dSmrg } while (--nbox); 1005428d7b3dSmrg} 1006428d7b3dSmrg 1007428d7b3dSmrgfastcall static void 1008428d7b3dSmrgmono_inplace_composite_box(struct sna *sna, 1009428d7b3dSmrg const struct sna_composite_op *op, 1010428d7b3dSmrg const BoxRec *box) 1011428d7b3dSmrg{ 1012428d7b3dSmrg struct mono_inplace_composite *c = op->priv; 1013428d7b3dSmrg 1014428d7b3dSmrg pixman_image_composite(c->op, c->src, NULL, c->dst, 1015428d7b3dSmrg box->x1 + c->sx, box->y1 + c->sy, 1016428d7b3dSmrg 0, 0, 1017428d7b3dSmrg box->x1 + c->dx, box->y1 + c->dy, 1018428d7b3dSmrg box->x2 - box->x1, 1019428d7b3dSmrg box->y2 - box->y1); 1020428d7b3dSmrg} 1021428d7b3dSmrg 1022428d7b3dSmrgstatic void 1023428d7b3dSmrgmono_inplace_composite_boxes(struct sna *sna, 1024428d7b3dSmrg const struct sna_composite_op *op, 1025428d7b3dSmrg const BoxRec *box, int nbox) 1026428d7b3dSmrg{ 1027428d7b3dSmrg struct mono_inplace_composite *c = op->priv; 1028428d7b3dSmrg 1029428d7b3dSmrg do { 1030428d7b3dSmrg pixman_image_composite(c->op, c->src, NULL, c->dst, 1031428d7b3dSmrg box->x1 + c->sx, box->y1 + c->sy, 1032428d7b3dSmrg 0, 0, 1033428d7b3dSmrg box->x1 + c->dx, box->y1 + c->dy, 1034428d7b3dSmrg box->x2 - box->x1, 1035428d7b3dSmrg box->y2 - box->y1); 1036428d7b3dSmrg box++; 1037428d7b3dSmrg } while (--nbox); 1038428d7b3dSmrg} 1039428d7b3dSmrg 1040428d7b3dSmrgbool 1041428d7b3dSmrgmono_trapezoid_span_inplace(struct sna *sna, 1042428d7b3dSmrg CARD8 op, 1043428d7b3dSmrg PicturePtr src, 1044428d7b3dSmrg PicturePtr dst, 1045428d7b3dSmrg INT16 src_x, INT16 src_y, 1046428d7b3dSmrg int ntrap, xTrapezoid *traps) 1047428d7b3dSmrg{ 1048428d7b3dSmrg struct mono mono; 1049428d7b3dSmrg union { 1050428d7b3dSmrg struct mono_inplace_fill fill; 1051428d7b3dSmrg struct mono_inplace_composite composite; 1052428d7b3dSmrg } inplace; 1053428d7b3dSmrg int was_clear; 1054428d7b3dSmrg int x, y, n; 1055428d7b3dSmrg 1056428d7b3dSmrg if (!trapezoids_bounds(ntrap, traps, &mono.clip.extents)) 1057428d7b3dSmrg return true; 1058428d7b3dSmrg 1059428d7b3dSmrg DBG(("%s: extents (%d, %d), (%d, %d)\n", 1060428d7b3dSmrg __FUNCTION__, 1061428d7b3dSmrg mono.clip.extents.x1, mono.clip.extents.y1, 1062428d7b3dSmrg mono.clip.extents.x2, mono.clip.extents.y2)); 1063428d7b3dSmrg 1064428d7b3dSmrg if (!sna_compute_composite_region(&mono.clip, 1065428d7b3dSmrg src, NULL, dst, 1066428d7b3dSmrg src_x, src_y, 1067428d7b3dSmrg 0, 0, 1068428d7b3dSmrg mono.clip.extents.x1, mono.clip.extents.y1, 1069428d7b3dSmrg mono.clip.extents.x2 - mono.clip.extents.x1, 1070428d7b3dSmrg mono.clip.extents.y2 - mono.clip.extents.y1)) { 1071428d7b3dSmrg DBG(("%s: trapezoids do not intersect drawable clips\n", 1072428d7b3dSmrg __FUNCTION__)) ; 1073428d7b3dSmrg return true; 1074428d7b3dSmrg } 1075428d7b3dSmrg 1076428d7b3dSmrg DBG(("%s: clipped extents (%d, %d), (%d, %d)\n", 1077428d7b3dSmrg __FUNCTION__, 1078428d7b3dSmrg mono.clip.extents.x1, mono.clip.extents.y1, 1079428d7b3dSmrg mono.clip.extents.x2, mono.clip.extents.y2)); 1080428d7b3dSmrg 1081428d7b3dSmrg was_clear = sna_drawable_is_clear(dst->pDrawable); 1082428d7b3dSmrg if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &mono.clip, 1083428d7b3dSmrg MOVE_WRITE | MOVE_READ)) 1084428d7b3dSmrg return true; 1085428d7b3dSmrg 1086428d7b3dSmrg mono.sna = sna; 1087428d7b3dSmrg if (!mono_init(&mono, 2*ntrap)) 1088428d7b3dSmrg return false; 1089428d7b3dSmrg 1090428d7b3dSmrg mono.op.damage = NULL; 1091428d7b3dSmrg 1092428d7b3dSmrg x = dst->pDrawable->x; 1093428d7b3dSmrg y = dst->pDrawable->y; 1094428d7b3dSmrg 1095428d7b3dSmrg for (n = 0; n < ntrap; n++) { 1096428d7b3dSmrg if (!xTrapezoidValid(&traps[n])) 1097428d7b3dSmrg continue; 1098428d7b3dSmrg 1099428d7b3dSmrg if (pixman_fixed_to_int(traps[n].top) + y >= mono.clip.extents.y2 || 1100428d7b3dSmrg pixman_fixed_to_int(traps[n].bottom) + y < mono.clip.extents.y1) 1101428d7b3dSmrg continue; 1102428d7b3dSmrg 1103428d7b3dSmrg mono_add_line(&mono, x, y, 1104428d7b3dSmrg traps[n].top, traps[n].bottom, 1105428d7b3dSmrg &traps[n].left.p1, &traps[n].left.p2, 1); 1106428d7b3dSmrg mono_add_line(&mono, x, y, 1107428d7b3dSmrg traps[n].top, traps[n].bottom, 1108428d7b3dSmrg &traps[n].right.p1, &traps[n].right.p2, -1); 1109428d7b3dSmrg } 1110428d7b3dSmrg 1111428d7b3dSmrg if (sna_picture_is_solid(src, &inplace.fill.color) && 1112428d7b3dSmrg (op == PictOpSrc || op == PictOpClear || 1113428d7b3dSmrg (was_clear && (op == PictOpOver || op == PictOpAdd)) || 1114428d7b3dSmrg (op == PictOpOver && inplace.fill.color >> 24 == 0xff))) { 1115428d7b3dSmrg PixmapPtr pixmap; 1116428d7b3dSmrg int16_t dx, dy; 1117428d7b3dSmrg uint8_t *ptr; 1118428d7b3dSmrg 1119428d7b3dSmrgunbounded_pass: 1120428d7b3dSmrg pixmap = get_drawable_pixmap(dst->pDrawable); 1121428d7b3dSmrg 1122428d7b3dSmrg ptr = pixmap->devPrivate.ptr; 1123428d7b3dSmrg if (get_drawable_deltas(dst->pDrawable, pixmap, &dx, &dy)) 1124428d7b3dSmrg ptr += dy * pixmap->devKind + dx * pixmap->drawable.bitsPerPixel / 8; 1125428d7b3dSmrg inplace.fill.data = (uint32_t *)ptr; 1126428d7b3dSmrg inplace.fill.stride = pixmap->devKind / sizeof(uint32_t); 1127428d7b3dSmrg inplace.fill.bpp = pixmap->drawable.bitsPerPixel; 1128428d7b3dSmrg 1129428d7b3dSmrg if (op == PictOpClear) 1130428d7b3dSmrg inplace.fill.color = 0; 1131428d7b3dSmrg else if (dst->format != PICT_a8r8g8b8) 1132428d7b3dSmrg inplace.fill.color = sna_rgba_to_color(inplace.fill.color, dst->format); 1133428d7b3dSmrg 1134428d7b3dSmrg DBG(("%s: fill %x\n", __FUNCTION__, inplace.fill.color)); 1135428d7b3dSmrg 1136428d7b3dSmrg mono.op.priv = &inplace.fill; 1137428d7b3dSmrg mono.op.box = mono_inplace_fill_box; 1138428d7b3dSmrg mono.op.boxes = mono_inplace_fill_boxes; 1139428d7b3dSmrg 1140428d7b3dSmrg op = 0; 1141428d7b3dSmrg } else { 1142428d7b3dSmrg if (src->pDrawable) { 1143428d7b3dSmrg if (!sna_drawable_move_to_cpu(src->pDrawable, 1144428d7b3dSmrg MOVE_READ)) { 1145428d7b3dSmrg mono_fini(&mono); 1146428d7b3dSmrg return false; 1147428d7b3dSmrg } 1148428d7b3dSmrg if (src->alphaMap && 1149428d7b3dSmrg !sna_drawable_move_to_cpu(src->alphaMap->pDrawable, 1150428d7b3dSmrg MOVE_READ)) { 1151428d7b3dSmrg mono_fini(&mono); 1152428d7b3dSmrg return false; 1153428d7b3dSmrg } 1154428d7b3dSmrg } 1155428d7b3dSmrg 1156428d7b3dSmrg inplace.composite.dst = image_from_pict(dst, false, 1157428d7b3dSmrg &inplace.composite.dx, 1158428d7b3dSmrg &inplace.composite.dy); 1159428d7b3dSmrg inplace.composite.src = image_from_pict(src, false, 1160428d7b3dSmrg &inplace.composite.sx, 1161428d7b3dSmrg &inplace.composite.sy); 1162428d7b3dSmrg inplace.composite.sx += 1163428d7b3dSmrg src_x - pixman_fixed_to_int(traps[0].left.p1.x), 1164428d7b3dSmrg inplace.composite.sy += 1165428d7b3dSmrg src_y - pixman_fixed_to_int(traps[0].left.p1.y), 1166428d7b3dSmrg inplace.composite.op = op; 1167428d7b3dSmrg 1168428d7b3dSmrg mono.op.priv = &inplace.composite; 1169428d7b3dSmrg mono.op.box = mono_inplace_composite_box; 1170428d7b3dSmrg mono.op.boxes = mono_inplace_composite_boxes; 1171428d7b3dSmrg } 1172428d7b3dSmrg 1173428d7b3dSmrg if (mono.clip.data == NULL && mono.op.damage == NULL) 1174428d7b3dSmrg mono.span = mono_span__fast; 1175428d7b3dSmrg else 1176428d7b3dSmrg mono.span = mono_span; 1177428d7b3dSmrg if (sigtrap_get() == 0) { 1178428d7b3dSmrg mono_render(&mono); 1179428d7b3dSmrg sigtrap_put(); 1180428d7b3dSmrg } 1181428d7b3dSmrg mono_fini(&mono); 1182428d7b3dSmrg 1183428d7b3dSmrg if (op) { 1184428d7b3dSmrg free_pixman_pict(src, inplace.composite.src); 1185428d7b3dSmrg free_pixman_pict(dst, inplace.composite.dst); 1186428d7b3dSmrg 1187428d7b3dSmrg if (!was_clear && !operator_is_bounded(op)) { 1188428d7b3dSmrg xPointFixed p1, p2; 1189428d7b3dSmrg 1190428d7b3dSmrg DBG(("%s: unbounded fixup\n", __FUNCTION__)); 1191428d7b3dSmrg 1192428d7b3dSmrg if (!mono_init(&mono, 2+2*ntrap)) 1193428d7b3dSmrg return false; 1194428d7b3dSmrg 1195428d7b3dSmrg p1.y = mono.clip.extents.y1 * pixman_fixed_1; 1196428d7b3dSmrg p2.y = mono.clip.extents.y2 * pixman_fixed_1; 1197428d7b3dSmrg 1198428d7b3dSmrg p1.x = mono.clip.extents.x1 * pixman_fixed_1; 1199428d7b3dSmrg p2.x = mono.clip.extents.x1 * pixman_fixed_1; 1200428d7b3dSmrg mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, -1); 1201428d7b3dSmrg 1202428d7b3dSmrg p1.x = mono.clip.extents.x2 * pixman_fixed_1; 1203428d7b3dSmrg p2.x = mono.clip.extents.x2 * pixman_fixed_1; 1204428d7b3dSmrg mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, 1); 1205428d7b3dSmrg 1206428d7b3dSmrg for (n = 0; n < ntrap; n++) { 1207428d7b3dSmrg if (!xTrapezoidValid(&traps[n])) 1208428d7b3dSmrg continue; 1209428d7b3dSmrg 1210428d7b3dSmrg if (pixman_fixed_to_int(traps[n].top) + x >= mono.clip.extents.y2 || 1211428d7b3dSmrg pixman_fixed_to_int(traps[n].bottom) + y < mono.clip.extents.y1) 1212428d7b3dSmrg continue; 1213428d7b3dSmrg 1214428d7b3dSmrg mono_add_line(&mono, x, y, 1215428d7b3dSmrg traps[n].top, traps[n].bottom, 1216428d7b3dSmrg &traps[n].left.p1, &traps[n].left.p2, 1); 1217428d7b3dSmrg mono_add_line(&mono, x, y, 1218428d7b3dSmrg traps[n].top, traps[n].bottom, 1219428d7b3dSmrg &traps[n].right.p1, &traps[n].right.p2, -1); 1220428d7b3dSmrg } 1221428d7b3dSmrg 1222428d7b3dSmrg op = PictOpClear; 1223428d7b3dSmrg goto unbounded_pass; 1224428d7b3dSmrg } 1225428d7b3dSmrg } 1226428d7b3dSmrg 1227428d7b3dSmrg return true; 1228428d7b3dSmrg} 1229428d7b3dSmrg 1230428d7b3dSmrgbool 1231428d7b3dSmrgmono_trap_span_converter(struct sna *sna, 1232428d7b3dSmrg PicturePtr dst, 1233428d7b3dSmrg INT16 x, INT16 y, 1234428d7b3dSmrg int ntrap, xTrap *traps) 1235428d7b3dSmrg{ 1236428d7b3dSmrg struct mono mono; 1237428d7b3dSmrg xRenderColor white; 1238428d7b3dSmrg PicturePtr src; 1239428d7b3dSmrg int error; 1240428d7b3dSmrg int n; 1241428d7b3dSmrg 1242428d7b3dSmrg white.red = white.green = white.blue = white.alpha = 0xffff; 1243428d7b3dSmrg src = CreateSolidPicture(0, &white, &error); 1244428d7b3dSmrg if (src == NULL) 1245428d7b3dSmrg return true; 1246428d7b3dSmrg 1247428d7b3dSmrg mono.clip = *dst->pCompositeClip; 1248428d7b3dSmrg x += dst->pDrawable->x; 1249428d7b3dSmrg y += dst->pDrawable->y; 1250428d7b3dSmrg 1251428d7b3dSmrg DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d)\n", 1252428d7b3dSmrg __FUNCTION__, 1253428d7b3dSmrg mono.clip.extents.x1, mono.clip.extents.y1, 1254428d7b3dSmrg mono.clip.extents.x2, mono.clip.extents.y2, 1255428d7b3dSmrg x, y)); 1256428d7b3dSmrg 1257428d7b3dSmrg mono.sna = sna; 1258428d7b3dSmrg if (!mono_init(&mono, 2*ntrap)) 1259428d7b3dSmrg return false; 1260428d7b3dSmrg 1261428d7b3dSmrg for (n = 0; n < ntrap; n++) { 1262428d7b3dSmrg xPointFixed p1, p2; 1263428d7b3dSmrg 1264428d7b3dSmrg if (pixman_fixed_to_int(traps[n].top.y) + y >= mono.clip.extents.y2 || 1265428d7b3dSmrg pixman_fixed_to_int(traps[n].bot.y) + y < mono.clip.extents.y1) 1266428d7b3dSmrg continue; 1267428d7b3dSmrg 1268428d7b3dSmrg p1.y = traps[n].top.y; 1269428d7b3dSmrg p2.y = traps[n].bot.y; 1270428d7b3dSmrg 1271428d7b3dSmrg p1.x = traps[n].top.l; 1272428d7b3dSmrg p2.x = traps[n].bot.l; 1273428d7b3dSmrg mono_add_line(&mono, x, y, 1274428d7b3dSmrg traps[n].top.y, traps[n].bot.y, 1275428d7b3dSmrg &p1, &p2, 1); 1276428d7b3dSmrg 1277428d7b3dSmrg p1.x = traps[n].top.r; 1278428d7b3dSmrg p2.x = traps[n].bot.r; 1279428d7b3dSmrg mono_add_line(&mono, x, y, 1280428d7b3dSmrg traps[n].top.y, traps[n].bot.y, 1281428d7b3dSmrg &p1, &p2, -1); 1282428d7b3dSmrg } 1283428d7b3dSmrg 1284428d7b3dSmrg if (mono.sna->render.composite(mono.sna, PictOpAdd, src, NULL, dst, 1285428d7b3dSmrg 0, 0, 1286428d7b3dSmrg 0, 0, 1287428d7b3dSmrg mono.clip.extents.x1, mono.clip.extents.y1, 1288428d7b3dSmrg mono.clip.extents.x2 - mono.clip.extents.x1, 1289428d7b3dSmrg mono.clip.extents.y2 - mono.clip.extents.y1, 1290428d7b3dSmrg COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) { 1291428d7b3dSmrg if (mono.clip.data == NULL && mono.op.damage == NULL) 1292428d7b3dSmrg mono.span = mono_span__fast; 1293428d7b3dSmrg else 1294428d7b3dSmrg mono.span = mono_span; 1295428d7b3dSmrg mono_render(&mono); 1296428d7b3dSmrg mono.op.done(mono.sna, &mono.op); 1297428d7b3dSmrg } 1298428d7b3dSmrg 1299428d7b3dSmrg mono_fini(&mono); 1300428d7b3dSmrg FreePicture(src, 0); 1301428d7b3dSmrg return true; 1302428d7b3dSmrg} 1303428d7b3dSmrg 1304428d7b3dSmrgbool 1305428d7b3dSmrgmono_triangles_span_converter(struct sna *sna, 1306428d7b3dSmrg CARD8 op, PicturePtr src, PicturePtr dst, 1307428d7b3dSmrg INT16 src_x, INT16 src_y, 1308428d7b3dSmrg int count, xTriangle *tri) 1309428d7b3dSmrg{ 1310428d7b3dSmrg struct mono mono; 1311428d7b3dSmrg BoxRec extents; 1312428d7b3dSmrg int16_t dst_x, dst_y; 1313428d7b3dSmrg int16_t dx, dy; 1314428d7b3dSmrg bool was_clear; 1315428d7b3dSmrg int n; 1316428d7b3dSmrg 1317428d7b3dSmrg mono.sna = sna; 1318428d7b3dSmrg 1319428d7b3dSmrg dst_x = pixman_fixed_to_int(tri[0].p1.x); 1320428d7b3dSmrg dst_y = pixman_fixed_to_int(tri[0].p1.y); 1321428d7b3dSmrg 1322428d7b3dSmrg miTriangleBounds(count, tri, &extents); 1323428d7b3dSmrg DBG(("%s: extents (%d, %d), (%d, %d)\n", 1324428d7b3dSmrg __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 1325428d7b3dSmrg 1326428d7b3dSmrg if (extents.y1 >= extents.y2 || extents.x1 >= extents.x2) 1327428d7b3dSmrg return true; 1328428d7b3dSmrg 1329428d7b3dSmrg if (!sna_compute_composite_region(&mono.clip, 1330428d7b3dSmrg src, NULL, dst, 1331428d7b3dSmrg src_x + extents.x1 - dst_x, 1332428d7b3dSmrg src_y + extents.y1 - dst_y, 1333428d7b3dSmrg 0, 0, 1334428d7b3dSmrg extents.x1, extents.y1, 1335428d7b3dSmrg extents.x2 - extents.x1, 1336428d7b3dSmrg extents.y2 - extents.y1)) { 1337428d7b3dSmrg DBG(("%s: triangles do not intersect drawable clips\n", 1338428d7b3dSmrg __FUNCTION__)) ; 1339428d7b3dSmrg return true; 1340428d7b3dSmrg } 1341428d7b3dSmrg 1342428d7b3dSmrg dx = dst->pDrawable->x; 1343428d7b3dSmrg dy = dst->pDrawable->y; 1344428d7b3dSmrg 1345428d7b3dSmrg DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n", 1346428d7b3dSmrg __FUNCTION__, 1347428d7b3dSmrg mono.clip.extents.x1, mono.clip.extents.y1, 1348428d7b3dSmrg mono.clip.extents.x2, mono.clip.extents.y2, 1349428d7b3dSmrg dx, dy, 1350428d7b3dSmrg src_x + mono.clip.extents.x1 - dst_x - dx, 1351428d7b3dSmrg src_y + mono.clip.extents.y1 - dst_y - dy)); 1352428d7b3dSmrg 1353428d7b3dSmrg was_clear = sna_drawable_is_clear(dst->pDrawable); 1354428d7b3dSmrg 1355428d7b3dSmrg if (!mono_init(&mono, 3*count)) 1356428d7b3dSmrg return false; 1357428d7b3dSmrg 1358428d7b3dSmrg for (n = 0; n < count; n++) { 1359428d7b3dSmrg mono_add_line(&mono, dx, dy, 1360428d7b3dSmrg tri[n].p1.y, tri[n].p2.y, 1361428d7b3dSmrg &tri[n].p1, &tri[n].p2, 1); 1362428d7b3dSmrg mono_add_line(&mono, dx, dy, 1363428d7b3dSmrg tri[n].p2.y, tri[n].p3.y, 1364428d7b3dSmrg &tri[n].p2, &tri[n].p3, 1); 1365428d7b3dSmrg mono_add_line(&mono, dx, dy, 1366428d7b3dSmrg tri[n].p3.y, tri[n].p1.y, 1367428d7b3dSmrg &tri[n].p3, &tri[n].p1, 1); 1368428d7b3dSmrg } 1369428d7b3dSmrg 1370428d7b3dSmrg if (mono.sna->render.composite(mono.sna, op, src, NULL, dst, 1371428d7b3dSmrg src_x + mono.clip.extents.x1 - dst_x - dx, 1372428d7b3dSmrg src_y + mono.clip.extents.y1 - dst_y - dy, 1373428d7b3dSmrg 0, 0, 1374428d7b3dSmrg mono.clip.extents.x1, mono.clip.extents.y1, 1375428d7b3dSmrg mono.clip.extents.x2 - mono.clip.extents.x1, 1376428d7b3dSmrg mono.clip.extents.y2 - mono.clip.extents.y1, 1377428d7b3dSmrg COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) { 1378428d7b3dSmrg if (mono.clip.data == NULL && mono.op.damage == NULL) 1379428d7b3dSmrg mono.span = mono_span__fast; 1380428d7b3dSmrg else 1381428d7b3dSmrg mono.span = mono_span; 1382428d7b3dSmrg mono_render(&mono); 1383428d7b3dSmrg mono.op.done(mono.sna, &mono.op); 1384428d7b3dSmrg } 1385428d7b3dSmrg 1386428d7b3dSmrg if (!was_clear && !operator_is_bounded(op)) { 1387428d7b3dSmrg xPointFixed p1, p2; 1388428d7b3dSmrg 1389428d7b3dSmrg if (!mono_init(&mono, 2+3*count)) 1390428d7b3dSmrg return false; 1391428d7b3dSmrg 1392428d7b3dSmrg p1.y = mono.clip.extents.y1 * pixman_fixed_1; 1393428d7b3dSmrg p2.y = mono.clip.extents.y2 * pixman_fixed_1; 1394428d7b3dSmrg 1395428d7b3dSmrg p1.x = mono.clip.extents.x1 * pixman_fixed_1; 1396428d7b3dSmrg p2.x = mono.clip.extents.x1 * pixman_fixed_1; 1397428d7b3dSmrg mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, -1); 1398428d7b3dSmrg 1399428d7b3dSmrg p1.x = mono.clip.extents.x2 * pixman_fixed_1; 1400428d7b3dSmrg p2.x = mono.clip.extents.x2 * pixman_fixed_1; 1401428d7b3dSmrg mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, 1); 1402428d7b3dSmrg 1403428d7b3dSmrg for (n = 0; n < count; n++) { 1404428d7b3dSmrg mono_add_line(&mono, dx, dy, 1405428d7b3dSmrg tri[n].p1.y, tri[n].p2.y, 1406428d7b3dSmrg &tri[n].p1, &tri[n].p2, 1); 1407428d7b3dSmrg mono_add_line(&mono, dx, dy, 1408428d7b3dSmrg tri[n].p2.y, tri[n].p3.y, 1409428d7b3dSmrg &tri[n].p2, &tri[n].p3, 1); 1410428d7b3dSmrg mono_add_line(&mono, dx, dy, 1411428d7b3dSmrg tri[n].p3.y, tri[n].p1.y, 1412428d7b3dSmrg &tri[n].p3, &tri[n].p1, 1); 1413428d7b3dSmrg } 1414428d7b3dSmrg 1415428d7b3dSmrg if (mono.sna->render.composite(mono.sna, 1416428d7b3dSmrg PictOpClear, 1417428d7b3dSmrg mono.sna->clear, NULL, dst, 1418428d7b3dSmrg 0, 0, 1419428d7b3dSmrg 0, 0, 1420428d7b3dSmrg mono.clip.extents.x1, mono.clip.extents.y1, 1421428d7b3dSmrg mono.clip.extents.x2 - mono.clip.extents.x1, 1422428d7b3dSmrg mono.clip.extents.y2 - mono.clip.extents.y1, 1423428d7b3dSmrg COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) { 1424428d7b3dSmrg if (mono.clip.data == NULL && mono.op.damage == NULL) 1425428d7b3dSmrg mono.span = mono_span__fast; 1426428d7b3dSmrg else 1427428d7b3dSmrg mono.span = mono_span; 1428428d7b3dSmrg mono_render(&mono); 1429428d7b3dSmrg mono.op.done(mono.sna, &mono.op); 1430428d7b3dSmrg } 1431428d7b3dSmrg mono_fini(&mono); 1432428d7b3dSmrg } 1433428d7b3dSmrg 1434428d7b3dSmrg mono_fini(&mono); 1435428d7b3dSmrg REGION_UNINIT(NULL, &mono.clip); 1436428d7b3dSmrg return true; 1437428d7b3dSmrg} 1438428d7b3dSmrg 1439428d7b3dSmrgbool 1440428d7b3dSmrgmono_tristrip_span_converter(struct sna *sna, 1441428d7b3dSmrg CARD8 op, PicturePtr src, PicturePtr dst, 1442428d7b3dSmrg INT16 src_x, INT16 src_y, 1443428d7b3dSmrg int count, xPointFixed *points) 1444428d7b3dSmrg{ 1445428d7b3dSmrg struct mono mono; 1446428d7b3dSmrg BoxRec extents; 1447428d7b3dSmrg int16_t dst_x, dst_y; 1448428d7b3dSmrg int16_t dx, dy; 1449428d7b3dSmrg bool was_clear; 1450428d7b3dSmrg int n; 1451428d7b3dSmrg 1452428d7b3dSmrg mono.sna = sna; 1453428d7b3dSmrg 1454428d7b3dSmrg dst_x = pixman_fixed_to_int(points[0].x); 1455428d7b3dSmrg dst_y = pixman_fixed_to_int(points[0].y); 1456428d7b3dSmrg 1457428d7b3dSmrg miPointFixedBounds(count, points, &extents); 1458428d7b3dSmrg DBG(("%s: extents (%d, %d), (%d, %d)\n", 1459428d7b3dSmrg __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 1460428d7b3dSmrg 1461428d7b3dSmrg if (extents.y1 >= extents.y2 || extents.x1 >= extents.x2) 1462428d7b3dSmrg return true; 1463428d7b3dSmrg 1464428d7b3dSmrg if (!sna_compute_composite_region(&mono.clip, 1465428d7b3dSmrg src, NULL, dst, 1466428d7b3dSmrg src_x + extents.x1 - dst_x, 1467428d7b3dSmrg src_y + extents.y1 - dst_y, 1468428d7b3dSmrg 0, 0, 1469428d7b3dSmrg extents.x1, extents.y1, 1470428d7b3dSmrg extents.x2 - extents.x1, 1471428d7b3dSmrg extents.y2 - extents.y1)) { 1472428d7b3dSmrg DBG(("%s: triangles do not intersect drawable clips\n", 1473428d7b3dSmrg __FUNCTION__)) ; 1474428d7b3dSmrg return true; 1475428d7b3dSmrg } 1476428d7b3dSmrg 1477428d7b3dSmrg dx = dst->pDrawable->x; 1478428d7b3dSmrg dy = dst->pDrawable->y; 1479428d7b3dSmrg 1480428d7b3dSmrg DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n", 1481428d7b3dSmrg __FUNCTION__, 1482428d7b3dSmrg mono.clip.extents.x1, mono.clip.extents.y1, 1483428d7b3dSmrg mono.clip.extents.x2, mono.clip.extents.y2, 1484428d7b3dSmrg dx, dy, 1485428d7b3dSmrg src_x + mono.clip.extents.x1 - dst_x - dx, 1486428d7b3dSmrg src_y + mono.clip.extents.y1 - dst_y - dy)); 1487428d7b3dSmrg 1488428d7b3dSmrg was_clear = sna_drawable_is_clear(dst->pDrawable); 1489428d7b3dSmrg 1490428d7b3dSmrg if (!mono_init(&mono, 2*count)) 1491428d7b3dSmrg return false; 1492428d7b3dSmrg 1493428d7b3dSmrg mono_add_line(&mono, dx, dy, 1494428d7b3dSmrg points[0].y, points[1].y, 1495428d7b3dSmrg &points[0], &points[1], -1); 1496428d7b3dSmrg n = 2; 1497428d7b3dSmrg do { 1498428d7b3dSmrg mono_add_line(&mono, dx, dy, 1499428d7b3dSmrg points[n-2].y, points[n].y, 1500428d7b3dSmrg &points[n-2], &points[n], 1); 1501428d7b3dSmrg if (++n == count) 1502428d7b3dSmrg break; 1503428d7b3dSmrg 1504428d7b3dSmrg mono_add_line(&mono, dx, dy, 1505428d7b3dSmrg points[n-2].y, points[n].y, 1506428d7b3dSmrg &points[n-2], &points[n], -1); 1507428d7b3dSmrg if (++n == count) 1508428d7b3dSmrg break; 1509428d7b3dSmrg } while (1); 1510428d7b3dSmrg mono_add_line(&mono, dx, dy, 1511428d7b3dSmrg points[n-2].y, points[n-1].y, 1512428d7b3dSmrg &points[n-2], &points[n-1], 1); 1513428d7b3dSmrg 1514428d7b3dSmrg if (mono.sna->render.composite(mono.sna, op, src, NULL, dst, 1515428d7b3dSmrg src_x + mono.clip.extents.x1 - dst_x - dx, 1516428d7b3dSmrg src_y + mono.clip.extents.y1 - dst_y - dy, 1517428d7b3dSmrg 0, 0, 1518428d7b3dSmrg mono.clip.extents.x1, mono.clip.extents.y1, 1519428d7b3dSmrg mono.clip.extents.x2 - mono.clip.extents.x1, 1520428d7b3dSmrg mono.clip.extents.y2 - mono.clip.extents.y1, 1521428d7b3dSmrg COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) { 1522428d7b3dSmrg if (mono.clip.data == NULL && mono.op.damage == NULL) 1523428d7b3dSmrg mono.span = mono_span__fast; 1524428d7b3dSmrg else 1525428d7b3dSmrg mono.span = mono_span; 1526428d7b3dSmrg mono_render(&mono); 1527428d7b3dSmrg mono.op.done(mono.sna, &mono.op); 1528428d7b3dSmrg } 1529428d7b3dSmrg 1530428d7b3dSmrg if (!was_clear && !operator_is_bounded(op)) { 1531428d7b3dSmrg xPointFixed p1, p2; 1532428d7b3dSmrg 1533428d7b3dSmrg if (!mono_init(&mono, 2+2*count)) 1534428d7b3dSmrg return false; 1535428d7b3dSmrg 1536428d7b3dSmrg p1.y = mono.clip.extents.y1 * pixman_fixed_1; 1537428d7b3dSmrg p2.y = mono.clip.extents.y2 * pixman_fixed_1; 1538428d7b3dSmrg 1539428d7b3dSmrg p1.x = mono.clip.extents.x1 * pixman_fixed_1; 1540428d7b3dSmrg p2.x = mono.clip.extents.x1 * pixman_fixed_1; 1541428d7b3dSmrg mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, -1); 1542428d7b3dSmrg 1543428d7b3dSmrg p1.x = mono.clip.extents.x2 * pixman_fixed_1; 1544428d7b3dSmrg p2.x = mono.clip.extents.x2 * pixman_fixed_1; 1545428d7b3dSmrg mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, 1); 1546428d7b3dSmrg 1547428d7b3dSmrg mono_add_line(&mono, dx, dy, 1548428d7b3dSmrg points[0].y, points[1].y, 1549428d7b3dSmrg &points[0], &points[1], -1); 1550428d7b3dSmrg n = 2; 1551428d7b3dSmrg do { 1552428d7b3dSmrg mono_add_line(&mono, dx, dy, 1553428d7b3dSmrg points[n-2].y, points[n].y, 1554428d7b3dSmrg &points[n-2], &points[n], 1); 1555428d7b3dSmrg if (++n == count) 1556428d7b3dSmrg break; 1557428d7b3dSmrg 1558428d7b3dSmrg mono_add_line(&mono, dx, dy, 1559428d7b3dSmrg points[n-2].y, points[n].y, 1560428d7b3dSmrg &points[n-2], &points[n], -1); 1561428d7b3dSmrg if (++n == count) 1562428d7b3dSmrg break; 1563428d7b3dSmrg } while (1); 1564428d7b3dSmrg mono_add_line(&mono, dx, dy, 1565428d7b3dSmrg points[n-2].y, points[n-1].y, 1566428d7b3dSmrg &points[n-2], &points[n-1], 1); 1567428d7b3dSmrg 1568428d7b3dSmrg if (mono.sna->render.composite(mono.sna, 1569428d7b3dSmrg PictOpClear, 1570428d7b3dSmrg mono.sna->clear, NULL, dst, 1571428d7b3dSmrg 0, 0, 1572428d7b3dSmrg 0, 0, 1573428d7b3dSmrg mono.clip.extents.x1, mono.clip.extents.y1, 1574428d7b3dSmrg mono.clip.extents.x2 - mono.clip.extents.x1, 1575428d7b3dSmrg mono.clip.extents.y2 - mono.clip.extents.y1, 1576428d7b3dSmrg COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) { 1577428d7b3dSmrg if (mono.clip.data == NULL && mono.op.damage == NULL) 1578428d7b3dSmrg mono.span = mono_span__fast; 1579428d7b3dSmrg else 1580428d7b3dSmrg mono.span = mono_span; 1581428d7b3dSmrg mono_render(&mono); 1582428d7b3dSmrg mono.op.done(mono.sna, &mono.op); 1583428d7b3dSmrg } 1584428d7b3dSmrg mono_fini(&mono); 1585428d7b3dSmrg } 1586428d7b3dSmrg 1587428d7b3dSmrg mono_fini(&mono); 1588428d7b3dSmrg REGION_UNINIT(NULL, &mono.clip); 1589428d7b3dSmrg return true; 1590428d7b3dSmrg} 1591