diff options
author | Martin Robinson <mrobinson@igalia.com> | 2013-01-22 20:09:01 -0800 |
---|---|---|
committer | Martin Robinson <mrobinson@igalia.com> | 2013-01-25 16:30:11 -0800 |
commit | cfe0e59663c71a6ecd0c976797ac32339e363af2 (patch) | |
tree | 3c06863d2673e0a946fc5884b13bb59017fbd133 | |
parent | 1e3424cfd1fea3f9aa2b1c8af4bb72239a94f365 (diff) |
gl/msaa: Add a fast path for fills that are simple quads
Instead of invoking Bentley-Ottman for fills that are simple
quadrilaterals, just pass the geometry straight to OpenGL.
-rw-r--r-- | src/cairo-gl-msaa-compositor.c | 45 | ||||
-rw-r--r-- | src/cairo-path-fixed-private.h | 17 | ||||
-rw-r--r-- | src/cairo-path-fixed.c | 136 |
3 files changed, 158 insertions, 40 deletions
diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c index 4854d8f0..54772efb 100644 --- a/src/cairo-gl-msaa-compositor.c +++ b/src/cairo-gl-msaa-compositor.c @@ -45,6 +45,7 @@ #include "cairo-composite-rectangles-private.h" #include "cairo-compositor-private.h" #include "cairo-gl-private.h" +#include "cairo-path-private.h" #include "cairo-traps-private.h" static cairo_bool_t @@ -712,6 +713,29 @@ finish: } static cairo_int_status_t +_draw_simple_quad_path (cairo_gl_context_t *ctx, + cairo_gl_composite_t *setup, + const cairo_path_fixed_t *path) +{ + cairo_point_t triangle[3]; + cairo_int_status_t status; + const cairo_point_t *points; + + points = cairo_path_head (path)->points; + triangle[0] = points[0]; + triangle[1] = points[1]; + triangle[2] = points[2]; + status = _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle); + if (status) + return status; + + triangle[0] = points[2]; + triangle[1] = points[3]; + triangle[2] = points[0]; + return _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle); +} + +static cairo_int_status_t _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, cairo_composite_rectangles_t *composite, const cairo_path_fixed_t *path, @@ -724,6 +748,7 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, cairo_gl_context_t *ctx = NULL; cairo_int_status_t status; cairo_traps_t traps; + cairo_bool_t draw_path_with_traps; if (! can_use_msaa_compositor (dst, antialias)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -749,10 +774,14 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, return _paint_back_unbounded_surface (compositor, composite, surface); } - _cairo_traps_init (&traps); - status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); - if (unlikely (status)) - goto cleanup_traps; + draw_path_with_traps = ! _cairo_path_fixed_is_simple_quad (path); + + if (draw_path_with_traps) { + _cairo_traps_init (&traps); + status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); + if (unlikely (status)) + goto cleanup_traps; + } status = _cairo_gl_composite_init (&setup, composite->op, @@ -776,7 +805,10 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, if (unlikely (status)) goto cleanup_setup; - status = _draw_traps (ctx, &setup, &traps); + if (! draw_path_with_traps) + status = _draw_simple_quad_path (ctx, &setup, path); + else + status = _draw_traps (ctx, &setup, &traps); if (unlikely (status)) goto cleanup_setup; @@ -787,7 +819,8 @@ cleanup_setup: status = _cairo_gl_context_release (ctx, status); cleanup_traps: - _cairo_traps_fini (&traps); + if (draw_path_with_traps) + _cairo_traps_fini (&traps); return status; } diff --git a/src/cairo-path-fixed-private.h b/src/cairo-path-fixed-private.h index 9b7b4037..05904adb 100644 --- a/src/cairo-path-fixed-private.h +++ b/src/cairo-path-fixed-private.h @@ -59,6 +59,20 @@ typedef char cairo_path_op_t; #define CAIRO_PATH_BUF_SIZE ((512 - sizeof (cairo_path_buf_t)) \ / (2 * sizeof (cairo_point_t) + sizeof (cairo_path_op_t))) +#define cairo_path_head(path__) (&(path__)->buf.base) +#define cairo_path_tail(path__) cairo_path_buf_prev (cairo_path_head (path__)) + +#define cairo_path_buf_next(pos__) \ + cairo_list_entry ((pos__)->link.next, cairo_path_buf_t, link) +#define cairo_path_buf_prev(pos__) \ + cairo_list_entry ((pos__)->link.prev, cairo_path_buf_t, link) + +#define cairo_path_foreach_buf_start(pos__, path__) \ + pos__ = cairo_path_head (path__); do +#define cairo_path_foreach_buf_end(pos__, path__) \ + while ((pos__ = cairo_path_buf_next (pos__)) != cairo_path_head (path__)) + + typedef struct _cairo_path_buf { cairo_list_t link; unsigned int num_ops; @@ -186,4 +200,7 @@ cairo_private cairo_bool_t _cairo_path_fixed_is_stroke_box (const cairo_path_fixed_t *path, cairo_box_t *box); +cairo_bool_t +_cairo_path_fixed_is_simple_quad (const cairo_path_fixed_t *path); + #endif /* CAIRO_PATH_FIXED_PRIVATE_H */ diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c index c7b1cab1..66fbdfe1 100644 --- a/src/cairo-path-fixed.c +++ b/src/cairo-path-fixed.c @@ -69,19 +69,6 @@ _cairo_path_buf_add_points (cairo_path_buf_t *buf, const cairo_point_t *points, int num_points); -#define cairo_path_head(path__) (&(path__)->buf.base) -#define cairo_path_tail(path__) cairo_path_buf_prev (cairo_path_head (path__)) - -#define cairo_path_buf_next(pos__) \ - cairo_list_entry ((pos__)->link.next, cairo_path_buf_t, link) -#define cairo_path_buf_prev(pos__) \ - cairo_list_entry ((pos__)->link.prev, cairo_path_buf_t, link) - -#define cairo_path_foreach_buf_start(pos__, path__) \ - pos__ = cairo_path_head (path__); do -#define cairo_path_foreach_buf_end(pos__, path__) \ - while ((pos__ = cairo_path_buf_next (pos__)) != cairo_path_head (path__)) - void _cairo_path_fixed_init (cairo_path_fixed_t *path) { @@ -1219,18 +1206,11 @@ _canonical_box (cairo_box_t *box, } } -/* - * Check whether the given path contains a single rectangle. - */ -cairo_bool_t -_cairo_path_fixed_is_box (const cairo_path_fixed_t *path, - cairo_box_t *box) +static inline cairo_bool_t +_path_is_quad (const cairo_path_fixed_t *path) { const cairo_path_buf_t *buf = cairo_path_head (path); - if (! path->fill_is_rectilinear) - return FALSE; - /* Do we have the right number of ops? */ if (buf->num_ops < 4 || buf->num_ops > 6) return FALSE; @@ -1265,22 +1245,87 @@ _cairo_path_fixed_is_box (const cairo_path_fixed_t *path, } } - /* Ok, we may have a box, if the points line up */ - if (buf->points[0].y == buf->points[1].y && - buf->points[1].x == buf->points[2].x && - buf->points[2].y == buf->points[3].y && - buf->points[3].x == buf->points[0].x) - { + return TRUE; +} + +static inline cairo_bool_t +_points_form_rect (const cairo_point_t *points) +{ + if (points[0].y == points[1].y && + points[1].x == points[2].x && + points[2].y == points[3].y && + points[3].x == points[0].x) + return TRUE; + if (points[0].x == points[1].x && + points[1].y == points[2].y && + points[2].x == points[3].x && + points[3].y == points[0].y) + return TRUE; + return FALSE; +} + +/* + * Check whether the given path contains a single rectangle. + */ +cairo_bool_t +_cairo_path_fixed_is_box (const cairo_path_fixed_t *path, + cairo_box_t *box) +{ + const cairo_path_buf_t *buf; + + if (! path->fill_is_rectilinear) + return FALSE; + + if (! _path_is_quad (path)) + return FALSE; + + buf = cairo_path_head (path); + if (_points_form_rect (buf->points)) { _canonical_box (box, &buf->points[0], &buf->points[2]); return TRUE; } - if (buf->points[0].x == buf->points[1].x && - buf->points[1].y == buf->points[2].y && - buf->points[2].x == buf->points[3].x && - buf->points[3].y == buf->points[0].y) - { - _canonical_box (box, &buf->points[0], &buf->points[2]); + return FALSE; +} + +/* Determine whether two lines A->B and C->D intersect based on the + * algorithm described here: http://paulbourke.net/geometry/lineline2d/ */ +static inline cairo_bool_t +_lines_intersect_or_are_coincident (cairo_point_t a, + cairo_point_t b, + cairo_point_t c, + cairo_point_t d) +{ + cairo_int64_t numerator_a, numerator_b, denominator; + + denominator = _cairo_int64_sub (_cairo_int32x32_64_mul (d.y - c.y, b.x - a.x), + _cairo_int32x32_64_mul (d.x - c.x, b.y - a.y)); + numerator_a = _cairo_int64_sub (_cairo_int32x32_64_mul (d.x - c.x, a.y - c.y), + _cairo_int32x32_64_mul (d.y - c.y, a.x - c.x)); + numerator_b = _cairo_int64_sub (_cairo_int32x32_64_mul (b.x - a.x, a.y - c.y), + _cairo_int32x32_64_mul (b.y - a.y, a.x - c.x)); + + if (_cairo_int64_is_zero (denominator)) { + /* If the denominator and numerators are both zero, + * the lines are coincident. */ + if (_cairo_int64_is_zero (numerator_a) && _cairo_int64_is_zero (numerator_b)) + return TRUE; + + /* Otherwise, a zero denominator indicates the lines are + * parallel and never intersect. */ + return FALSE; + } + + /* If either division would produce a number between 0 and 1, i.e. + * the numerator is smaller than the denominator and their signs are + * the same, then the lines intersect. */ + if (_cairo_int64_lt (numerator_a, denominator) && + ! (_cairo_int64_negative (numerator_a) ^ _cairo_int64_negative(denominator))) { + return TRUE; + } + + if (_cairo_int64_lt (numerator_b, denominator) && + ! (_cairo_int64_negative (numerator_b) ^ _cairo_int64_negative(denominator))) { return TRUE; } @@ -1288,6 +1333,29 @@ _cairo_path_fixed_is_box (const cairo_path_fixed_t *path, } cairo_bool_t +_cairo_path_fixed_is_simple_quad (const cairo_path_fixed_t *path) +{ + const cairo_point_t *points; + + if (! _path_is_quad (path)) + return FALSE; + + points = cairo_path_head (path)->points; + if (_points_form_rect (points)) + return TRUE; + + if (_lines_intersect_or_are_coincident (points[0], points[1], + points[3], points[2])) + return FALSE; + + if (_lines_intersect_or_are_coincident (points[0], points[3], + points[1], points[2])) + return FALSE; + + return TRUE; +} + +cairo_bool_t _cairo_path_fixed_is_stroke_box (const cairo_path_fixed_t *path, cairo_box_t *box) { |