[PATCH 2/2] gl/msaa: Add support for unbounded operators

"Henry (Yu) Song - SISA" <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <3955FA337689574EB32F94B12A7E6E9E0B41844C@ex10mail>
Add support for unbounded operators by creating an intermediate
surface which will be drawn back to the destination with the
appropriate compositing operator.
---
src/cairo-gl-msaa-compositor.c |  101 ++++++++++++++++++++++++++++++++++++++-
src/cairo-gl-private.h         |    8 +++
src/cairo-gl-surface.c         |    6 ++-
3 files changed, 111 insertions(+), 4 deletions(-)

diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c
index 2c8e4f5..4cc7361 100644
--- a/src/cairo-gl-msaa-compositor.c
+++ b/src/cairo-gl-msaa-compositor.c
@@ -231,6 +231,59 @@ _draw_clip_to_stencil_buffer (cairo_gl_context_t   *ctx,
}
 static cairo_int_status_t
+_ensure_intermediate_surface (cairo_gl_surface_t *surface)
+{
+    cairo_gl_surface_t *intermediate = (cairo_gl_surface_t *) surface->intermediate;
+    cairo_surface_t *new_surface = NULL;
+
+    if (intermediate != NULL &&
+     intermediate->width == surface->width &&
+     intermediate->height == surface->height) {
+     return _cairo_gl_surface_clear (intermediate, CAIRO_COLOR_TRANSPARENT);
+    }
+
+    if (intermediate != NULL) {
+     cairo_surface_destroy (surface->intermediate);
+     surface->intermediate = NULL;
+    }
+
+    new_surface = cairo_surface_create_similar (&surface->base,
+                                   CAIRO_CONTENT_COLOR_ALPHA,
+                                   surface->width,
+                                   surface->height);
+
+    if (new_surface == NULL)
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    if (unlikely (new_surface->status)) {
+        cairo_surface_destroy (new_surface);
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    assert (cairo_surface_get_type (new_surface) == CAIRO_SURFACE_TYPE_GL);
+    surface->intermediate = new_surface;
+    return _cairo_gl_surface_clear ((cairo_gl_surface_t *) new_surface, CAIRO_COLOR_TRANSPARENT);
+}
+
+static cairo_int_status_t
+_paint_back_intermediate_surface (cairo_gl_surface_t *surface,
+                         cairo_operator_t op,
+                         cairo_clip_t *clip)
+{
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+    cairo_surface_pattern_t tmp_pattern;
+
+    surface->intermediate->is_clear = FALSE;
+    _cairo_pattern_init_for_surface (&tmp_pattern,
+                            (cairo_surface_t*) surface->intermediate);
+    tmp_pattern.base.has_component_alpha = FALSE;
+    status = _cairo_surface_paint (&surface->base, op, &(tmp_pattern.base), clip);
+
+    _cairo_pattern_fini (&tmp_pattern.base);
+    return status;
+}
+
+
+static cairo_int_status_t
_cairo_gl_msaa_compositor_paint (const cairo_compositor_t  *compositor,
                        cairo_composite_rectangles_t *composite)
{
@@ -369,16 +422,29 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t      *compositor,
                         cairo_antialias_t           antialias)
{
     cairo_int_status_t status;
-    cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
     struct _tristrip_composite_info info;
+    cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
+    cairo_gl_surface_t *original_dst = dst;
+    cairo_operator_t op = composite->op;
+    cairo_operator_t original_op = op;
+
+
     cairo_bool_t used_stencil_buffer_for_clip = FALSE;
     if (antialias != CAIRO_ANTIALIAS_NONE)
     return CAIRO_INT_STATUS_UNSUPPORTED;
+    if (! _cairo_operator_bounded_by_mask (op)) {
+     if (unlikely ((status = _ensure_intermediate_surface (dst))))
+         return status;
+     dst = (cairo_gl_surface_t *) dst->intermediate;
+     op = CAIRO_OPERATOR_OVER;
+    }
+
+
     status = _cairo_gl_composite_init (&info.setup,
-                              composite->op,
+                              op,
                              dst,
                              FALSE, /* assume_component_alpha */
                              &composite->bounded);
@@ -428,6 +494,14 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t      *compositor,
     _cairo_gl_composite_flush (info.ctx);
+    if (! _cairo_operator_bounded_by_mask (original_op)) {
+     status = _paint_back_intermediate_surface (original_dst,
+                                      original_op,
+                                      composite->clip);
+     if (unlikely (status))
+         goto finish;
+    }
+
finish:
     _cairo_gl_composite_fini (&info.setup);
@@ -449,7 +523,12 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor,
                       cairo_antialias_t       antialias)
{
     cairo_gl_composite_t setup;
+
     cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
+    cairo_gl_surface_t *original_dst = dst;
+    cairo_operator_t op = composite->op;
+    cairo_operator_t original_op = op;
+
     cairo_gl_context_t *ctx = NULL;
     cairo_int_status_t status;
     cairo_traps_t traps;
@@ -457,13 +536,20 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t      *compositor,
     if (antialias != CAIRO_ANTIALIAS_NONE)
     return CAIRO_INT_STATUS_UNSUPPORTED;
+    if (! _cairo_operator_bounded_by_mask (op)) {
+     if (unlikely ((status = _ensure_intermediate_surface (dst))))
+         return status;
+     dst = (cairo_gl_surface_t *) dst->intermediate;
+     op = CAIRO_OPERATOR_OVER;
+    }
+
     _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,
+                              op,
                              dst,
                              FALSE, /* assume_component_alpha */
                              &composite->bounded);
@@ -499,6 +585,15 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor,
         goto cleanup_setup;
     _cairo_gl_composite_flush (ctx);
+
+    if (! _cairo_operator_bounded_by_mask (original_op)) {
+     status = _paint_back_intermediate_surface (original_dst,
+                                      original_op,
+                                      composite->clip);
+     if (unlikely (status))
+         goto cleanup_setup;
+    }
+
cleanup_setup:
     _cairo_gl_composite_fini (&setup);
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 19c7c1f..17da7f0 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -119,6 +119,10 @@ typedef struct _cairo_gl_surface {
     GLuint depth_stencil; /* GL renderbuffer object for holding stencil buffer clip. */
     int owns_tex;
     cairo_bool_t needs_update;
+
+    /* The intermediate surface is used for
+       unbounded operators in the MSAA compositor. */
+    cairo_surface_t *intermediate;
} cairo_gl_surface_t;
 typedef struct cairo_gl_glyph_cache {
@@ -374,6 +378,10 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
                       int width, int height,
                       int dst_x, int dst_y);
+cairo_private cairo_status_t
+_cairo_gl_surface_clear (cairo_gl_surface_t  *surface,
+                 const cairo_color_t *color);
+
static cairo_always_inline cairo_bool_t
_cairo_gl_device_has_glsl (cairo_device_t *device)
{
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index c781ec4..5b7d930 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -363,6 +363,7 @@ _cairo_gl_surface_init (cairo_device_t *device,
     surface->width = width;
     surface->height = height;
     surface->needs_update = FALSE;
+    surface->intermediate = NULL;
}
 static cairo_surface_t *
@@ -446,7 +447,7 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
     return &surface->base;
}
-static cairo_status_t
+cairo_status_t
_cairo_gl_surface_clear (cairo_gl_surface_t  *surface,
                          const cairo_color_t *color)
{
@@ -906,6 +907,9 @@ _cairo_gl_surface_finish (void *abstract_surface)
     cairo_status_t status;
     cairo_gl_context_t *ctx;
+    if (surface->intermediate)
+     cairo_surface_destroy (surface->intermediate);
+
     status = _cairo_gl_context_acquire (surface->base.device, &ctx);
     if (unlikely (status))
         return status;
--
1.7.5.4

--
cairo mailing list
[email protected]
http://lists.cairographics.org/mailman/listinfo/cairo
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.