[cairo] [PATCH] gl/msaa: Add full support for masking with the SOURCE operator

Martin Robinson mrobinson at igalia.com
Fri Dec 28 16:46:33 PST 2012


Note that I'm not the original author. Thus, I've included the full
commit below.

commit 038ea9d46cd140da796c97b27107fab8d7bd9837
Author: Henry Song <henry.song at samsung.com>
Date:   Tue Mar 13 08:43:24 2012 -0700

    gl/msaa: Add full support for masking with the SOURCE operator

    Since OpenGL does not have a means to represent a masking SOURCE
    operation in one step, we use two steps combined with the ADD
    operator.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index fa62a87..6731886 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -629,24 +629,13 @@ _cairo_gl_composite_setup_clipping
(cairo_gl_composite_t *setup,
 }

 cairo_status_t
-_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
-			   cairo_gl_context_t **ctx_out)
+_cairo_gl_switch_operands_and_operator (cairo_gl_composite_t *setup,
+					cairo_gl_context_t *ctx)
 {
     unsigned int dst_size, src_size, mask_size, vertex_size;
-    cairo_gl_context_t *ctx;
     cairo_status_t status;
-    cairo_bool_t component_alpha;
     cairo_gl_shader_t *shader;
-
-    assert (setup->dst);
-
-    status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
-    if (unlikely (status))
-	return status;
-
-    _cairo_gl_context_set_destination (ctx, setup->dst,
setup->multisample);
-
-    glEnable (GL_BLEND);
+    cairo_bool_t component_alpha;

     component_alpha =
 	setup->mask.type == CAIRO_GL_OPERAND_TEXTURE &&
@@ -654,40 +643,40 @@ _cairo_gl_composite_begin (cairo_gl_composite_t
*setup,

     /* Do various magic for component alpha */
     if (component_alpha) {
-        status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
-        if (unlikely (status))
-            goto FAIL;
-    } else {
-        if (ctx->pre_shader) {
-            _cairo_gl_composite_flush (ctx);
-            ctx->pre_shader = NULL;
-        }
+	status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
+	if (unlikely (status))
+	    return status;
+     } else {
+	if (ctx->pre_shader) {
+	    _cairo_gl_composite_flush (ctx);
+	    ctx->pre_shader = NULL;
+	}
     }

     status = _cairo_gl_get_shader_by_type (ctx,
 					   &setup->src,
 					   &setup->mask,
 					   setup->spans,
-                                           component_alpha ?
+					   component_alpha ?
 					   CAIRO_GL_SHADER_IN_CA_SOURCE :
 					   CAIRO_GL_SHADER_IN_NORMAL,
                                            &shader);
     if (unlikely (status)) {
-        ctx->pre_shader = NULL;
-        goto FAIL;
+	ctx->pre_shader = NULL;
+	return status;
     }
     if (ctx->current_shader != shader)
         _cairo_gl_composite_flush (ctx);

     status = CAIRO_STATUS_SUCCESS;

-    dst_size  = 2 * sizeof (GLfloat);
-    src_size  = _cairo_gl_operand_get_vertex_size (setup->src.type);
+    dst_size = 2 * sizeof (GLfloat);
+    src_size = _cairo_gl_operand_get_vertex_size (setup->src.type);
     mask_size = _cairo_gl_operand_get_vertex_size (setup->mask.type);
     vertex_size = dst_size + src_size + mask_size;

     if (setup->spans)
-	    vertex_size += sizeof (GLfloat);
+	vertex_size += sizeof (GLfloat);

     _cairo_gl_composite_setup_vbo (ctx, vertex_size);

@@ -700,15 +689,35 @@ _cairo_gl_composite_begin (cairo_gl_composite_t
*setup,
     _cairo_gl_set_operator (ctx, setup->op, component_alpha);

     if (_cairo_gl_context_is_flushed (ctx)) {
-        if (ctx->pre_shader) {
-            _cairo_gl_set_shader (ctx, ctx->pre_shader);
-            _cairo_gl_composite_bind_to_shader (ctx, setup);
-        }
-        _cairo_gl_set_shader (ctx, shader);
-        _cairo_gl_composite_bind_to_shader (ctx, setup);
+	if (ctx->pre_shader) {
+	    _cairo_gl_set_shader (ctx, ctx->pre_shader);
+	    _cairo_gl_composite_bind_to_shader (ctx, setup);
+	}
+	_cairo_gl_set_shader (ctx, shader);
+	_cairo_gl_composite_bind_to_shader (ctx, setup);
     }

-    status = _cairo_gl_composite_setup_clipping (setup, ctx, vertex_size);
+    return status;
+}
+
+cairo_status_t
+_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
+			   cairo_gl_context_t **ctx_out)
+{
+    cairo_gl_context_t *ctx;
+    cairo_status_t status;
+
+    assert (setup->dst);
+
+    status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
+    if (unlikely (status))
+	return status;
+
+    _cairo_gl_context_set_destination (ctx, setup->dst,
setup->multisample);
+    glEnable (GL_BLEND);
+    _cairo_gl_switch_operands_and_operator (setup, ctx);
+
+    status = _cairo_gl_composite_setup_clipping (setup, ctx,
ctx->vertex_size);
     if (unlikely (status))
 	goto FAIL;

@@ -938,13 +947,10 @@ _cairo_gl_composite_fini (cairo_gl_composite_t *setup)
 }

 cairo_status_t
-_cairo_gl_composite_init (cairo_gl_composite_t *setup,
-                          cairo_operator_t op,
-                          cairo_gl_surface_t *dst,
-                          cairo_bool_t assume_component_alpha)
+_cairo_gl_composite_set_operator (cairo_gl_composite_t *setup,
+				  cairo_operator_t op,
+				  cairo_bool_t assume_component_alpha)
 {
-    memset (setup, 0, sizeof (cairo_gl_composite_t));
-
     if (assume_component_alpha) {
         if (op != CAIRO_OPERATOR_CLEAR &&
             op != CAIRO_OPERATOR_OVER &&
@@ -955,8 +961,26 @@ _cairo_gl_composite_init (cairo_gl_composite_t *setup,
             return UNSUPPORTED ("unsupported operator");
     }

-    setup->dst = dst;
     setup->op = op;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_gl_composite_init (cairo_gl_composite_t *setup,
+                          cairo_operator_t op,
+                          cairo_gl_surface_t *dst,
+                          cairo_bool_t assume_component_alpha)
+{
+    cairo_status_t status;
+
+    memset (setup, 0, sizeof (cairo_gl_composite_t));
+
+    status = _cairo_gl_composite_set_operator (setup, op,
+					       assume_component_alpha);
+    if (status)
+	return status;
+
+    setup->dst = dst;
     setup->clip_region = dst->clip_region;

     return CAIRO_STATUS_SUCCESS;
diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c
index 12c416f..d96d746 100644
--- a/src/cairo-gl-msaa-compositor.c
+++ b/src/cairo-gl-msaa-compositor.c
@@ -286,6 +286,74 @@ _cairo_gl_msaa_compositor_set_clip
(cairo_composite_rectangles_t *composite,
     _cairo_gl_composite_set_clip (setup, composite->clip);
 }

+/* Masking with the SOURCE operator requires two passes. In the first
+ * pass we use the mask as the source to get:
+ * result = (1 - ma) * dst
+ * In the second pass we use the add operator to achieve:
+ * result = (src * ma) + dst
+ * Combined this produces:
+ * result = (src * ma) + (1 - ma) * dst
+ */
+static cairo_int_status_t
+_cairo_gl_msaa_compositor_mask_source_operator (const
cairo_compositor_t *compositor,
+						cairo_composite_rectangles_t *composite)
+{
+    cairo_gl_composite_t setup;
+    cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
+    cairo_gl_context_t *ctx = NULL;
+    cairo_int_status_t status;
+
+    status = _cairo_gl_composite_init (&setup,
+				       CAIRO_OPERATOR_DEST_OUT,
+				       dst,
+				       FALSE /* assume_component_alpha */);
+    if (unlikely (status))
+	return status;
+    status = _cairo_gl_composite_set_source (&setup,
+					     &composite->mask_pattern.base,
+					     &composite->mask_sample_area,
+					     &composite->bounded);
+    if (unlikely (status))
+	goto finish;
+    _cairo_gl_composite_set_clip (&setup, composite->clip);
+    _cairo_gl_composite_set_multisample (&setup);
+    status = _cairo_gl_composite_begin (&setup, &ctx);
+    if (unlikely (status))
+	goto finish;
+
+    _draw_int_rect (ctx, &setup, &composite->bounded);
+
+    /* Now draw the second pass. */
+    _cairo_gl_composite_set_operator (&setup, CAIRO_OPERATOR_ADD,
+				      FALSE /* assume_component_alpha */);
+    if (unlikely (status))
+        goto finish;
+    status = _cairo_gl_composite_set_source (&setup,
+					     &composite->source_pattern.base,
+					     &composite->source_sample_area,
+					     &composite->bounded);
+    if (unlikely (status))
+	goto finish;
+    status = _cairo_gl_composite_set_mask (&setup,
+				           &composite->mask_pattern.base,
+					   &composite->source_sample_area,
+					   &composite->bounded);
+    if (unlikely (status))
+	goto finish;
+    status = _cairo_gl_switch_operands_and_operator (&setup, ctx);
+    if (unlikely (status))
+	goto finish;
+
+    _draw_int_rect (ctx, &setup, &composite->bounded);
+
+finish:
+    _cairo_gl_composite_fini (&setup);
+    if (ctx)
+	status = _cairo_gl_context_release (ctx, status);
+
+    return status;
+}
+
 static cairo_int_status_t
 _cairo_gl_msaa_compositor_mask (const cairo_compositor_t	*compositor,
 				cairo_composite_rectangles_t	*composite)
@@ -308,12 +376,13 @@ _cairo_gl_msaa_compositor_mask (const
cairo_compositor_t	*compositor,
 	! _cairo_pattern_is_opaque (&composite->mask_pattern.base,
 				    &composite->mask_sample_area)) {

-       /* If the source is opaque the operation reduces to OVER. */
-	if (_cairo_pattern_is_opaque (&composite->source_pattern.base,
-				      &composite->source_sample_area))
-	    op = CAIRO_OPERATOR_OVER;
-	else
-	    return CAIRO_INT_STATUS_UNSUPPORTED;
+	if (! _cairo_pattern_is_opaque (&composite->source_pattern.base,
+				      &composite->source_sample_area)) {
+	    return _cairo_gl_msaa_compositor_mask_source_operator (compositor,
composite);
+	}
+
+	/* If the source is opaque the operation reduces to OVER. */
+	op = CAIRO_OPERATOR_OVER;
     }

     if (_should_use_unbounded_surface (composite)) {
@@ -713,7 +782,8 @@ _cairo_gl_msaa_compositor_glyphs (const
cairo_compositor_t	*compositor,
     info.font = scaled_font;
     info.glyphs = glyphs;
     info.num_glyphs = num_glyphs;
-    info.use_mask = overlap || ! composite->is_bounded;
+    info.use_mask = overlap || ! composite->is_bounded ||
+		    composite->op == CAIRO_OPERATOR_SOURCE;
     info.extents = composite->bounded;

     _cairo_scaled_font_freeze_cache (scaled_font);
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 57242a4..1a4d40e 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -497,6 +497,11 @@ _cairo_gl_composite_init (cairo_gl_composite_t *setup,
 cairo_private void
 _cairo_gl_composite_fini (cairo_gl_composite_t *setup);

+cairo_status_t
+_cairo_gl_composite_set_operator (cairo_gl_composite_t *setup,
+				  cairo_operator_t op,
+				  cairo_bool_t assume_component_alpha);
+
 cairo_private void
 _cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
                                      cairo_region_t *clip_region);
@@ -539,6 +544,10 @@ cairo_private cairo_status_t
 _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
                            cairo_gl_context_t **ctx);

+cairo_status_t
+_cairo_gl_switch_operands_and_operator (cairo_gl_composite_t *setup,
+					cairo_gl_context_t *ctx);
+
 cairo_private void
 _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
                                GLfloat x1,


More information about the cairo mailing list