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

Martin Robinson <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <[email protected]>
Note that I'm not the original author. Thus, I've included the full
commit below.

commit 038ea9d46cd140da796c97b27107fab8d7bd9837
Author: Henry Song <[email protected]>
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,
-- 
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.