diff --git a/src/sna/sna_trapezoids_imprecise.c b/src/sna/sna_trapezoids_imprecise.c index 4e90f9c4..8bc7c8a8 100644 --- a/src/sna/sna_trapezoids_imprecise.c +++ b/src/sna/sna_trapezoids_imprecise.c @@ -1707,8 +1707,7 @@ static void span_thread_add_box(struct sna *sna, void *data, { struct span_thread_boxes *b = data; - __DBG(("%s: adding %d boxes with alpha=%f\n", - __FUNCTION__, count, alpha)); + __DBG(("%s: adding box with alpha=%f\n", __FUNCTION__, alpha)); if (unlikely(b->num_boxes == SPAN_THREAD_MAX_BOXES)) { DBG(("%s: flushing %d boxes\n", __FUNCTION__, b->num_boxes)); diff --git a/src/sna/sna_trapezoids_mono.c b/src/sna/sna_trapezoids_mono.c index 5b65fa45..07a7867d 100644 --- a/src/sna/sna_trapezoids_mono.c +++ b/src/sna/sna_trapezoids_mono.c @@ -79,7 +79,7 @@ struct mono { struct mono_polygon polygon; }; -#define I(x) pixman_fixed_to_int ((x) + pixman_fixed_1_minus_e/2) +#define I(x) pixman_fixed_to_int((x) + pixman_fixed_1_minus_e/2) static struct quorem floored_muldivrem(int32_t x, int32_t a, int32_t b) @@ -250,22 +250,22 @@ mono_add_line(struct mono *mono, e->dxdy = floored_muldivrem(dx, pixman_fixed_1, dy); - e->x = floored_muldivrem((ytop - dst_y) * pixman_fixed_1 + pixman_fixed_1_minus_e/2 - p1->y, + e->x = floored_muldivrem((ytop - dst_y) * pixman_fixed_1 + pixman_fixed_1/2 - p1->y, dx, dy); e->x.quo += p1->x; e->x.rem -= dy; e->dy = dy; - - __DBG(("%s: initial x=%d [%d.%d/%d] + dxdy=%d.%d/%d\n", - __FUNCTION__, - I(e->x.quo), e->x.quo, e->x.rem, e->dy, - e->dxdy.quo, e->dxdy.rem, e->dy)); } e->x.quo += dst_x*pixman_fixed_1; + __DBG(("%s: initial x=%d [%d.%d/%d] + dxdy=%d.%d/%d\n", + __FUNCTION__, + I(e->x.quo), e->x.quo, e->x.rem, e->dy, + e->dxdy.quo, e->dxdy.rem, e->dy)); { struct mono_edge **ptail = &polygon->y_buckets[ytop - mono->clip.extents.y1]; + assert(ytop - mono->clip.extents.y1 < mono->clip.extents.y2 - mono->clip.extents.y1); if (*ptail) (*ptail)->prev = e; e->next = *ptail; @@ -369,6 +369,10 @@ static struct mono_edge *mono_filter(struct mono_edge *edges) e->x.rem == n->x.rem && e->dxdy.quo == n->dxdy.quo && e->dxdy.rem == n->dxdy.rem) { + assert(e->dy == n->dy); + __DBG(("%s: discarding cancellation pair (%d.%d) + (%d.%d)\n", + __FUNCTION__, e->x.quo, e->x.rem, e->dxdy.quo, e->dxdy.rem)); + if (e->prev) e->prev->next = n->next; else @@ -379,8 +383,11 @@ static struct mono_edge *mono_filter(struct mono_edge *edges) break; e = n->next; - } else + } else { + __DBG(("%s: adding edge (%d.%d) + (%d.%d)/%d, height=%d\n", + __FUNCTION__, n->x.quo, n->x.rem, n->dxdy.quo, n->dxdy.rem, n->dy, n->height_left)); e = n; + } } return edges; @@ -571,6 +578,8 @@ mono_row(struct mono *c, int16_t y, int16_t h) int winding = 0; BoxRec box; + __DBG(("%s: y=%d, h=%d\n", __FUNCTION__, y, h)); + DBG_MONO_EDGES(edge); VALIDATE_MONO_EDGES(&c->head); @@ -581,6 +590,8 @@ mono_row(struct mono *c, int16_t y, int16_t h) struct mono_edge *next = edge->next; int16_t xend = I(edge->x.quo); + __DBG(("%s: adding edge dir=%d [winding=%d], x=%d [%d]\n", + __FUNCTION__, edge->dir, winding + edge->dir, xend, edge->x.quo)); if (--edge->height_left) { if (edge->dy) { edge->x.quo += edge->dxdy.quo; @@ -589,6 +600,8 @@ mono_row(struct mono *c, int16_t y, int16_t h) ++edge->x.quo; edge->x.rem -= edge->dy; } + __DBG(("%s: stepped edge (%d.%d) + (%d.%d)/%d, height=%d, prev_x=%d\n", + __FUNCTION__, edge->x.quo, edge->x.rem, edge->dxdy.quo, edge->dxdy.rem, edge->dy, edge->height_left, edge->x.quo)); } if (edge->x.quo < prev_x) { @@ -612,17 +625,22 @@ mono_row(struct mono *c, int16_t y, int16_t h) winding += edge->dir; if (winding == 0) { assert(I(next->x.quo) >= xend); - if (I(next->x.quo) > xend + 1) { + if (I(next->x.quo) > xend) { + __DBG(("%s: end span: %d\n", __FUNCTION__, xend)); if (xstart < c->clip.extents.x1) xstart = c->clip.extents.x1; if (xend > c->clip.extents.x2) xend = c->clip.extents.x2; - if (xend > xstart) + if (xend > xstart) { + __DBG(("%s: emit span [%d, %d]\n", __FUNCTION__, xstart, xend)); c->span(c, xstart, xend, &box); + } xstart = INT16_MIN; } - } else if (xstart == INT16_MIN) + } else if (xstart == INT16_MIN) { + __DBG(("%s: starting new span: %d\n", __FUNCTION__, xend)); xstart = xend; + } edge = next; } @@ -684,9 +702,14 @@ mono_render(struct mono *mono) for (i = 0; i < h; i = j) { j = i + 1; + __DBG(("%s: row=%d, new edges? %d\n", __FUNCTION__, + i, polygon->y_buckets[i] != NULL)); + if (polygon->y_buckets[i]) mono_merge_edges(mono, polygon->y_buckets[i]); + __DBG(("%s: row=%d, vertical? %d\n", __FUNCTION__, + i, mono->is_vertical)); if (mono->is_vertical) { struct mono_edge *e = mono->head.next; int min_height = h - i; @@ -701,6 +724,7 @@ mono_render(struct mono *mono) j++; if (j != i + 1) mono_step_edges(mono, j - (i + 1)); + __DBG(("%s: %d vertical rows\n", __FUNCTION__, j-i)); } mono_row(mono, i, j-i); @@ -1423,10 +1447,13 @@ mono_triangles_span_converter(struct sna *sna, mono_render(&mono); mono.op.done(mono.sna, &mono.op); } + mono_fini(&mono); if (!was_clear && !operator_is_bounded(op)) { xPointFixed p1, p2; + DBG(("%s: performing unbounded clear\n", __FUNCTION__)); + if (!mono_init(&mono, 2+3*count)) return false; @@ -1472,7 +1499,6 @@ mono_triangles_span_converter(struct sna *sna, mono_fini(&mono); } - mono_fini(&mono); REGION_UNINIT(NULL, &mono.clip); return true; } diff --git a/src/sna/sna_trapezoids_precise.c b/src/sna/sna_trapezoids_precise.c index c9838528..242b4acb 100644 --- a/src/sna/sna_trapezoids_precise.c +++ b/src/sna/sna_trapezoids_precise.c @@ -1655,8 +1655,7 @@ static void span_thread_add_box(struct sna *sna, void *data, { struct span_thread_boxes *b = data; - __DBG(("%s: adding %d boxes with alpha=%f\n", - __FUNCTION__, count, alpha)); + __DBG(("%s: adding box with alpha=%f\n", __FUNCTION__, alpha)); if (unlikely(b->num_boxes == SPAN_THREAD_MAX_BOXES)) { DBG(("%s: flushing %d boxes\n", __FUNCTION__, b->num_boxes)); diff --git a/test/.gitignore b/test/.gitignore index 373ba15e..2a68c3dc 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -11,6 +11,7 @@ cursor-test render-fill render-trapezoid render-trapezoid-image +render-triangle render-fill-copy render-composite-solid render-composite-solid-mask diff --git a/test/Makefile.am b/test/Makefile.am index aaa656af..50f2126a 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -15,6 +15,7 @@ stress_TESTS = \ render-glyphs \ render-trapezoid \ render-trapezoid-image \ + render-triangle \ render-fill-copy \ render-composite-solid \ render-composite-solid-mask \ diff --git a/test/render-triangle.c b/test/render-triangle.c new file mode 100644 index 00000000..165834ce --- /dev/null +++ b/test/render-triangle.c @@ -0,0 +1,180 @@ +#include +#include +#include + +#include "test.h" + +enum edge { + EDGE_SHARP = PolyEdgeSharp, + EDGE_SMOOTH, +}; + +static void set_edge(Display *dpy, Picture p, enum edge edge) +{ + XRenderPictureAttributes a; + + a.poly_edge = edge; + XRenderChangePicture(dpy, p, CPPolyEdge, &a); +} + +static XRenderPictFormat *mask_format(Display *dpy, enum mask mask) +{ + switch (mask) { + default: + case MASK_NONE: return NULL; + case MASK_A1: return XRenderFindStandardFormat(dpy, PictStandardA1); + case MASK_A8: return XRenderFindStandardFormat(dpy, PictStandardA8); + } +} + +static const char *mask_name(enum mask mask) +{ + switch (mask) { + default: + case MASK_NONE: return "none"; + case MASK_A1: return "a1"; + case MASK_A8: return "a8"; + } +} + +static const char *edge_name(enum edge edge) +{ + switch (edge) { + default: + case EDGE_SHARP: return "sharp"; + case EDGE_SMOOTH: return "smooth"; + } +} + +static void clear(struct test_display *dpy, struct test_target *tt) +{ + XRenderColor render_color = {0}; + XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color, + 0, 0, tt->width, tt->height); +} + +static void step_to_point(int step, int width, int height, XPointFixed *p) +{ + do { + p->x = (step - 64) << 16; + p->y = -64 << 16; + + step -= width - 128; + if (step <= 0) + return; + + p->x = (width + 64) << 16; + p->y = (step - 64) << 16; + step -= height - 128; + + if (step <= 0) + return; + + p->x = (width + 64 - step) << 16; + p->y = (height + 64) << 16; + step -= width - 128; + + if (step <= 0) + return; + + p->x = -64 << 16; + p->y = (height + 64 - step) << 16; + step -= height - 128; + } while (step > 0); +} + +static void edge_test(struct test *t, + enum mask mask, + enum edge edge, + enum target target) +{ + struct test_target out, ref; + XRenderColor white = { 0xffff, 0xffff, 0xffff, 0xffff }; + Picture src_ref, src_out; + XTriangle tri; + unsigned step, max; + + test_target_create_render(&t->out, target, &out); + set_edge(t->out.dpy, out.picture, edge); + src_out = XRenderCreateSolidFill(t->out.dpy, &white); + + test_target_create_render(&t->ref, target, &ref); + set_edge(t->ref.dpy, ref.picture, edge); + src_ref = XRenderCreateSolidFill(t->ref.dpy, &white); + + printf("Testing edges (with mask %s and %s edges) (%s): ", + mask_name(mask), + edge_name(edge), + test_target_name(target)); + fflush(stdout); + + max = 2*(out.width + 128 + out.height+128); + step = 0; + for (step = 0; step <= max; step++) { + char buf[80]; + + step_to_point(step, out.width, out.height, &tri.p1); + step_to_point(step + out.width + 128, + out.width, out.height, + &tri.p2); + step_to_point(step + out.height + 128 + 2*(out.width + 128), + out.width, out.height, + &tri.p3); + + sprintf(buf, + "tri=((%d, %d), (%d, %d), (%d, %d))\n", + tri.p1.x >> 16, tri.p1.y >> 16, + tri.p2.x >> 16, tri.p2.y >> 16, + tri.p3.x >> 16, tri.p3.y >> 16); + + clear(&t->out, &out); + XRenderCompositeTriangles(t->out.dpy, + PictOpSrc, + src_out, + out.picture, + mask_format(t->out.dpy, mask), + 0, 0, + &tri, 1); + + clear(&t->ref, &ref); + XRenderCompositeTriangles(t->ref.dpy, + PictOpSrc, + src_ref, + ref.picture, + mask_format(t->ref.dpy, mask), + 0, 0, + &tri, 1); + + test_compare(t, + out.draw, out.format, + ref.draw, ref.format, + 0, 0, out.width, out.height, + buf); + } + + XRenderFreePicture(t->out.dpy, src_out); + test_target_destroy_render(&t->out, &out); + + XRenderFreePicture(t->ref.dpy, src_ref); + test_target_destroy_render(&t->ref, &ref); + + printf("pass\n"); +} + +int main(int argc, char **argv) +{ + struct test test; + enum target target; + enum mask mask; + enum edge edge; + + test_init(&test, argc, argv); + + for (target = TARGET_FIRST; target <= TARGET_LAST; target++) { + for (mask = MASK_NONE; mask <= MASK_A8; mask++) + for (edge = EDGE_SHARP; edge <= EDGE_SMOOTH; edge++) + edge_test(&test, mask, edge, target); + } + + return 0; +}