[cairo-commit] 2 commits - src/cairo-gl-glyphs.c src/cairo-gl-private.h src/cairo-gl-surface.c

Eric Anholt anholt at kemper.freedesktop.org
Fri Jan 22 10:34:40 PST 2010


 src/cairo-gl-glyphs.c  |  219 ++++++++++++++++++++++++++++++++-----------------
 src/cairo-gl-private.h |    8 +
 src/cairo-gl-surface.c |    6 -
 3 files changed, 156 insertions(+), 77 deletions(-)

New commits:
commit 5914e995723682e0b1f685d9ff5ea5abe05ae024
Author: Eric Anholt <eric at anholt.net>
Date:   Fri Jan 22 09:21:36 2010 -0800

    [gl] Cache a temporary glyph compositing mask for reuse later.
    
    Cuts firefox-talos-gfx time from 56 seconds to 43 seconds.

diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index a5560eb..ecbbd0b 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -624,12 +624,25 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t	*dst,
     int i;
 
     /* XXX: For non-CA, this should be CAIRO_CONTENT_ALPHA to save memory */
-    mask = cairo_gl_surface_create (dst->ctx,
-	                            CAIRO_CONTENT_COLOR_ALPHA,
-				    glyph_extents->width,
-				    glyph_extents->height);
-    if (unlikely (mask->status))
-	return mask->status;
+    if (dst->ctx->glyphs_temporary_mask) {
+	if (glyph_extents->width <= dst->ctx->glyphs_temporary_mask->width &&
+	    glyph_extents->height <= dst->ctx->glyphs_temporary_mask->height)
+	{
+	    _cairo_gl_surface_clear (dst->ctx->glyphs_temporary_mask);
+	    mask = &dst->ctx->glyphs_temporary_mask->base;
+	} else {
+	    cairo_surface_destroy (&dst->ctx->glyphs_temporary_mask->base);
+	    dst->ctx->glyphs_temporary_mask = NULL;
+	}
+    }
+    if (!mask) {
+	mask = cairo_gl_surface_create (dst->ctx,
+					CAIRO_CONTENT_COLOR_ALPHA,
+					glyph_extents->width,
+					glyph_extents->height);
+	if (unlikely (mask->status))
+	    return mask->status;
+    }
 
     for (i = 0; i < num_glyphs; i++) {
 	glyphs[i].x -= glyph_extents->x;
@@ -661,7 +674,9 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t	*dst,
 	*remaining_glyphs = num_glyphs;
     }
 
-    cairo_surface_destroy (mask);
+    if (!dst->ctx->glyphs_temporary_mask)
+	dst->ctx->glyphs_temporary_mask = (cairo_gl_surface_t *)mask;
+
     return status;
 }
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 585557b..7d157d8 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -91,6 +91,7 @@ struct _cairo_gl_context {
     GLint max_texture_size;
 
     cairo_gl_surface_t *current_target;
+    cairo_gl_surface_t *glyphs_temporary_mask;
     cairo_gl_glyph_cache_t glyph_cache[2];
 
     void (*make_current)(void *ctx, cairo_gl_surface_t *surface);
@@ -169,6 +170,9 @@ cairo_private cairo_bool_t
 _cairo_gl_operator_is_supported (cairo_operator_t op);
 
 cairo_private void
+_cairo_gl_surface_clear (cairo_gl_surface_t *surface);
+
+cairo_private void
 _cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op,
 			cairo_bool_t component_alpha);
 
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 392a0a8..5335e4b 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -176,6 +176,8 @@ cairo_gl_context_destroy (cairo_gl_context_t *context)
 
     context->destroy (context);
 
+    cairo_surface_destroy (&context->glyphs_temporary_mask->base);
+
     free (context);
 }
 slim_hidden_def (cairo_gl_context_destroy);
@@ -541,7 +543,7 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
     return &surface->base;
 }
 
-static void
+void
 _cairo_gl_surface_clear (cairo_gl_surface_t *surface)
 {
     cairo_gl_context_t *ctx;
commit 1bf0f64ee7783742fa777a496567e4da48e300dd
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Jan 21 14:08:11 2010 -0800

    [gl] Composite component-alpha glyphs directly instead of through a mask.
    
    Cuts gnome-terminal-vim time from 58 seconds to 20.

diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index dbc7100..a5560eb 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -40,6 +40,13 @@
 #define GLYPH_CACHE_MIN_SIZE 4
 #define GLYPH_CACHE_MAX_SIZE 128
 
+typedef enum _cairo_gl_glyphs_shader {
+    CAIRO_GL_GLYPHS_SHADER_UNSET,
+    CAIRO_GL_GLYPHS_SHADER_NORMAL,
+    CAIRO_GL_GLYPHS_SHADER_CA_SOURCE_ALPHA,
+    CAIRO_GL_GLYPHS_SHADER_CA_SOURCE,
+} cairo_gl_glyphs_shader_t;
+
 typedef struct _cairo_gl_glyph_private {
     cairo_rtree_node_t node;
     cairo_gl_glyph_cache_t *cache;
@@ -239,42 +246,117 @@ typedef struct _cairo_gl_glyphs_setup
     cairo_gl_composite_setup_t *composite;
     cairo_region_t *clip;
     cairo_gl_surface_t *dst;
+    cairo_gl_glyphs_shader_t shader;
+    cairo_operator_t op;
+    cairo_bool_t component_alpha;
 } cairo_gl_glyphs_setup_t;
 
 static void
+_cairo_gl_glyphs_set_shader (cairo_gl_context_t *ctx,
+			     cairo_gl_glyphs_setup_t *setup,
+			     cairo_gl_glyphs_shader_t shader)
+{
+    if (setup->shader == shader)
+	return;
+
+    setup->shader = shader;
+
+    if (shader != CAIRO_GL_GLYPHS_SHADER_CA_SOURCE_ALPHA)
+	_cairo_gl_set_src_operand (ctx, setup->composite);
+    else
+	_cairo_gl_set_src_alpha_operand (ctx, setup->composite);
+
+    /* Set up the IN operator for source IN mask.
+     *
+     * IN (normal, any op): dst.argb = src.argb * mask.aaaa
+     * IN (component, ADD): dst.argb = src.argb * mask.argb
+     *
+     * The mask channel selection for component alpha ADD will be updated in
+     * the loop over glyphs below.
+     */
+    glActiveTexture (GL_TEXTURE1);
+    glEnable (GL_TEXTURE_2D);
+    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+
+    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE1);
+    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE1);
+    if (setup->shader == CAIRO_GL_GLYPHS_SHADER_NORMAL)
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
+    else
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
+    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
+    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS);
+    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+}
+
+static void
+_cairo_gl_glyphs_draw (cairo_gl_context_t *ctx,
+		       cairo_gl_glyphs_setup_t *setup)
+{
+    if (!setup->component_alpha || setup->op != CAIRO_OPERATOR_OVER) {
+	glDrawArrays (GL_QUADS, 0, 4 * setup->num_prims);
+    } else {
+	_cairo_gl_set_operator (setup->dst, CAIRO_OPERATOR_DEST_OUT, TRUE);
+	_cairo_gl_glyphs_set_shader(ctx, setup,
+				    CAIRO_GL_GLYPHS_SHADER_CA_SOURCE_ALPHA);
+	glDrawArrays (GL_QUADS, 0, 4 * setup->num_prims);
+
+	_cairo_gl_set_operator (setup->dst, CAIRO_OPERATOR_ADD, TRUE);
+	_cairo_gl_glyphs_set_shader(ctx, setup,
+				    CAIRO_GL_GLYPHS_SHADER_CA_SOURCE);
+	glDrawArrays (GL_QUADS, 0, 4 * setup->num_prims);
+    }
+}
+
+static void
 _cairo_gl_flush_glyphs (cairo_gl_context_t *ctx,
 			cairo_gl_glyphs_setup_t *setup)
 {
     int i;
 
-    if (setup->vb != NULL) {
-	glUnmapBufferARB (GL_ARRAY_BUFFER_ARB);
-	setup->vb = NULL;
+    if (setup->vb == NULL)
+	return;
+
+    glUnmapBufferARB (GL_ARRAY_BUFFER_ARB);
+    setup->vb = NULL;
+
+    if (setup->num_prims == 0)
+	return;
 
-	if (setup->num_prims != 0) {
-	    if (setup->clip) {
-		int num_rectangles = cairo_region_num_rectangles (setup->clip);
+    if (!setup->component_alpha) {
+	_cairo_gl_set_operator (setup->dst, setup->op, FALSE);
+	_cairo_gl_glyphs_set_shader(ctx, setup, CAIRO_GL_GLYPHS_SHADER_NORMAL);
+    } else if (setup->op == CAIRO_OPERATOR_ADD) {
+	_cairo_gl_set_operator (setup->dst, setup->op, FALSE);
+	_cairo_gl_glyphs_set_shader(ctx, setup, CAIRO_GL_GLYPHS_SHADER_CA_SOURCE);
+    }
 
-		glEnable (GL_SCISSOR_TEST);
-		for (i = 0; i < num_rectangles; i++) {
-		    cairo_rectangle_int_t rect;
+    if (setup->clip) {
+	int num_rectangles = cairo_region_num_rectangles (setup->clip);
 
-		    cairo_region_get_rectangle (setup->clip, i, &rect);
+	glEnable (GL_SCISSOR_TEST);
+	for (i = 0; i < num_rectangles; i++) {
+	    cairo_rectangle_int_t rect;
 
-		    glScissor (rect.x,
-			       _cairo_gl_y_flip (setup->dst, rect.y),
-			       rect.x + rect.width,
-			       _cairo_gl_y_flip (setup->dst,
-						 rect.y + rect.height));
-		    glDrawArrays (GL_QUADS, 0, 4 * setup->num_prims);
-		}
-		glDisable (GL_SCISSOR_TEST);
-	    } else {
-		glDrawArrays (GL_QUADS, 0, 4 * setup->num_prims);
-	    }
-	    setup->num_prims = 0;
+	    cairo_region_get_rectangle (setup->clip, i, &rect);
+
+	    glScissor (rect.x,
+		       _cairo_gl_y_flip (setup->dst, rect.y),
+		       rect.x + rect.width,
+		       _cairo_gl_y_flip (setup->dst,
+					 rect.y + rect.height));
+	    _cairo_gl_glyphs_draw (ctx, setup);
 	}
+	glDisable (GL_SCISSOR_TEST);
+    } else {
+	_cairo_gl_glyphs_draw (ctx, setup);
     }
+    setup->num_prims = 0;
 }
 
 static void
@@ -366,36 +448,7 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 
     ctx = _cairo_gl_context_acquire (dst->ctx);
 
-    /* Set up the IN operator for source IN mask.
-     *
-     * IN (normal, any op): dst.argb = src.argb * mask.aaaa
-     * IN (component, ADD): dst.argb = src.argb * mask.argb
-     *
-     * The mask channel selection for component alpha ADD will be updated in
-     * the loop over glyphs below.
-     */
-    glActiveTexture (GL_TEXTURE1);
-    glEnable (GL_TEXTURE_2D);
-    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
-    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
-    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
-
-    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE1);
-    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE1);
-    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
-    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
-
-    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
-    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS);
-    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
-    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
-
     _cairo_gl_set_destination (dst);
-    /* If we're doing some CA glyphs, we're only doing it for ADD,
-     * which doesn't require the source alpha value in blending.
-     */
-    _cairo_gl_set_operator (dst, op, FALSE);
-    _cairo_gl_set_src_operand (ctx, &composite_setup);
 
     _cairo_scaled_font_freeze_cache (scaled_font);
     if (! _cairo_gl_surface_owns_font (dst, scaled_font)) {
@@ -422,6 +475,8 @@ _render_glyphs (cairo_gl_surface_t	*dst,
     setup.vbo_size = num_glyphs * 4 * setup.vertex_size;
     if (setup.vbo_size > 4096)
 	setup.vbo_size = 4096;
+    setup.op = op;
+    setup.shader = CAIRO_GL_GLYPHS_SHADER_UNSET;
 
     glGenBuffersARB (1, &vbo);
     glBindBufferARB (GL_ARRAY_BUFFER_ARB, vbo);
@@ -483,14 +538,11 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 	     * need to make sure we send the rgb bits down to the destination.
 	     */
 	    if (last_format == CAIRO_FORMAT_ARGB32) {
-		assert (op == CAIRO_OPERATOR_ADD);
-		glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 		*has_component_alpha = TRUE;
+		setup.component_alpha = TRUE;
 	    } else {
-		glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
+		setup.component_alpha = FALSE;
 	    }
-
-	    /* XXX component alpha */
 	}
 
 	if (scaled_glyph->surface_private == NULL) {
@@ -646,18 +698,20 @@ _cairo_gl_surface_show_glyphs (void			*abstract_dst,
      * since only _cairo_gl_surface_composite() currently supports component
      * alpha.
      */
-    for (i = 0; i < num_glyphs; i++) {
-	cairo_scaled_glyph_t *scaled_glyph;
-
-	status = _cairo_scaled_glyph_lookup (scaled_font,
-					     glyphs[i].index,
-					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
-					     &scaled_glyph);
-	if (!_cairo_status_is_error (status) &&
-	    scaled_glyph->surface->format == CAIRO_FORMAT_ARGB32)
-	{
-	    use_mask = TRUE;
-	    break;
+    if (!use_mask && op != CAIRO_OPERATOR_OVER) {
+	for (i = 0; i < num_glyphs; i++) {
+	    cairo_scaled_glyph_t *scaled_glyph;
+
+	    status = _cairo_scaled_glyph_lookup (scaled_font,
+						 glyphs[i].index,
+						 CAIRO_SCALED_GLYPH_INFO_SURFACE,
+						 &scaled_glyph);
+	    if (!_cairo_status_is_error (status) &&
+		scaled_glyph->surface->format == CAIRO_FORMAT_ARGB32)
+	    {
+		use_mask = TRUE;
+		break;
+	    }
 	}
     }
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 490bc5c..585557b 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -177,6 +177,10 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
 			   cairo_gl_composite_setup_t *setup);
 
 cairo_private void
+_cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
+				 cairo_gl_composite_setup_t *setup);
+
+cairo_private void
 _cairo_gl_operand_destroy (cairo_gl_composite_operand_t *operand);
 
 cairo_private cairo_bool_t
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 2acc8b5..392a0a8 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1216,7 +1216,7 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
  * for creating the "source alpha" value (src.aaaa * mask.argb) required by
  * component alpha rendering.
  */
-static void
+void
 _cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
 				 cairo_gl_composite_setup_t *setup)
 {


More information about the cairo-commit mailing list