[cairo] [PATCH] gl/msaa: Only clear parts of the stencil buffer we will use

Martin Robinson mrobinson at igalia.com
Sun Dec 30 10:34:42 PST 2012


commit f81016dd38a2b1bb8d18bb3a37181ec83d143189
Author: Henry Song <henry.song at samsung.com>
Date:   Mon May 21 10:03:53 2012 +0200

    gl/msaa: Only clear parts of the stencil buffer we will use
    
    Writing to the stencil buffer can be expensive, so when using the
    stencil buffer for clipping only clear the clip extent. When using the
    stencil buffer to prevent overlapping rendering during stroking, only
    clear the approximate stroke extents.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index dbd4e02..196a50a 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -501,8 +501,8 @@ _scissor_to_doubles (cairo_gl_surface_t	*surface,
     glEnable (GL_SCISSOR_TEST);
 }
 
-static void
-_scissor_to_rectangle (cairo_gl_surface_t *surface,
+void
+_cairo_gl_scissor_to_rectangle (cairo_gl_surface_t *surface,
 		       const cairo_rectangle_int_t *r)
 {
     _scissor_to_doubles (surface, r->x, r->y, r->x+r->width, r->y+r->height);
@@ -555,19 +555,22 @@ _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
 	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;
     }
 
+    /* The clip is not rectangular, so use the stencil buffer. */
     glDepthMask (GL_TRUE);
     glEnable (GL_STENCIL_TEST);
+
+    /* Clear the stencil buffer, but only the areas that we are
+     * going to be drawing to. */
+    _cairo_gl_scissor_to_rectangle (dst, _cairo_clip_get_extents (clip));
     glClearStencil (0);
     glClear (GL_STENCIL_BUFFER_BIT);
+    glDisable (GL_SCISSOR_TEST);
+
     glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
     glStencilFunc (GL_EQUAL, 1, 0xffffffff);
     glColorMask (0, 0, 0, 0);
@@ -787,7 +790,7 @@ _cairo_gl_composite_draw_triangles_with_clip_region (cairo_gl_context_t *ctx,
 
 	cairo_region_get_rectangle (ctx->clip_region, i, &rect);
 
-	_scissor_to_rectangle (ctx->current_target, &rect);
+	_cairo_gl_scissor_to_rectangle (ctx->current_target, &rect);
 	_cairo_gl_composite_draw_triangles (ctx, count);
     }
 }
diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c
index 03bc658..499a923 100644
--- a/src/cairo-gl-msaa-compositor.c
+++ b/src/cairo-gl-msaa-compositor.c
@@ -539,10 +539,15 @@ _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)
+_prevent_overlapping_strokes (cairo_gl_context_t 		*ctx,
+			      cairo_gl_composite_t 		*setup,
+			      cairo_composite_rectangles_t 	*composite,
+			      const cairo_path_fixed_t		*path,
+			      const cairo_stroke_style_t	*style,
+			      const cairo_matrix_t		*ctm)
 {
+    cairo_rectangle_int_t stroke_extents;
+
     if (! _cairo_gl_ensure_stencil (ctx, setup->dst))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
@@ -551,13 +556,33 @@ _prevent_overlapping_drawing (cairo_gl_context_t *ctx,
 	return CAIRO_INT_STATUS_SUCCESS;
 
    if (glIsEnabled (GL_STENCIL_TEST) == FALSE) {
+	cairo_bool_t scissor_was_enabled;
+
+       /* In case we have pending operations we have to flush before
+	  adding the stencil buffer. */
+       _cairo_gl_composite_flush (ctx);
+
 	/* 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);
+
+	/* We scissor here so that we don't have to clear the entire stencil
+	 * buffer. If the scissor test is already enabled, it was enabled
+	 * for clipping. In that case, instead of calculating an intersection,
+	 * we just reuse it, and risk clearing too much. */
+	scissor_was_enabled = glIsEnabled (GL_SCISSOR_TEST);
+	if (! scissor_was_enabled) {
+	    _cairo_path_fixed_approximate_stroke_extents (path, style, ctm,
+							  &stroke_extents);
+	    _cairo_gl_scissor_to_rectangle (setup->dst, &stroke_extents);
+	}
 	glClearStencil (1);
 	glClear (GL_STENCIL_BUFFER_BIT);
+	if (! scissor_was_enabled)
+	    glDisable (GL_SCISSOR_TEST);
+
 	glStencilFunc (GL_EQUAL, 1, 1);
     }
 
@@ -661,7 +686,8 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t	*compositor,
     if (unlikely (status))
 	goto finish;
 
-    status = _prevent_overlapping_drawing (info.ctx, &info.setup, composite);
+    status = _prevent_overlapping_strokes (info.ctx, &info.setup,
+					   composite, path, style, ctm);
     if (unlikely (status))
 	goto finish;
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 56f55ea..a1e18e1 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -789,6 +789,10 @@ _cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
 cairo_private cairo_surface_t *
 _cairo_gl_white_source (void);
 
+void
+_cairo_gl_scissor_to_rectangle (cairo_gl_surface_t *surface,
+				const cairo_rectangle_int_t *r);
+
 static inline cairo_gl_operand_t *
 source_to_operand (cairo_surface_t *surface)
 {


More information about the cairo mailing list