[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