[cairo-commit] 2 commits - src/cairo-compiler-private.h src/cairo-gl-composite.c src/cairo-gl-private.h src/cairo-gl-surface.c src/cairo-recording-surface.c
Chris Wilson
ickle at kemper.freedesktop.org
Fri Jul 29 07:41:05 PDT 2011
src/cairo-compiler-private.h | 13 -
src/cairo-gl-composite.c | 517 +++++++++++++++++++++++++++++++++++++++++-
src/cairo-gl-private.h | 20 +
src/cairo-gl-surface.c | 137 ++++++-----
src/cairo-recording-surface.c | 10
5 files changed, 628 insertions(+), 69 deletions(-)
New commits:
commit 0660f62fe5ffdd86eedf8262f3ac50fb039491c1
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jul 29 15:28:49 2011 +0100
gl: Rectilinear fast path
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index c259fe9..6ea8c85 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -282,7 +282,7 @@ _cairo_gl_operand_init (cairo_gl_operand_t *operand,
int dst_x, int dst_y,
int width, int height)
{
- cairo_status_t status;
+ cairo_int_status_t status;
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
@@ -1430,7 +1430,184 @@ _composite_boxes (cairo_gl_surface_t *dst,
_cairo_pattern_fini (&mask.base);
_cairo_gl_composite_fini (&setup);
+ return status;
+}
+
+static cairo_bool_t converter_add_box (cairo_box_t *box, void *closure)
+{
+ return _cairo_rectangular_scan_converter_add_box (closure, box, 1) == CAIRO_STATUS_SUCCESS;
+}
+
+typedef struct _cairo_gl_surface_span_renderer {
+ cairo_span_renderer_t base;
+
+ cairo_gl_composite_t setup;
+
+ int xmin, xmax;
+ int ymin, ymax;
+
+ cairo_gl_context_t *ctx;
+} cairo_gl_surface_span_renderer_t;
+
+static cairo_status_t
+_cairo_gl_render_bounded_spans (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
+
+ if (num_spans == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ do {
+ if (spans[0].coverage) {
+ _cairo_gl_composite_emit_rect (renderer->ctx,
+ spans[0].x, y,
+ spans[1].x, y + height,
+ spans[0].coverage);
+ }
+ spans++;
+ } while (--num_spans > 1);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_render_unbounded_spans (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
+
+ if (y > renderer->ymin) {
+ _cairo_gl_composite_emit_rect (renderer->ctx,
+ renderer->xmin, renderer->ymin,
+ renderer->xmax, y,
+ 0);
+ }
+
+ if (num_spans == 0) {
+ _cairo_gl_composite_emit_rect (renderer->ctx,
+ renderer->xmin, y,
+ renderer->xmax, y + height,
+ 0);
+ } else {
+ if (spans[0].x != renderer->xmin) {
+ _cairo_gl_composite_emit_rect (renderer->ctx,
+ renderer->xmin, y,
+ spans[0].x, y + height,
+ 0);
+ }
+
+ do {
+ _cairo_gl_composite_emit_rect (renderer->ctx,
+ spans[0].x, y,
+ spans[1].x, y + height,
+ spans[0].coverage);
+ spans++;
+ } while (--num_spans > 1);
+
+ if (spans[0].x != renderer->xmax) {
+ _cairo_gl_composite_emit_rect (renderer->ctx,
+ spans[0].x, y,
+ renderer->xmax, y + height,
+ 0);
+ }
+ }
+
+ renderer->ymin = y + height;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_finish_unbounded_spans (void *abstract_renderer)
+{
+ cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
+
+ if (renderer->ymax > renderer->ymin) {
+ _cairo_gl_composite_emit_rect (renderer->ctx,
+ renderer->xmin, renderer->ymin,
+ renderer->xmax, renderer->ymax,
+ 0);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_finish_bounded_spans (void *abstract_renderer)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_composite_unaligned_boxes (cairo_gl_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ cairo_boxes_t *boxes,
+ const cairo_composite_rectangles_t *composite)
+{
+ cairo_rectangular_scan_converter_t converter;
+ cairo_gl_surface_span_renderer_t renderer;
+ const cairo_rectangle_int_t *extents;
+ cairo_status_t status;
+
+ if (composite->clip->path)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* XXX for ADD or if we know the boxes are disjoint we can do a simpler
+ * pass, but for now... */
+
+ _cairo_rectangular_scan_converter_init (&converter, &composite->bounded);
+ cairo_boxes_for_each_box (boxes, converter_add_box, &converter);
+
+ if (composite->is_bounded) {
+ renderer.base.render_rows = _cairo_gl_render_bounded_spans;
+ renderer.base.finish = _cairo_gl_finish_bounded_spans;
+ extents = &composite->bounded;
+ } else {
+ renderer.base.render_rows = _cairo_gl_render_unbounded_spans;
+ renderer.base.finish = _cairo_gl_finish_unbounded_spans;
+ extents = &composite->unbounded;
+ }
+ renderer.xmin = extents->x;
+ renderer.xmax = extents->x + extents->width;
+ renderer.ymin = extents->y;
+ renderer.ymax = extents->y + extents->height;
+
+ status = _cairo_gl_composite_init (&renderer.setup,
+ op, dst,
+ FALSE, extents);
+ if (unlikely (status))
+ goto FAIL;
+
+ status = _cairo_gl_composite_set_source (&renderer.setup, pattern,
+ extents->x, extents->y,
+ extents->x, extents->y,
+ extents->width, extents->height);
+ if (unlikely (status))
+ goto FAIL;
+
+ _cairo_gl_composite_set_mask_spans (&renderer.setup);
+ if (! composite->is_bounded)
+ _cairo_gl_composite_set_clip_region (&renderer.setup,
+ _cairo_clip_get_region (composite->clip));
+
+ status = _cairo_gl_composite_begin (&renderer.setup, &renderer.ctx);
+ if (unlikely (status))
+ goto FAIL;
+
+ status = converter.base.generate (&converter.base, &renderer.base);
+
+ converter.base.destroy (&converter.base);
+ renderer.base.finish (&renderer.base);
+
+ status = _cairo_gl_context_release (renderer.ctx, status);
+FAIL:
+ _cairo_gl_composite_fini (&renderer.setup);
return status;
}
@@ -1481,6 +1658,9 @@ _cairo_gl_clip_and_composite_boxes (cairo_gl_surface_t *dst,
if (boxes->num_boxes == 0 && extents->is_bounded)
return CAIRO_STATUS_SUCCESS;
+ if (! _cairo_gl_operator_is_supported (op))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (boxes->is_pixel_aligned && _cairo_clip_is_region (extents->clip) &&
(op == CAIRO_OPERATOR_SOURCE ||
(dst->base.is_clear && (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD))))
@@ -1554,6 +1734,10 @@ _cairo_gl_clip_and_composite_boxes (cairo_gl_surface_t *dst,
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
+ status = _composite_unaligned_boxes (dst, op, src, boxes, extents);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
/* Otherwise XXX */
return CAIRO_INT_STATUS_UNSUPPORTED;
}
commit c2150b344123823098a57a0653b9857f7dc8c8d6
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jul 29 15:06:20 2011 +0100
gl: Rectangular fast path
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/cairo-compiler-private.h b/src/cairo-compiler-private.h
index 96034d6..dfe114b 100644
--- a/src/cairo-compiler-private.h
+++ b/src/cairo-compiler-private.h
@@ -183,17 +183,8 @@
#endif
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
-#define _CAIRO_BOOLEAN_EXPR(expr) \
- __extension__ ({ \
- int _cairo_boolean_var_; \
- if (expr) \
- _cairo_boolean_var_ = 1; \
- else \
- _cairo_boolean_var_ = 0; \
- _cairo_boolean_var_; \
-})
-#define likely(expr) (__builtin_expect (_CAIRO_BOOLEAN_EXPR(expr), 1))
-#define unlikely(expr) (__builtin_expect (_CAIRO_BOOLEAN_EXPR(expr), 0))
+#define likely(expr) (__builtin_expect (!!(expr), 1))
+#define unlikely(expr) (__builtin_expect (!!(expr), 0))
#else
#define likely(expr) (expr)
#define unlikely(expr) (expr)
diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 27912b3..c259fe9 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -42,6 +42,8 @@
#include "cairoint.h"
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-clip-private.h"
#include "cairo-error-private.h"
#include "cairo-gl-private.h"
@@ -1226,3 +1228,332 @@ _cairo_gl_composite_init (cairo_gl_composite_t *setup,
return CAIRO_STATUS_SUCCESS;
}
+static cairo_bool_t
+cairo_boxes_for_each_box (cairo_boxes_t *boxes,
+ cairo_bool_t (*func) (cairo_box_t *box,
+ void *data),
+ void *data)
+{
+ struct _cairo_boxes_chunk *chunk;
+ int i;
+
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++)
+ if (! func (&chunk->base[i], data))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+struct image_contains_box {
+ int width, height;
+ int tx, ty;
+};
+
+static cairo_bool_t image_contains_box (cairo_box_t *box, void *closure)
+{
+ struct image_contains_box *data = closure;
+
+ return
+ _cairo_fixed_integer_part (box->p1.x) + data->tx >= 0 &&
+ _cairo_fixed_integer_part (box->p1.y) + data->ty >= 0 &&
+ _cairo_fixed_integer_part (box->p2.x) + data->tx <= data->width &&
+ _cairo_fixed_integer_part (box->p2.y) + data->ty <= data->height;
+}
+
+struct image_upload_box {
+ cairo_gl_surface_t *surface;
+ cairo_image_surface_t *image;
+ int tx, ty;
+};
+
+static cairo_bool_t image_upload_box (cairo_box_t *box, void *closure)
+{
+ const struct image_upload_box *iub = closure;
+ int x = _cairo_fixed_integer_part (box->p1.x);
+ int y = _cairo_fixed_integer_part (box->p1.y);
+ int w = _cairo_fixed_integer_part (box->p2.x - box->p1.x);
+ int h = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
+
+ return _cairo_gl_surface_draw_image (iub->surface,
+ iub->image,
+ x + iub->tx, y + iub->ty,
+ w, h,
+ x, y) == CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_upload_image_inplace (cairo_gl_surface_t *surface,
+ const cairo_pattern_t *source,
+ cairo_boxes_t *boxes)
+{
+ const cairo_surface_pattern_t *pattern;
+ struct image_contains_box icb;
+ struct image_upload_box iub;
+ cairo_image_surface_t *image;
+ int tx, ty;
+
+ if (! boxes->is_pixel_aligned)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ pattern = (const cairo_surface_pattern_t *) source;
+ if (pattern->surface->type != CAIRO_SURFACE_TYPE_IMAGE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ image = (cairo_image_surface_t *) pattern->surface;
+ if (image->format == CAIRO_FORMAT_INVALID)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* Check that the data is entirely within the image */
+ icb.width = image->width;
+ icb.height = image->height;
+ icb.tx = tx;
+ icb.ty = ty;
+ if (! cairo_boxes_for_each_box (boxes, image_contains_box, &icb))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ iub.surface = surface;
+ iub.image = image;
+ iub.tx = tx;
+ iub.ty = ty;
+ cairo_boxes_for_each_box (boxes, image_upload_box, &iub);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_bool_t composite_box (cairo_box_t *box, void *closure)
+{
+ _cairo_gl_composite_emit_rect (closure,
+ _cairo_fixed_integer_part (box->p1.x),
+ _cairo_fixed_integer_part (box->p1.y),
+ _cairo_fixed_integer_part (box->p2.x),
+ _cairo_fixed_integer_part (box->p2.y),
+ 0);
+ return TRUE;
+}
+
+static cairo_status_t
+_composite_boxes (cairo_gl_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_boxes_t *boxes,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_bool_t need_clip_mask = FALSE;
+ cairo_gl_composite_t setup;
+ cairo_gl_context_t *ctx;
+ cairo_surface_pattern_t mask;
+ cairo_status_t status;
+
+ /* If the boxes are not pixel-aligned, we will need to compute a real mask */
+ if (! boxes->is_pixel_aligned)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (extents->clip->path &&
+ (! extents->is_bounded || op == CAIRO_OPERATOR_SOURCE))
+ {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ if (! extents->is_bounded)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_gl_composite_init (&setup, op, dst, FALSE,
+ &extents->bounded);
+ if (unlikely (status))
+ goto CLEANUP;
+
+ status = _cairo_gl_composite_set_source (&setup, src,
+ extents->bounded.x,
+ extents->bounded.y,
+ extents->bounded.x,
+ extents->bounded.y,
+ extents->bounded.width,
+ extents->bounded.height);
+ if (unlikely (status))
+ goto CLEANUP;
+
+ need_clip_mask = extents->clip->path != NULL;
+ if (need_clip_mask) {
+ cairo_surface_t *clip_surface;
+ int clip_x, clip_y;
+
+ clip_surface = _cairo_clip_get_surface (extents->clip,
+ &dst->base,
+ &clip_x, &clip_y);
+ if (unlikely (clip_surface->status)) {
+ status = clip_surface->status;
+ need_clip_mask = FALSE;
+ goto CLEANUP;
+ }
+
+ _cairo_pattern_init_for_surface (&mask, clip_surface);
+ mask.base.filter = CAIRO_FILTER_NEAREST;
+ cairo_matrix_init_translate (&mask.base.matrix,
+ -clip_x,
+ -clip_y);
+ cairo_surface_destroy (clip_surface);
+
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ src = NULL;
+ op = CAIRO_OPERATOR_DEST_OUT;
+ }
+
+ status = _cairo_gl_composite_set_mask (&setup, &mask.base,
+ extents->bounded.x,
+ extents->bounded.y,
+ extents->bounded.x,
+ extents->bounded.y,
+ extents->bounded.width,
+ extents->bounded.height);
+ if (unlikely (status))
+ goto CLEANUP;
+ }
+
+ status = _cairo_gl_composite_begin (&setup, &ctx);
+ if (unlikely (status))
+ goto CLEANUP;
+
+ cairo_boxes_for_each_box (boxes, composite_box, ctx);
+
+ status = _cairo_gl_context_release (ctx, status);
+
+ CLEANUP:
+ if (need_clip_mask)
+ _cairo_pattern_fini (&mask.base);
+
+ _cairo_gl_composite_fini (&setup);
+
+ return status;
+}
+
+/* XXX _cairo_gl_clip_and_composite_polygon() */
+cairo_int_status_t
+_cairo_gl_surface_polygon (cairo_gl_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_polygon_t *polygon,
+ cairo_fill_rule_t fill_rule,
+ cairo_antialias_t antialias,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
+
+ if (! _cairo_clip_is_region (extents->clip))
+ return UNSUPPORTED ("a clip surface would be required");
+
+ if (! _cairo_surface_check_span_renderer (op, src, &dst->base, antialias))
+ return UNSUPPORTED ("no span renderer");
+
+ if (op == CAIRO_OPERATOR_SOURCE)
+ return UNSUPPORTED ("SOURCE compositing doesn't work in GL");
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ op = CAIRO_OPERATOR_DEST_OUT;
+ src = &_cairo_pattern_white.base;
+ }
+
+ return _cairo_surface_composite_polygon (&dst->base,
+ op,
+ src,
+ fill_rule,
+ antialias,
+ extents,
+ polygon,
+ clip_region);
+}
+
+cairo_int_status_t
+_cairo_gl_clip_and_composite_boxes (cairo_gl_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_boxes_t *boxes,
+ cairo_composite_rectangles_t *extents)
+{
+ cairo_int_status_t status;
+
+ if (boxes->num_boxes == 0 && extents->is_bounded)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (boxes->is_pixel_aligned && _cairo_clip_is_region (extents->clip) &&
+ (op == CAIRO_OPERATOR_SOURCE ||
+ (dst->base.is_clear && (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD))))
+ {
+ if (boxes->num_boxes == 1 &&
+ extents->bounded.width == dst->width &&
+ extents->bounded.height == dst->height)
+ {
+ op = CAIRO_OPERATOR_SOURCE;
+#if 0
+ dst->deferred_clear = FALSE;
+#endif
+ }
+
+ status = _upload_image_inplace (dst, src, boxes);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
+
+ /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
+ if (extents->clip->path != NULL && extents->is_bounded) {
+ cairo_polygon_t polygon;
+ cairo_fill_rule_t fill_rule;
+ cairo_antialias_t antialias;
+ cairo_clip_t *clip;
+
+ clip = _cairo_clip_copy (extents->clip);
+ clip = _cairo_clip_intersect_boxes (clip, boxes);
+ status = _cairo_clip_get_polygon (clip, &polygon,
+ &fill_rule, &antialias);
+ _cairo_clip_path_destroy (clip->path);
+ clip->path = NULL;
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ cairo_clip_t *saved_clip = extents->clip;
+ extents->clip = clip;
+ status = _cairo_gl_surface_polygon (dst, op, src,
+ &polygon,
+ fill_rule,
+ antialias,
+ extents);
+ if (extents->clip != clip)
+ clip = NULL;
+ extents->clip = saved_clip;
+ _cairo_polygon_fini (&polygon);
+ }
+ if (clip)
+ _cairo_clip_destroy (clip);
+
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
+
+#if 0
+ if (dst->deferred_clear) {
+ status = _cairo_gl_surface_clear (dst);
+ if (unlikely (status))
+ return status;
+ }
+#endif
+
+ if (boxes->is_pixel_aligned &&
+ _cairo_clip_is_region (extents->clip) &&
+ op == CAIRO_OPERATOR_SOURCE) {
+ status = _upload_image_inplace (dst, src, boxes);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
+
+ /* Use a fast path if the boxes are pixel aligned */
+ status = _composite_boxes (dst, op, src, boxes, extents);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ /* Otherwise XXX */
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index c83d78f..ee79b23 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -594,6 +594,26 @@ _cairo_gl_operand_get_gl_filter (cairo_gl_operand_t *operand);
cairo_private cairo_extend_t
_cairo_gl_operand_get_extend (cairo_gl_operand_t *operand);
+cairo_private cairo_bool_t
+_cairo_gl_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_int_t *rectangle);
+
+cairo_private cairo_int_status_t
+_cairo_gl_surface_polygon (cairo_gl_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_polygon_t *polygon,
+ cairo_fill_rule_t fill_rule,
+ cairo_antialias_t antialias,
+ const cairo_composite_rectangles_t *extents);
+
+cairo_private cairo_int_status_t
+_cairo_gl_clip_and_composite_boxes (cairo_gl_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_boxes_t *boxes,
+ cairo_composite_rectangles_t *extents);
+
slim_hidden_proto (cairo_gl_surface_create);
slim_hidden_proto (cairo_gl_surface_create_for_texture);
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index fde9335..09a1589 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1581,7 +1581,7 @@ FAIL:
return _cairo_span_renderer_create_in_error (status);
}
-cairo_private cairo_bool_t
+cairo_bool_t
_cairo_gl_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -1632,6 +1632,12 @@ _cairo_gl_surface_paint (void *abstract_surface,
const cairo_pattern_t *source,
const cairo_clip_t *clip)
{
+ cairo_gl_surface_t *surface = abstract_surface;
+ cairo_composite_rectangles_t extents;
+ cairo_rectangle_int_t unbounded;
+ cairo_boxes_t boxes;
+ cairo_status_t status;
+
/* simplify the common case of clearing the surface */
if (clip == NULL) {
if (op == CAIRO_OPERATOR_CLEAR)
@@ -1644,41 +1650,22 @@ _cairo_gl_surface_paint (void *abstract_surface,
}
}
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_gl_surface_polygon (cairo_gl_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_polygon_t *polygon,
- cairo_fill_rule_t fill_rule,
- cairo_antialias_t antialias,
- const cairo_composite_rectangles_t *extents)
-{
- cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
-
- if (! _cairo_clip_is_region (extents->clip))
- return UNSUPPORTED ("a clip surface would be required");
-
- if (! _cairo_surface_check_span_renderer (op, src, &dst->base, antialias))
- return UNSUPPORTED ("no span renderer");
+ _cairo_gl_surface_get_extents (surface, &unbounded);
+ status = _cairo_composite_rectangles_init_for_paint (&extents, &unbounded,
+ op, source,
+ clip);
+ if (unlikely (status))
+ return status;
- if (op == CAIRO_OPERATOR_SOURCE)
- return UNSUPPORTED ("SOURCE compositing doesn't work in GL");
- if (op == CAIRO_OPERATOR_CLEAR) {
- op = CAIRO_OPERATOR_DEST_OUT;
- src = &_cairo_pattern_white.base;
+ status = _cairo_clip_to_boxes(extents.clip, &boxes);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _cairo_gl_clip_and_composite_boxes (surface, op, source,
+ &boxes, &extents);
}
- return _cairo_surface_composite_polygon (&dst->base,
- op,
- src,
- fill_rule,
- antialias,
- extents,
- polygon,
- clip_region);
+ _cairo_composite_rectangles_fini (&extents);
+
+ return status;
}
static cairo_int_status_t
@@ -1696,8 +1683,7 @@ _cairo_gl_surface_stroke (void *abstract_surface,
cairo_gl_surface_t *surface = abstract_surface;
cairo_composite_rectangles_t extents;
cairo_rectangle_int_t unbounded;
- cairo_polygon_t polygon;
- cairo_status_t status;
+ cairo_int_status_t status;
_cairo_gl_surface_get_extents (surface, &unbounded);
status = _cairo_composite_rectangles_init_for_stroke (&extents,
@@ -1708,18 +1694,40 @@ _cairo_gl_surface_stroke (void *abstract_surface,
if (unlikely (status))
return status;
- _cairo_polygon_init_with_clip (&polygon, extents.clip);
- status = _cairo_path_fixed_stroke_to_polygon (path,
- style,
- ctm, ctm_inverse,
- tolerance,
- &polygon);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- status = _cairo_gl_surface_polygon (surface, op, source, &polygon,
- CAIRO_FILL_RULE_WINDING, antialias,
- &extents);
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init_with_clip (&boxes, extents.clip);
+ status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
+ style,
+ ctm,
+ antialias,
+ &boxes);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ status = _cairo_gl_clip_and_composite_boxes (surface, op, source,
+ &boxes, &extents);
+ }
+ _cairo_boxes_fini (&boxes);
+ }
+
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ cairo_polygon_t polygon;
+
+ _cairo_polygon_init_with_clip (&polygon, extents.clip);
+ status = _cairo_path_fixed_stroke_to_polygon (path,
+ style,
+ ctm, ctm_inverse,
+ tolerance,
+ &polygon);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ status = _cairo_gl_surface_polygon (surface, op, source, &polygon,
+ CAIRO_FILL_RULE_WINDING, antialias,
+ &extents);
+ }
+ _cairo_polygon_fini (&polygon);
}
- _cairo_polygon_fini (&polygon);
_cairo_composite_rectangles_fini (&extents);
@@ -1739,8 +1747,7 @@ _cairo_gl_surface_fill (void *abstract_surface,
cairo_gl_surface_t *surface = abstract_surface;
cairo_composite_rectangles_t extents;
cairo_rectangle_int_t unbounded;
- cairo_polygon_t polygon;
- cairo_status_t status;
+ cairo_int_status_t status;
_cairo_gl_surface_get_extents (surface, &unbounded);
status = _cairo_composite_rectangles_init_for_fill (&extents,
@@ -1750,14 +1757,34 @@ _cairo_gl_surface_fill (void *abstract_surface,
if (unlikely (status))
return status;
- _cairo_polygon_init_with_clip (&polygon, extents.clip);
- status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- status = _cairo_gl_surface_polygon (surface, op, source, &polygon,
- fill_rule, antialias,
- &extents);
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (_cairo_path_fixed_fill_is_rectilinear (path)) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init_with_clip (&boxes, extents.clip);
+ status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
+ fill_rule,
+ antialias,
+ &boxes);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ status = _cairo_gl_clip_and_composite_boxes (surface, op, source,
+ &boxes, &extents);
+ }
+ _cairo_boxes_fini (&boxes);
+ }
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ cairo_polygon_t polygon;
+
+ _cairo_polygon_init_with_clip (&polygon, extents.clip);
+ status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ status = _cairo_gl_surface_polygon (surface, op, source, &polygon,
+ fill_rule, antialias,
+ &extents);
+ }
+ _cairo_polygon_fini (&polygon);
}
- _cairo_polygon_fini (&polygon);
_cairo_composite_rectangles_fini (&extents);
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index bb9b2dd..478695f 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -585,8 +585,14 @@ _command_init (cairo_recording_surface_t *surface,
command->index = surface->commands.num_elements;
/* steal the clip */
- command->clip = composite->clip;
- composite->clip = NULL;
+ command->clip = NULL;
+ if (! _cairo_clip_is_region (composite->clip) ||
+ cairo_region_contains_rectangle (_cairo_clip_get_region (composite->clip),
+ &composite->unbounded) != CAIRO_REGION_OVERLAP_IN)
+ {
+ command->clip = composite->clip;
+ composite->clip = NULL;
+ }
return status;
}
More information about the cairo-commit
mailing list