[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