diff options
-rw-r--r-- | src/sna/sna_trapezoids.h | 32 | ||||
-rw-r--r-- | src/sna/sna_trapezoids_imprecise.c | 23 | ||||
-rw-r--r-- | src/sna/sna_trapezoids_mono.c | 159 | ||||
-rw-r--r-- | src/sna/sna_trapezoids_precise.c | 344 |
4 files changed, 533 insertions, 25 deletions
diff --git a/src/sna/sna_trapezoids.h b/src/sna/sna_trapezoids.h index 5acf5317..e8f7f3f4 100644 --- a/src/sna/sna_trapezoids.h +++ b/src/sna/sna_trapezoids.h @@ -227,10 +227,37 @@ triangles_mask_converter(CARD8 op, PicturePtr src, PicturePtr dst, int count, xTriangle *tri); bool +mono_tristrip_span_converter(struct sna *sna, + CARD8 op, PicturePtr src, PicturePtr dst, + INT16 src_x, INT16 src_y, + int count, xPointFixed *points); +bool +imprecise_tristrip_span_converter(struct sna *sna, + CARD8 op, PicturePtr src, PicturePtr dst, + PictFormatPtr maskFormat, INT16 src_x, INT16 src_y, + int count, xPointFixed *points); +bool +precise_tristrip_span_converter(struct sna *sna, + CARD8 op, PicturePtr src, PicturePtr dst, + PictFormatPtr maskFormat, INT16 src_x, INT16 src_y, + int count, xPointFixed *points); + +static inline bool tristrip_span_converter(struct sna *sna, CARD8 op, PicturePtr src, PicturePtr dst, PictFormatPtr maskFormat, INT16 src_x, INT16 src_y, - int count, xPointFixed *points); + int count, xPointFixed *points) +{ + if (NO_SCAN_CONVERTER) + return false; + + if (is_mono(dst, maskFormat)) + return mono_tristrip_span_converter(sna, op, src, dst, src_x, src_y, count, points); + else if (is_precise(dst, maskFormat)) + return precise_tristrip_span_converter(sna, op, src, dst, maskFormat, src_x, src_y, count, points); + else + return imprecise_tristrip_span_converter(sna, op, src, dst, maskFormat, src_x, src_y, count, points); +} inline static void trapezoid_origin(const xLineFixed *l, int16_t *x, int16_t *y) { @@ -332,8 +359,7 @@ xTriangleValid(const xTriangle *t) static inline int pixman_fixed_to_fast(pixman_fixed_t v) { - //return (v + ((1<<(16-FAST_SAMPLES_shift-1))-1)) >> (16 - FAST_SAMPLES_shift); - return (v + ((1<<(16-FAST_SAMPLES_shift-1)))) >> (16 - FAST_SAMPLES_shift); + return (v + ((1<<(16-FAST_SAMPLES_shift-1))-1)) >> (16 - FAST_SAMPLES_shift); } bool trapezoids_bounds(int n, const xTrapezoid *t, BoxPtr box); diff --git a/src/sna/sna_trapezoids_imprecise.c b/src/sna/sna_trapezoids_imprecise.c index 8bb54265..82306651 100644 --- a/src/sna/sna_trapezoids_imprecise.c +++ b/src/sna/sna_trapezoids_imprecise.c @@ -42,7 +42,7 @@ #undef SAMPLES_X #undef SAMPLES_Y -#if 1 +#if 0 #define __DBG DBG #else #define __DBG(x) @@ -633,6 +633,7 @@ polygon_add_line(struct polygon *polygon, unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop, polygon->ymin); polygon->y_buckets[ix] = prev->next; + polygon->num_edges--; return; } } @@ -1940,7 +1941,7 @@ imprecise_trapezoid_span_converter(struct sna *sna, dy *= FAST_SAMPLES_Y; num_threads = 1; - if (!NO_GPU_THREADS && 0 && + if (!NO_GPU_THREADS && (flags & COMPOSITE_SPANS_RECTILINEAR) == 0 && tmp.thread_boxes && thread_choose_span(&tmp, dst, maskFormat, &clip)) @@ -3876,10 +3877,10 @@ tristrip_thread(void *arg) } bool -tristrip_span_converter(struct sna *sna, - CARD8 op, PicturePtr src, PicturePtr dst, - PictFormatPtr maskFormat, INT16 src_x, INT16 src_y, - int count, xPointFixed *points) +imprecise_tristrip_span_converter(struct sna *sna, + CARD8 op, PicturePtr src, PicturePtr dst, + PictFormatPtr maskFormat, INT16 src_x, INT16 src_y, + int count, xPointFixed *points) { struct sna_composite_spans_op tmp; BoxRec extents; @@ -3888,16 +3889,6 @@ tristrip_span_converter(struct sna *sna, int dx, dy, num_threads; bool was_clear; - if (NO_SCAN_CONVERTER) - return false; - - /* XXX strict adherence to the Render specification */ - if (is_precise(dst, maskFormat)) { - DBG(("%s: fallback -- precise rasterisation requested\n", - __FUNCTION__)); - return false; - } - if (!sna->render.check_composite_spans(sna, op, src, dst, 0, 0, 0)) { DBG(("%s: fallback -- composite spans not supported\n", __FUNCTION__)); diff --git a/src/sna/sna_trapezoids_mono.c b/src/sna/sna_trapezoids_mono.c index acd2b101..d53e5359 100644 --- a/src/sna/sna_trapezoids_mono.c +++ b/src/sna/sna_trapezoids_mono.c @@ -356,7 +356,7 @@ static struct mono_edge *mono_filter(struct mono_edge *edges) struct mono_edge *e; e = edges; - do { + while (e->next) { struct mono_edge *n = e->next; if (e->dir == -n->dir && e->height_left == n->height_left && @@ -373,8 +373,8 @@ static struct mono_edge *mono_filter(struct mono_edge *edges) e = n->next; } else - e = e->next; - } while (e->next); + e = n; + } return edges; } @@ -1425,3 +1425,156 @@ mono_triangles_span_converter(struct sna *sna, REGION_UNINIT(NULL, &mono.clip); return true; } + +bool +mono_tristrip_span_converter(struct sna *sna, + CARD8 op, PicturePtr src, PicturePtr dst, + INT16 src_x, INT16 src_y, + int count, xPointFixed *points) +{ + struct mono mono; + BoxRec extents; + int16_t dst_x, dst_y; + int16_t dx, dy; + bool was_clear; + int n; + + mono.sna = sna; + + dst_x = pixman_fixed_to_int(points[0].x); + dst_y = pixman_fixed_to_int(points[0].y); + + miPointFixedBounds(count, points, &extents); + DBG(("%s: extents (%d, %d), (%d, %d)\n", + __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); + + if (extents.y1 >= extents.y2 || extents.x1 >= extents.x2) + return true; + + if (!sna_compute_composite_region(&mono.clip, + src, NULL, dst, + src_x + extents.x1 - dst_x, + src_y + extents.y1 - dst_y, + 0, 0, + extents.x1, extents.y1, + extents.x2 - extents.x1, + extents.y2 - extents.y1)) { + DBG(("%s: triangles do not intersect drawable clips\n", + __FUNCTION__)) ; + return true; + } + + dx = dst->pDrawable->x; + dy = dst->pDrawable->y; + + DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n", + __FUNCTION__, + mono.clip.extents.x1, mono.clip.extents.y1, + mono.clip.extents.x2, mono.clip.extents.y2, + dx, dy, + src_x + mono.clip.extents.x1 - dst_x - dx, + src_y + mono.clip.extents.y1 - dst_y - dy)); + + was_clear = sna_drawable_is_clear(dst->pDrawable); + + if (!mono_init(&mono, 2*count)) + return false; + + mono_add_line(&mono, dx, dy, + points[0].y, points[1].y, + &points[0], &points[1], -1); + n = 2; + do { + mono_add_line(&mono, dx, dy, + points[n-2].y, points[n].y, + &points[n-2], &points[n], 1); + if (++n == count) + break; + + mono_add_line(&mono, dx, dy, + points[n-2].y, points[n].y, + &points[n-2], &points[n], -1); + if (++n == count) + break; + } while (1); + mono_add_line(&mono, dx, dy, + points[n-2].y, points[n-1].y, + &points[n-2], &points[n-1], 1); + + if (mono.sna->render.composite(mono.sna, op, src, NULL, dst, + src_x + mono.clip.extents.x1 - dst_x - dx, + src_y + mono.clip.extents.y1 - dst_y - dy, + 0, 0, + mono.clip.extents.x1, mono.clip.extents.y1, + mono.clip.extents.x2 - mono.clip.extents.x1, + mono.clip.extents.y2 - mono.clip.extents.y1, + COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) { + if (mono.clip.data == NULL && mono.op.damage == NULL) + mono.span = mono_span__fast; + else + mono.span = mono_span; + mono_render(&mono); + mono.op.done(mono.sna, &mono.op); + } + + if (!was_clear && !operator_is_bounded(op)) { + xPointFixed p1, p2; + + if (!mono_init(&mono, 2+2*count)) + return false; + + p1.y = mono.clip.extents.y1 * pixman_fixed_1; + p2.y = mono.clip.extents.y2 * pixman_fixed_1; + + p1.x = mono.clip.extents.x1 * pixman_fixed_1; + p2.x = mono.clip.extents.x1 * pixman_fixed_1; + mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, -1); + + p1.x = mono.clip.extents.x2 * pixman_fixed_1; + p2.x = mono.clip.extents.x2 * pixman_fixed_1; + mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, 1); + + mono_add_line(&mono, dx, dy, + points[0].y, points[1].y, + &points[0], &points[1], -1); + n = 2; + do { + mono_add_line(&mono, dx, dy, + points[n-2].y, points[n].y, + &points[n-2], &points[n], 1); + if (++n == count) + break; + + mono_add_line(&mono, dx, dy, + points[n-2].y, points[n].y, + &points[n-2], &points[n], -1); + if (++n == count) + break; + } while (1); + mono_add_line(&mono, dx, dy, + points[n-2].y, points[n-1].y, + &points[n-2], &points[n-1], 1); + + if (mono.sna->render.composite(mono.sna, + PictOpClear, + mono.sna->clear, NULL, dst, + 0, 0, + 0, 0, + mono.clip.extents.x1, mono.clip.extents.y1, + mono.clip.extents.x2 - mono.clip.extents.x1, + mono.clip.extents.y2 - mono.clip.extents.y1, + COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) { + if (mono.clip.data == NULL && mono.op.damage == NULL) + mono.span = mono_span__fast; + else + mono.span = mono_span; + mono_render(&mono); + mono.op.done(mono.sna, &mono.op); + } + 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 99ed087e..af05fe46 100644 --- a/src/sna/sna_trapezoids_precise.c +++ b/src/sna/sna_trapezoids_precise.c @@ -663,7 +663,7 @@ static struct edge *filter(struct edge *edges) struct edge *e; e = edges; - do { + while (e->next) { struct edge *n = e->next; if (e->dir == -n->dir && e->height_left == n->height_left && @@ -680,8 +680,8 @@ static struct edge *filter(struct edge *edges) e = n->next; } else - e = e->next; - } while (e->next); + e = n; + } return edges; } @@ -3238,3 +3238,341 @@ precise_trapezoid_span_fallback(CARD8 op, PicturePtr src, PicturePtr dst, return true; } + +static inline void +project_point_onto_grid(const xPointFixed *in, + int dx, int dy, + xPointFixed *out) +{ + out->x = dx + pixman_fixed_to_grid_x(in->x); + out->y = dy + pixman_fixed_to_grid_y(in->y); + __DBG(("%s: (%f, %f) -> (%d, %d)\n", + __FUNCTION__, + pixman_fixed_to_double(in->x), + pixman_fixed_to_double(in->y), + out->x, out->y)); +} + +inline static void +polygon_add_line(struct polygon *polygon, + const xPointFixed *p1, + const xPointFixed *p2) +{ + struct edge *e = &polygon->edges[polygon->num_edges]; + int dx = p2->x - p1->x; + int dy = p2->y - p1->y; + int top, bot; + + if (dy == 0) + return; + + __DBG(("%s: line=(%d, %d), (%d, %d)\n", + __FUNCTION__, (int)p1->x, (int)p1->y, (int)p2->x, (int)p2->y)); + + e->dir = 1; + if (dy < 0) { + const xPointFixed *t; + + dx = -dx; + dy = -dy; + + e->dir = -1; + + t = p1; + p1 = p2; + p2 = t; + } + assert (dy > 0); + e->dy = dy; + + top = MAX(p1->y, polygon->ymin); + bot = MIN(p2->y, polygon->ymax); + if (bot <= top) + return; + + e->ytop = top; + e->height_left = bot - top; + if (e->height_left <= 0) + return; + + __DBG(("%s: edge height=%d\n", __FUNCTION__, e->dir * e->height_left)); + + if (dx == 0) { + e->x.quo = p1->x; + e->x.rem = -dy; + e->dxdy.quo = 0; + e->dxdy.rem = 0; + e->dy = 0; + } else { + e->dxdy = floored_divrem(dx, dy); + if (top == p1->y) { + e->x.quo = p1->x; + e->x.rem = -dy; + } else { + e->x = floored_muldivrem(top - p1->y, dx, dy); + e->x.quo += p1->x; + e->x.rem -= dy; + } + } + + if (polygon->num_edges > 0) { + struct edge *prev = &polygon->edges[polygon->num_edges-1]; + /* detect degenerate triangles inserted into tristrips */ + if (e->dir == -prev->dir && + e->ytop == prev->ytop && + e->height_left == prev->height_left && + e->x.quo == prev->x.quo && + e->x.rem == prev->x.rem && + e->dxdy.quo == prev->dxdy.quo && + e->dxdy.rem == prev->dxdy.rem) { + unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop, + polygon->ymin); + polygon->y_buckets[ix] = prev->next; + polygon->num_edges--; + return; + } + } + + _polygon_insert_edge_into_its_y_bucket(polygon, e); + polygon->num_edges++; +} + +struct tristrip_thread { + struct sna *sna; + const struct sna_composite_spans_op *op; + const xPointFixed *points; + RegionPtr clip; + span_func_t span; + BoxRec extents; + int dx, dy, draw_y; + int count; + bool unbounded; +}; + +static void +tristrip_thread(void *arg) +{ + struct tristrip_thread *thread = arg; + struct span_thread_boxes boxes; + struct tor tor; + xPointFixed p[4]; + int n, cw, ccw; + + if (!tor_init(&tor, &thread->extents, 2*thread->count)) + return; + + boxes.op = thread->op; + boxes.num_boxes = 0; + + cw = ccw = 0; + project_point_onto_grid(&thread->points[0], thread->dx, thread->dy, &p[cw]); + project_point_onto_grid(&thread->points[1], thread->dx, thread->dy, &p[2+ccw]); + polygon_add_line(tor.polygon, &p[2+ccw], &p[cw]); + n = 2; + do { + cw = !cw; + project_point_onto_grid(&thread->points[n], thread->dx, thread->dy, &p[cw]); + polygon_add_line(tor.polygon, &p[!cw], &p[cw]); + if (++n == thread->count) + break; + + ccw = !ccw; + project_point_onto_grid(&thread->points[n], thread->dx, thread->dy, &p[2+ccw]); + polygon_add_line(tor.polygon, &p[2+ccw], &p[2+!ccw]); + if (++n == thread->count) + break; + } while (1); + polygon_add_line(tor.polygon, &p[cw], &p[2+ccw]); + assert(tor.polygon->num_edges <= 2*thread->count); + + tor_render(thread->sna, &tor, + (struct sna_composite_spans_op *)&boxes, thread->clip, + thread->span, thread->unbounded); + + tor_fini(&tor); + + if (boxes.num_boxes) { + DBG(("%s: flushing %d boxes\n", __FUNCTION__, boxes.num_boxes)); + assert(boxes.num_boxes <= SPAN_THREAD_MAX_BOXES); + thread->op->thread_boxes(thread->sna, thread->op, + boxes.boxes, boxes.num_boxes); + } +} + +bool +precise_tristrip_span_converter(struct sna *sna, + CARD8 op, PicturePtr src, PicturePtr dst, + PictFormatPtr maskFormat, INT16 src_x, INT16 src_y, + int count, xPointFixed *points) +{ + struct sna_composite_spans_op tmp; + BoxRec extents; + pixman_region16_t clip; + int16_t dst_x, dst_y; + int dx, dy, num_threads; + bool was_clear; + + if (!sna->render.check_composite_spans(sna, op, src, dst, 0, 0, 0)) { + DBG(("%s: fallback -- composite spans not supported\n", + __FUNCTION__)); + return false; + } + + dst_x = pixman_fixed_to_int(points[0].x); + dst_y = pixman_fixed_to_int(points[0].y); + + miPointFixedBounds(count, points, &extents); + DBG(("%s: extents (%d, %d), (%d, %d)\n", + __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); + + if (extents.y1 >= extents.y2 || extents.x1 >= extents.x2) + return true; + +#if 0 + if (extents.y2 - extents.y1 < 64 && extents.x2 - extents.x1 < 64) { + DBG(("%s: fallback -- traps extents too small %dx%d\n", + __FUNCTION__, extents.y2 - extents.y1, extents.x2 - extents.x1)); + return false; + } +#endif + + if (!sna_compute_composite_region(&clip, + src, NULL, dst, + src_x + extents.x1 - dst_x, + src_y + extents.y1 - dst_y, + 0, 0, + extents.x1, extents.y1, + extents.x2 - extents.x1, + extents.y2 - extents.y1)) { + DBG(("%s: triangles do not intersect drawable clips\n", + __FUNCTION__)) ; + return true; + } + + if (!sna->render.check_composite_spans(sna, op, src, dst, + clip.extents.x2 - clip.extents.x1, + clip.extents.y2 - clip.extents.y1, + 0)) { + DBG(("%s: fallback -- composite spans not supported\n", + __FUNCTION__)); + return false; + } + + extents = *RegionExtents(&clip); + dx = dst->pDrawable->x; + dy = dst->pDrawable->y; + + DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n", + __FUNCTION__, + extents.x1, extents.y1, + extents.x2, extents.y2, + dx, dy, + src_x + extents.x1 - dst_x - dx, + src_y + extents.y1 - dst_y - dy)); + + was_clear = sna_drawable_is_clear(dst->pDrawable); + + memset(&tmp, 0, sizeof(tmp)); + if (!sna->render.composite_spans(sna, op, src, dst, + src_x + extents.x1 - dst_x - dx, + src_y + extents.y1 - dst_y - dy, + extents.x1, extents.y1, + extents.x2 - extents.x1, + extents.y2 - extents.y1, + 0, + &tmp)) { + DBG(("%s: fallback -- composite spans render op not supported\n", + __FUNCTION__)); + return false; + } + + dx *= SAMPLES_X; + dy *= SAMPLES_Y; + + num_threads = 1; + if (!NO_GPU_THREADS && 0 && + tmp.thread_boxes && + thread_choose_span(&tmp, dst, maskFormat, &clip)) + num_threads = sna_use_threads(extents.x2 - extents.x1, + extents.y2 - extents.y1, + 16); + if (num_threads == 1) { + struct tor tor; + xPointFixed p[4]; + int cw, ccw, n; + + if (!tor_init(&tor, &extents, 2*count)) + goto skip; + + cw = ccw = 0; + project_point_onto_grid(&points[0], dx, dy, &p[cw]); + project_point_onto_grid(&points[1], dx, dy, &p[2+ccw]); + polygon_add_line(tor.polygon, &p[2+ccw], &p[cw]); + n = 2; + do { + cw = !cw; + project_point_onto_grid(&points[n], dx, dy, &p[cw]); + polygon_add_line(tor.polygon, &p[!cw], &p[cw]); + if (++n == count) + break; + + ccw = !ccw; + project_point_onto_grid(&points[n], dx, dy, &p[2+ccw]); + polygon_add_line(tor.polygon, &p[2+ccw], &p[2+!ccw]); + if (++n == count) + break; + } while (1); + polygon_add_line(tor.polygon, &p[cw], &p[2+ccw]); + assert(tor.polygon->num_edges <= 2*count); + + tor_render(sna, &tor, &tmp, &clip, + choose_span(&tmp, dst, maskFormat, &clip), + !was_clear && maskFormat && !operator_is_bounded(op)); + + tor_fini(&tor); + } else { + struct tristrip_thread threads[num_threads]; + int y, h, n; + + DBG(("%s: using %d threads for tristrip compositing %dx%d\n", + __FUNCTION__, num_threads, + clip.extents.x2 - clip.extents.x1, + clip.extents.y2 - clip.extents.y1)); + + threads[0].sna = sna; + threads[0].op = &tmp; + threads[0].points = points; + threads[0].count = count; + threads[0].extents = clip.extents; + threads[0].clip = &clip; + threads[0].dx = dx; + threads[0].dy = dy; + threads[0].draw_y = dst->pDrawable->y; + threads[0].unbounded = !was_clear && maskFormat && !operator_is_bounded(op); + threads[0].span = thread_choose_span(&tmp, dst, maskFormat, &clip); + + y = clip.extents.y1; + h = clip.extents.y2 - clip.extents.y1; + h = (h + num_threads - 1) / num_threads; + num_threads -= (num_threads-1) * h >= clip.extents.y2 - clip.extents.y1; + + for (n = 1; n < num_threads; n++) { + threads[n] = threads[0]; + threads[n].extents.y1 = y; + threads[n].extents.y2 = y += h; + + sna_threads_run(n, tristrip_thread, &threads[n]); + } + + assert(y < threads[0].extents.y2); + threads[0].extents.y1 = y; + tristrip_thread(&threads[0]); + + sna_threads_wait(); + } +skip: + tmp.done(sna, &tmp); + + REGION_UNINIT(NULL, &clip); + return true; +} |