[cairo-commit] src/cairo-gl-composite.c src/cairo-gl-device.c src/cairo-gl-msaa-compositor.c src/cairo-gl-private.h

Martin Robinson mrobinson at kemper.freedesktop.org
Thu May 17 13:57:49 PDT 2012


 src/cairo-gl-composite.c       |  164 +++++++++++++++++++++++++++++++++++------
 src/cairo-gl-device.c          |    1 
 src/cairo-gl-msaa-compositor.c |  155 +++++++-------------------------------
 src/cairo-gl-private.h         |   12 +++
 4 files changed, 181 insertions(+), 151 deletions(-)

New commits:
commit e3f5b14fbabba2128de4ee2d8513800aa145fb2f
Author: Martin Robinson <mrobinson at igalia.com>
Date:   Tue Feb 21 09:36:52 2012 -0800

    gl/msaa: Wait to clip until compositing begins
    
    The MSAA compositors clips in a unique way We'd like to
    share this method with the text rendering path, so we move
    it to cairo-gl-composite so that it works in a way very
    similar to clipping with the spans and traps compositors.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index c4d6e0b..6063dca 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -115,6 +115,13 @@ _cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
     setup->clip_region = clip_region;
 }
 
+void
+_cairo_gl_composite_set_clip (cairo_gl_composite_t *setup,
+			      cairo_clip_t *clip)
+{
+    setup->clip = clip;
+}
+
 static void
 _cairo_gl_composite_bind_to_shader (cairo_gl_context_t   *ctx,
 				    cairo_gl_composite_t *setup)
@@ -467,6 +474,132 @@ _cairo_gl_composite_begin_component_alpha  (cairo_gl_context_t *ctx,
     return CAIRO_STATUS_SUCCESS;
 }
 
+static void
+_scissor_to_box (cairo_gl_surface_t	*surface,
+		 const cairo_box_t	*box)
+{
+    double x1, y1, x2, y2, height;
+    _cairo_box_to_doubles (box, &x1, &y1, &x2, &y2);
+
+    height = y2 - y1;
+    if (_cairo_gl_surface_is_texture (surface) == FALSE)
+	y1 = surface->height - (y1 + height);
+    glScissor (x1, y1, x2 - x1, height);
+    glEnable (GL_SCISSOR_TEST);
+}
+
+static void
+_cairo_gl_composite_setup_vbo (cairo_gl_context_t *ctx,
+			       unsigned int size_per_vertex)
+{
+    if (ctx->vertex_size != size_per_vertex)
+        _cairo_gl_composite_flush (ctx);
+
+    if (_cairo_gl_context_is_flushed (ctx)) {
+        ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, ctx->vbo);
+
+	ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2,
+					   GL_FLOAT, GL_FALSE, size_per_vertex, NULL);
+	ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX);
+    }
+    ctx->vertex_size = size_per_vertex;
+}
+
+static void
+_disable_stencil_buffer (void)
+{
+    glDisable (GL_STENCIL_TEST);
+    glDepthMask (GL_FALSE);
+}
+
+static cairo_int_status_t
+_cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
+					    cairo_gl_context_t *ctx,
+					    int vertex_size)
+{
+    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
+
+    cairo_gl_surface_t *dst = setup->dst;
+    cairo_clip_t *clip = setup->clip;
+
+    if (clip->num_boxes == 1 && clip->path == NULL) {
+	_scissor_to_box (dst, &clip->boxes[0]);
+	goto disable_stencil_buffer_and_return;
+    }
+
+    /* If we cannot reduce the clip to a rectangular region,
+       we clip using the stencil buffer. */
+    glDisable (GL_SCISSOR_TEST);
+
+    if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) {
+	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	goto disable_stencil_buffer_and_return;
+    }
+
+    glDepthMask (GL_TRUE);
+    glEnable (GL_STENCIL_TEST);
+    glClearStencil (0);
+    glClear (GL_STENCIL_BUFFER_BIT);
+    glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
+    glStencilFunc (GL_EQUAL, 1, 0xffffffff);
+    glColorMask (0, 0, 0, 0);
+
+    status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip);
+
+    if (unlikely (status)) {
+	glColorMask (1, 1, 1, 1);
+	goto disable_stencil_buffer_and_return;
+    }
+
+    /* We want to only render to the stencil buffer, so draw everything now.
+       Flushing also unbinds the VBO, which we want to rebind for regular
+       drawing. */
+    _cairo_gl_composite_flush (ctx);
+    _cairo_gl_composite_setup_vbo (ctx, vertex_size);
+
+    glColorMask (1, 1, 1, 1);
+    glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
+    glStencilFunc (GL_EQUAL, 1, 0xffffffff);
+    return CAIRO_INT_STATUS_SUCCESS;
+
+disable_stencil_buffer_and_return:
+    _disable_stencil_buffer ();
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_gl_composite_setup_clipping (cairo_gl_composite_t *setup,
+				    cairo_gl_context_t *ctx,
+				    int vertex_size)
+{
+
+    if (! _cairo_gl_context_is_flushed (ctx) &&
+	(! cairo_region_equal (ctx->clip_region, setup->clip_region) ||
+	 ! _cairo_clip_equal (ctx->clip, setup->clip)))
+	_cairo_gl_composite_flush (ctx);
+
+    cairo_region_destroy (ctx->clip_region);
+    ctx->clip_region = cairo_region_reference (setup->clip_region);
+    _cairo_clip_destroy (ctx->clip);
+    ctx->clip = _cairo_clip_copy (setup->clip);
+
+    assert (!setup->clip_region || !setup->clip);
+
+    if (ctx->clip_region) {
+	_disable_stencil_buffer ();
+	glEnable (GL_SCISSOR_TEST);
+	return CAIRO_INT_STATUS_SUCCESS;
+    }
+
+    if (ctx->clip)
+	return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
+							   vertex_size);
+
+    _disable_stencil_buffer ();
+    glDisable (GL_SCISSOR_TEST);
+    return CAIRO_INT_STATUS_SUCCESS;
+}
+
 cairo_status_t
 _cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
 				       cairo_gl_context_t **ctx_out,
@@ -484,6 +617,8 @@ _cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
     if (unlikely (status))
 	return status;
 
+    _cairo_gl_context_set_destination (ctx, setup->dst, multisampling);
+
     glEnable (GL_BLEND);
 
     component_alpha =
@@ -522,23 +657,12 @@ _cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
     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);
 
-    if (ctx->vertex_size != vertex_size)
-        _cairo_gl_composite_flush (ctx);
-
-    _cairo_gl_context_set_destination (ctx, setup->dst, multisampling);
-
-    if (_cairo_gl_context_is_flushed (ctx)) {
-        ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, ctx->vbo);
-
-	ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2,
-					   GL_FLOAT, GL_FALSE, vertex_size, NULL);
-	ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX);
-    }
+    _cairo_gl_composite_setup_vbo (ctx, vertex_size);
 
     _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, vertex_size, dst_size);
     _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, vertex_size, dst_size + src_size);
@@ -549,8 +673,6 @@ _cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
 
     _cairo_gl_set_operator (ctx, setup->op, component_alpha);
 
-    ctx->vertex_size = vertex_size;
-
     if (_cairo_gl_context_is_flushed (ctx)) {
         if (ctx->pre_shader) {
             _cairo_gl_set_shader (ctx, ctx->pre_shader);
@@ -560,15 +682,9 @@ _cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
         _cairo_gl_composite_bind_to_shader (ctx, setup);
     }
 
-    if (! _cairo_gl_context_is_flushed (ctx) &&
-        ! cairo_region_equal (ctx->clip_region, setup->clip_region))
-        _cairo_gl_composite_flush (ctx);
-    cairo_region_destroy (ctx->clip_region);
-    ctx->clip_region = cairo_region_reference (setup->clip_region);
-    if (ctx->clip_region)
-	glEnable (GL_SCISSOR_TEST);
-    else
-	glDisable (GL_SCISSOR_TEST);
+    status = _cairo_gl_composite_setup_clipping (setup, ctx, vertex_size);
+    if (unlikely (status))
+	goto FAIL;
 
     *ctx_out = ctx;
 
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index ffa4b04..f2b2243 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -137,6 +137,7 @@ _gl_destroy (void *device)
     _cairo_array_fini (&ctx->tristrip_indices);
 
     cairo_region_destroy (ctx->clip_region);
+    _cairo_clip_destroy (ctx->clip);
 
     free (ctx->vb_mem);
 
diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c
index 59cb1e3..f5bb6f4 100644
--- a/src/cairo-gl-msaa-compositor.c
+++ b/src/cairo-gl-msaa-compositor.c
@@ -157,10 +157,10 @@ _draw_triangle_fan (cairo_gl_context_t		*ctx,
     return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_int_status_t
-_draw_clip (cairo_gl_context_t		*ctx,
-	    cairo_gl_composite_t	*setup,
-	    cairo_clip_t		*clip)
+cairo_int_status_t
+_cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
+				     cairo_gl_composite_t *setup,
+				     cairo_clip_t *clip)
 {
     cairo_int_status_t status;
     cairo_traps_t traps;
@@ -198,93 +198,6 @@ _draw_clip (cairo_gl_context_t		*ctx,
     return status;
 }
 
-static void
-_disable_stencil_buffer (void)
-{
-    glDisable (GL_STENCIL_TEST);
-    glDepthMask (GL_FALSE);
-}
-
-static cairo_int_status_t
-_draw_clip_to_stencil_buffer (cairo_gl_context_t	*ctx,
-			      cairo_gl_composite_t	*setup,
-			      cairo_clip_t		*clip)
-{
-    cairo_int_status_t status;
-
-    assert (! _cairo_clip_is_all_clipped (clip));
-
-    if (! _cairo_gl_ensure_stencil (ctx, setup->dst))
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    glDepthMask (GL_TRUE);
-    glEnable (GL_STENCIL_TEST);
-    glClearStencil (0);
-    glClear (GL_STENCIL_BUFFER_BIT);
-    glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
-    glStencilFunc (GL_EQUAL, 1, 0xffffffff);
-    glColorMask (0, 0, 0, 0);
-
-    status = _draw_clip (ctx, setup, clip);
-    if (unlikely (status)) {
-	glColorMask (1, 1, 1, 1);
-	_disable_stencil_buffer ();
-	return status;
-    }
-
-    /* We want to only render to the stencil buffer, so draw everything now. */
-    _cairo_gl_composite_flush (ctx);
-
-    glColorMask (1, 1, 1, 1);
-    glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
-    glStencilFunc (GL_EQUAL, 1, 0xffffffff);
-
-    return status;;
-}
-
-static void
-_scissor_to_rectangle (cairo_gl_surface_t *surface,
-		       const cairo_rectangle_int_t *r)
-{
-    int y = r->y;
-    if (_cairo_gl_surface_is_texture (surface) == FALSE)
-	y = surface->height - (r->y + r->height);
-    glScissor (r->x, y, r->width, r->height);
-    glEnable (GL_SCISSOR_TEST);
-}
-
-static cairo_int_status_t
-_scissor_and_clip (cairo_gl_context_t		*ctx,
-		   cairo_gl_composite_t		*setup,
-		   cairo_composite_rectangles_t	*composite,
-		   cairo_bool_t			*used_stencil_buffer)
-{
-    cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
-    cairo_rectangle_int_t *bounds = &composite->unbounded;
-    cairo_clip_t *clip = composite->clip;
-    cairo_rectangle_int_t r;
-
-    *used_stencil_buffer = FALSE;
-
-    if (_cairo_composite_rectangles_can_reduce_clip (composite, clip)) {
-	_scissor_to_rectangle (dst, bounds);
-	return CAIRO_INT_STATUS_SUCCESS;
-    }
-
-    /* If we cannot reduce the clip to a rectangular region,
-       we scissor and clip using the stencil buffer */
-    if (clip->num_boxes > 1 || clip->path != NULL) {
-	*used_stencil_buffer = TRUE;
-	_scissor_to_rectangle (dst, bounds);
-	return _draw_clip_to_stencil_buffer (ctx, setup, clip);
-    }
-
-    /* Always interpret the clip path as ANTIALIAS_NONE */
-    _cairo_box_round_to_rectangle (clip->boxes, &r);
-    _scissor_to_rectangle (dst, &r);
-    return CAIRO_INT_STATUS_SUCCESS;
-}
-
 static cairo_bool_t
 _should_use_unbounded_surface (cairo_composite_rectangles_t *composite)
 {
@@ -365,6 +278,15 @@ should_fall_back (cairo_gl_surface_t *surface,
     return ! surface->supports_msaa;
 }
 
+static void
+_cairo_gl_msaa_compositor_set_clip (cairo_composite_rectangles_t *composite,
+				    cairo_gl_composite_t *setup)
+{
+    if (_cairo_composite_rectangles_can_reduce_clip (composite, composite->clip))
+	return;
+    _cairo_gl_composite_set_clip (setup, composite->clip);
+}
+
 static cairo_int_status_t
 _cairo_gl_msaa_compositor_mask (const cairo_compositor_t	*compositor,
 				cairo_composite_rectangles_t	*composite)
@@ -372,7 +294,6 @@ _cairo_gl_msaa_compositor_mask (const cairo_compositor_t	*compositor,
     cairo_gl_composite_t setup;
     cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
     cairo_gl_context_t *ctx = NULL;
-    cairo_bool_t used_stencil_buffer;
     cairo_int_status_t status;
     cairo_operator_t op = composite->op;
 
@@ -447,27 +368,22 @@ _cairo_gl_msaa_compositor_mask (const cairo_compositor_t	*compositor,
     if (unlikely (status))
 	goto finish;
 
+    _cairo_gl_msaa_compositor_set_clip (composite, &setup);
+
     /* We always use multisampling here, because we do not yet have the smarts
        to calculate when the clip or the source requires it. */
     status = _cairo_gl_composite_begin_multisample (&setup, &ctx, TRUE);
     if (unlikely (status))
 	goto finish;
 
-    status = _scissor_and_clip (ctx, &setup, composite, &used_stencil_buffer);
-    if (unlikely (status))
-	goto finish;
-
     _draw_int_rect (ctx, &setup, &composite->bounded);
     _cairo_gl_composite_flush (ctx);
 
 finish:
     _cairo_gl_composite_fini (&setup);
 
-    if (ctx) {
-	glDisable (GL_SCISSOR_TEST);
-	_disable_stencil_buffer ();
+    if (ctx)
 	status = _cairo_gl_context_release (ctx, status);
-    }
 
     return status;
 }
@@ -512,8 +428,7 @@ _stroke_shaper_add_quad (void			*closure,
 static cairo_int_status_t
 _prevent_overlapping_drawing (cairo_gl_context_t *ctx,
 			      cairo_gl_composite_t *setup,
-			      cairo_composite_rectangles_t *composite,
-			      cairo_bool_t used_stencil_buffer_for_clip)
+			      cairo_composite_rectangles_t *composite)
 {
     if (! _cairo_gl_ensure_stencil (ctx, setup->dst))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -522,9 +437,9 @@ _prevent_overlapping_drawing (cairo_gl_context_t *ctx,
 				  &composite->source_sample_area))
 	return CAIRO_INT_STATUS_SUCCESS;
 
-   if (used_stencil_buffer_for_clip == FALSE) {
-	/* Enable the stencil buffer, even if we have no clip so that
-	   we can use it below to prevent overlapping shapes. We initialize
+   if (glIsEnabled (GL_STENCIL_TEST) == FALSE) {
+	/* Enable the stencil buffer, even if we are not using it for clipping,
+	   so we can use it below to prevent overlapping shapes. We initialize
 	   it all to one here which represents infinite clip. */
 	glDepthMask (GL_TRUE);
 	glEnable (GL_STENCIL_TEST);
@@ -586,7 +501,6 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t	*compositor,
     cairo_int_status_t status;
     cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
     struct _tristrip_composite_info info;
-    cairo_bool_t used_stencil_buffer_for_clip;
 
     if (should_fall_back (dst, antialias))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -626,18 +540,14 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t	*compositor,
     if (unlikely (status))
 	goto finish;
 
+    _cairo_gl_msaa_compositor_set_clip (composite, &info.setup);
+
     status = _cairo_gl_composite_begin_multisample (&info.setup, &info.ctx,
 	antialias != CAIRO_ANTIALIAS_NONE);
     if (unlikely (status))
 	goto finish;
 
-    status = _scissor_and_clip (info.ctx, &info.setup, composite,
-				&used_stencil_buffer_for_clip);
-    if (unlikely (status))
-	goto finish;
-
-    status = _prevent_overlapping_drawing (info.ctx, &info.setup, composite,
-					   used_stencil_buffer_for_clip);
+    status = _prevent_overlapping_drawing (info.ctx, &info.setup, composite);
     if (unlikely (status))
 	goto finish;
 
@@ -658,11 +568,8 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t	*compositor,
 finish:
     _cairo_gl_composite_fini (&info.setup);
 
-    if (info.ctx) {
-	glDisable (GL_SCISSOR_TEST);
-	_disable_stencil_buffer ();
+    if (info.ctx)
 	status = _cairo_gl_context_release (info.ctx, status);
-    }
 
     return status;
 }
@@ -680,7 +587,6 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t	*compositor,
     cairo_gl_context_t *ctx = NULL;
     cairo_int_status_t status;
     cairo_traps_t traps;
-    cairo_bool_t used_stencil_buffer;
 
     if (should_fall_back (dst, antialias))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -725,16 +631,13 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t	*compositor,
     if (unlikely (status))
 	goto cleanup_setup;
 
+    _cairo_gl_msaa_compositor_set_clip (composite, &setup);
+
     status = _cairo_gl_composite_begin_multisample (&setup, &ctx,
 	antialias != CAIRO_ANTIALIAS_NONE);
     if (unlikely (status))
 	goto cleanup_setup;
 
-    status = _scissor_and_clip (ctx, &setup, composite,
-				&used_stencil_buffer);
-    if (unlikely (status))
-	goto cleanup_setup;
-
     status = _draw_traps (ctx, &setup, &traps);
     if (unlikely (status))
         goto cleanup_setup;
@@ -743,11 +646,9 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t	*compositor,
 cleanup_setup:
     _cairo_gl_composite_fini (&setup);
 
-    if (ctx) {
-	glDisable (GL_SCISSOR_TEST);
-	_disable_stencil_buffer ();
+    if (ctx)
 	status = _cairo_gl_context_release (ctx, status);
-    }
+
 cleanup_traps:
     _cairo_traps_fini (&traps);
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 16353de..0664320 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -335,6 +335,7 @@ struct _cairo_gl_context {
     unsigned int vb_offset;
     unsigned int vertex_size;
     cairo_region_t *clip_region;
+    cairo_clip_t *clip;
     cairo_array_t tristrip_indices;
 
     cairo_bool_t has_mesa_pack_invert;
@@ -361,6 +362,8 @@ typedef struct _cairo_gl_composite {
     cairo_gl_operand_t src;
     cairo_gl_operand_t mask;
     cairo_bool_t spans;
+
+    cairo_clip_t *clip;
 } cairo_gl_composite_t;
 
 typedef struct _cairo_gl_font {
@@ -489,6 +492,10 @@ cairo_private void
 _cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
                                      cairo_region_t *clip_region);
 
+cairo_private void
+_cairo_gl_composite_set_clip(cairo_gl_composite_t *setup,
+			     cairo_clip_t *clip);
+
 cairo_private cairo_int_status_t
 _cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
 			        const cairo_pattern_t *pattern,
@@ -747,6 +754,11 @@ _cairo_gl_pattern_to_source (cairo_surface_t *dst,
 			     const cairo_rectangle_int_t *sample,
 			     int *src_x, int *src_y);
 
+cairo_private cairo_int_status_t
+_cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
+				     cairo_gl_composite_t *setup,
+				     cairo_clip_t *clip);
+
 cairo_private cairo_surface_t *
 _cairo_gl_white_source (void);
 


More information about the cairo-commit mailing list