[cairo-commit] configure.ac src/cairo-image-compositor.c src/cairoint.h src/cairo-mutex-list-private.h src/cairo-scaled-font.c

Søren Sandmann Pedersen sandmann at kemper.freedesktop.org
Sat Jun 9 12:55:25 PDT 2012


 configure.ac                   |    2 
 src/cairo-image-compositor.c   |  361 ++++++++++++-----------------------------
 src/cairo-mutex-list-private.h |    1 
 src/cairo-scaled-font.c        |    2 
 src/cairoint.h                 |    4 
 5 files changed, 121 insertions(+), 249 deletions(-)

New commits:
commit 615205cf072935401dac46813b597e70bc8f0a8c
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Mon Apr 30 09:41:44 2012 -0400

    Use the new pixman_glyph_cache_t API that will be in pixman 0.28.0
    
    This new pixman API allows glyphs to be cached and composited in one
    go, which reduces overhead compared to individual calls to
    pixman_image_composite_region32().
    
    Notes:
    
    - There is an explicit call to _cairo_image_scaled_glyph_fini(). This
      could instead be done with a private, but I chose not to do that
      since we don't need to store any actual data; we only need
      notification when the glyph dies.
    
    - The slowdown in poppler-reseau is real and stable across runs. I'm
      not too concerned about it because this benchmark is only one run
      and so it is dominated by glyph cache setup costs and FreeType
      rasterizing.
    
    Performance results, image backend:
    
        Speedups
           firefox-talos-gfx  5571.55 -> 4265.57:  1.31x speedup
          gnome-terminal-vim  1875.82 -> 1715.14:  1.09x speedup
                   evolution  1128.24 -> 1047.68:  1.08x speedup
           xfce4-terminal-a1  1364.38 -> 1277.48:  1.07x speedup
    
        Slowdowns
              poppler-reseau   374.42 ->  394.29:  1.05x slowdown
    
    Performance results, image16 backend:
    
        Speedups
           firefox-talos-gfx  5387.25 -> 4065.39:  1.33x speedup
          gnome-terminal-vim  2116.66 -> 1962.79:  1.08x speedup
                   evolution   987.50 ->  924.27:  1.07x speedup
           xfce4-terminal-a1  1856.85 -> 1748.25:  1.06x speedup
                        gvim  1484.07 -> 1398.75:  1.06x speedup
    
        Slowdowns
              poppler-reseau   371.37 ->  393.99:  1.06x slowdown
    
    Also bump pixman requirement to 0.27.1.

diff --git a/configure.ac b/configure.ac
index 0fd1da1..a721cdf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -619,7 +619,7 @@ CAIRO_ENABLE(test_surfaces, test surfaces, no)
 dnl ===========================================================================
 
 CAIRO_ENABLE_SURFACE_BACKEND(image, image, always, [
-  pixman_REQUIRES="pixman-1 >= 0.22.0"
+  pixman_REQUIRES="pixman-1 >= 0.27.1"
   PKG_CHECK_MODULES(pixman, $pixman_REQUIRES, , [AC_MSG_RESULT(no)
   use_image="no (requires $pixman_REQUIRES http://cairographics.org/releases/)"])
   image_REQUIRES=$pixman_REQUIRES
diff --git a/src/cairo-image-compositor.c b/src/cairo-image-compositor.c
index a36a991..a55dade 100644
--- a/src/cairo-image-compositor.c
+++ b/src/cairo-image-compositor.c
@@ -750,223 +750,38 @@ composite_tristrip (void			*_dst,
     return  CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_int_status_t
-check_composite_glyphs (const cairo_composite_rectangles_t *extents,
-			cairo_scaled_font_t *scaled_font,
-			cairo_glyph_t *glyphs,
-			int *num_glyphs)
-{
-    return CAIRO_STATUS_SUCCESS;
-}
+static pixman_glyph_cache_t *global_glyph_cache;
 
-static cairo_int_status_t
-composite_one_glyph (void				*_dst,
-		     cairo_operator_t			 op,
-		     cairo_surface_t			*_src,
-		     int				 src_x,
-		     int				 src_y,
-		     int				 dst_x,
-		     int				 dst_y,
-		     cairo_composite_glyphs_info_t	 *info)
+static inline pixman_glyph_cache_t *
+get_glyph_cache (void)
 {
-    cairo_image_surface_t *glyph_surface;
-    cairo_scaled_glyph_t *scaled_glyph;
-    cairo_status_t status;
-    int x, y;
-
-    TRACE ((stderr, "%s\n", __FUNCTION__));
-
-    status = _cairo_scaled_glyph_lookup (info->font,
-					 info->glyphs[0].index,
-					 CAIRO_SCALED_GLYPH_INFO_SURFACE,
-					 &scaled_glyph);
+    if (!global_glyph_cache)
+	global_glyph_cache = pixman_glyph_cache_create ();
 
-    if (unlikely (status))
-	return status;
-
-    glyph_surface = scaled_glyph->surface;
-    if (glyph_surface->width == 0 || glyph_surface->height == 0)
-	return CAIRO_INT_STATUS_NOTHING_TO_DO;
-
-    /* round glyph locations to the nearest pixel */
-    /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
-    x = _cairo_lround (info->glyphs[0].x -
-		       glyph_surface->base.device_transform.x0);
-    y = _cairo_lround (info->glyphs[0].y -
-		       glyph_surface->base.device_transform.y0);
-
-    pixman_image_composite32 (_pixman_operator (op),
-			      ((cairo_image_source_t *)_src)->pixman_image,
-			      glyph_surface->pixman_image,
-			      to_pixman_image (_dst),
-			      x + src_x,  y + src_y,
-			      0, 0,
-			      x - dst_x, y - dst_y,
-			      glyph_surface->width,
-			      glyph_surface->height);
-
-    return CAIRO_INT_STATUS_SUCCESS;
+    return global_glyph_cache;
 }
 
-static cairo_int_status_t
-composite_glyphs_via_mask (void				*_dst,
-			   cairo_operator_t		 op,
-			   cairo_surface_t		*_src,
-			   int				 src_x,
-			   int				 src_y,
-			   int				 dst_x,
-			   int				 dst_y,
-			   cairo_composite_glyphs_info_t *info)
+void
+_cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
+				cairo_scaled_glyph_t *scaled_glyph)
 {
-    cairo_scaled_glyph_t *glyph_cache[64];
-    pixman_image_t *white = _pixman_image_for_color (CAIRO_COLOR_WHITE);
-    cairo_scaled_glyph_t *scaled_glyph;
-    uint8_t buf[2048];
-    pixman_image_t *mask;
-    pixman_format_code_t format;
-    cairo_status_t status;
-    int i;
-
-    TRACE ((stderr, "%s\n", __FUNCTION__));
-
-    if (unlikely (white == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    /* XXX convert the glyphs to common formats a8/a8r8g8b8 to hit
-     * optimised paths through pixman. Should we increase the bit
-     * depth of the target surface, we should reconsider the appropriate
-     * mask formats.
-     */
-
-    status = _cairo_scaled_glyph_lookup (info->font,
-					 info->glyphs[0].index,
-					 CAIRO_SCALED_GLYPH_INFO_SURFACE,
-					 &scaled_glyph);
-    if (unlikely (status)) {
-	pixman_image_unref (white);
-	return status;
-    }
-
-    memset (glyph_cache, 0, sizeof (glyph_cache));
-    glyph_cache[info->glyphs[0].index % ARRAY_LENGTH (glyph_cache)] = scaled_glyph;
-
-    format = PIXMAN_a8;
-    i = (info->extents.width + 3) & ~3;
-    if (scaled_glyph->surface->base.content & CAIRO_CONTENT_COLOR) {
-	format = PIXMAN_a8r8g8b8;
-	i = info->extents.width * 4;
-    }
+    CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
 
-    if (i * info->extents.height > (int) sizeof (buf)) {
-	mask = pixman_image_create_bits (format,
-					info->extents.width,
-					info->extents.height,
-					NULL, 0);
-    } else {
-	memset (buf, 0, i * info->extents.height);
-	mask = pixman_image_create_bits (format,
-					info->extents.width,
-					info->extents.height,
-					(uint32_t *)buf, i);
-    }
-    if (unlikely (mask == NULL)) {
-	pixman_image_unref (white);
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    if (global_glyph_cache) {
+	pixman_glyph_cache_remove (
+	    global_glyph_cache, scaled_font,
+	    (void *)_cairo_scaled_glyph_index (scaled_glyph));
     }
 
-    status = CAIRO_STATUS_SUCCESS;
-    for (i = 0; i < info->num_glyphs; i++) {
-	unsigned long glyph_index = info->glyphs[i].index;
-	int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
-	cairo_image_surface_t *glyph_surface;
-	int x, y;
-
-	scaled_glyph = glyph_cache[cache_index];
-	if (scaled_glyph == NULL ||
-	    _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
-	{
-	    status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
-						 CAIRO_SCALED_GLYPH_INFO_SURFACE,
-						 &scaled_glyph);
-
-	    if (unlikely (status)) {
-		pixman_image_unref (mask);
-		pixman_image_unref (white);
-		return status;
-	    }
-
-	    glyph_cache[cache_index] = scaled_glyph;
-	}
-
-	glyph_surface = scaled_glyph->surface;
-	if (glyph_surface->width && glyph_surface->height) {
-	    if (glyph_surface->base.content & CAIRO_CONTENT_COLOR &&
-		format == PIXMAN_a8) {
-		pixman_image_t *ca_mask;
-
-		format = PIXMAN_a8r8g8b8;
-		ca_mask = pixman_image_create_bits (format,
-						    info->extents.width,
-						    info->extents.height,
-						    NULL, 0);
-		if (unlikely (ca_mask == NULL)) {
-		    pixman_image_unref (mask);
-		    pixman_image_unref (white);
-		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-		}
-
-		pixman_image_composite32 (PIXMAN_OP_SRC,
-					  white, mask, ca_mask,
-					  0, 0,
-					  0, 0,
-					  0, 0,
-					  info->extents.width,
-					  info->extents.height);
-		pixman_image_unref (mask);
-		mask = ca_mask;
-	    }
-
-	    /* round glyph locations to the nearest pixel */
-	    /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
-	    x = _cairo_lround (info->glyphs[i].x -
-			       glyph_surface->base.device_transform.x0);
-	    y = _cairo_lround (info->glyphs[i].y -
-			       glyph_surface->base.device_transform.y0);
-
-	    if (glyph_surface->pixman_format == format) {
-		pixman_image_composite32 (PIXMAN_OP_ADD,
-					  glyph_surface->pixman_image, NULL, mask,
-					  0, 0,
-					  0, 0,
-					  x - info->extents.x, y - info->extents.y,
-					  glyph_surface->width,
-					  glyph_surface->height);
-	    } else {
-		pixman_image_composite32 (PIXMAN_OP_ADD,
-					  white, glyph_surface->pixman_image, mask,
-					  0, 0,
-					  0, 0,
-					  x - info->extents.x, y - info->extents.y,
-					  glyph_surface->width,
-					  glyph_surface->height);
-	    }
-	}
-    }
-
-    if (format == PIXMAN_a8r8g8b8)
-	pixman_image_set_component_alpha (mask, TRUE);
-
-    pixman_image_composite32 (_pixman_operator (op),
-			      ((cairo_image_source_t *)_src)->pixman_image,
-			      mask,
-			      to_pixman_image (_dst),
-			      info->extents.x + src_x, info->extents.y + src_y,
-			      0, 0,
-			      info->extents.x - dst_x, info->extents.y - dst_y,
-			      info->extents.width, info->extents.height);
-    pixman_image_unref (mask);
-    pixman_image_unref (white);
+    CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
+}
 
+static cairo_int_status_t
+check_composite_glyphs (const cairo_composite_rectangles_t *extents,
+			cairo_scaled_font_t *scaled_font,
+			cairo_glyph_t *glyphs,
+			int *num_glyphs)
+{
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -980,65 +795,115 @@ composite_glyphs (void				*_dst,
 		  int				 dst_y,
 		  cairo_composite_glyphs_info_t *info)
 {
-    cairo_scaled_glyph_t *glyph_cache[64];
-    pixman_image_t *dst, *src;
     cairo_status_t status;
+    pixman_glyph_cache_t *glyph_cache;
+    pixman_glyph_t pglyphs_stack[CAIRO_STACK_ARRAY_LENGTH (pixman_glyph_t)];
+    pixman_glyph_t *pglyphs = pglyphs_stack;
+    pixman_glyph_t *pg;
     int i;
 
     TRACE ((stderr, "%s\n", __FUNCTION__));
 
-    if (info->num_glyphs == 1)
-	return composite_one_glyph(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
+    CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
 
-    if (info->use_mask)
-	return composite_glyphs_via_mask(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
+    glyph_cache = get_glyph_cache();
 
-    op = _pixman_operator (op);
-    dst = to_pixman_image (_dst);
-    src = ((cairo_image_source_t *)_src)->pixman_image;
+    if (unlikely (!glyph_cache)) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto out_no_glyph_cache;
+    }
 
-    memset (glyph_cache, 0, sizeof (glyph_cache));
-    status = CAIRO_STATUS_SUCCESS;
+    pixman_glyph_cache_freeze (glyph_cache);
+    
+    if (info->num_glyphs > ARRAY_LENGTH (pglyphs_stack)) {
+	pglyphs = _cairo_malloc_ab (info->num_glyphs, sizeof (pixman_glyph_t));
 
+	if (unlikely (!pglyphs)) {
+	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    goto out;
+	}
+    }
+	
+    if (unlikely (!glyph_cache)) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto out;
+    }
+    
+    pg = pglyphs;
     for (i = 0; i < info->num_glyphs; i++) {
-	int x, y;
-	cairo_image_surface_t *glyph_surface;
-	cairo_scaled_glyph_t *scaled_glyph;
-	unsigned long glyph_index = info->glyphs[i].index;
-	int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
-
-	scaled_glyph = glyph_cache[cache_index];
-	if (scaled_glyph == NULL ||
-	    _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
-	{
-	    status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
+	unsigned long index = info->glyphs[i].index;
+	const void *glyph;
+
+	glyph = pixman_glyph_cache_lookup (glyph_cache, info->font, (void *)index);
+	if (!glyph) {
+	    cairo_scaled_glyph_t *scaled_glyph;
+	    cairo_image_surface_t *glyph_surface;
+
+	    /* This call can actually end up recursing, so we have to
+	     * drop the mutex around it.
+	     */
+	    CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
+	    status = _cairo_scaled_glyph_lookup (info->font, index,
 						 CAIRO_SCALED_GLYPH_INFO_SURFACE,
 						 &scaled_glyph);
+	    CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
 
 	    if (unlikely (status))
-		break;
-
-	    glyph_cache[cache_index] = scaled_glyph;
+		goto out;
+
+	    glyph_surface = scaled_glyph->surface;
+
+	    if (!glyph) {
+		glyph = pixman_glyph_cache_insert (glyph_cache, info->font, (void *)index,
+						   glyph_surface->base.device_transform.x0,
+						   glyph_surface->base.device_transform.y0,
+						   glyph_surface->pixman_image);
+		if (unlikely (!glyph)) {
+		    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+		    
+		    goto out;
+		}
+	    }
 	}
+		
+	pg->x = _cairo_lround (info->glyphs[i].x);
+	pg->y = _cairo_lround (info->glyphs[i].y);
+	pg->glyph = glyph;
+	pg++;
+    }
 
-	glyph_surface = scaled_glyph->surface;
-	if (glyph_surface->width && glyph_surface->height) {
-	    /* round glyph locations to the nearest pixel */
-	    /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
-	    x = _cairo_lround (info->glyphs[i].x -
-			       glyph_surface->base.device_transform.x0);
-	    y = _cairo_lround (info->glyphs[i].y -
-			       glyph_surface->base.device_transform.y0);
-
-	    pixman_image_composite32 (op, src, glyph_surface->pixman_image, dst,
-                                      x + src_x,  y + src_y,
-                                      0, 0,
-                                      x - dst_x, y - dst_y,
-				      glyph_surface->width,
-				      glyph_surface->height);
-	}
+    if (info->use_mask)
+    {
+	pixman_format_code_t mask_format;
+
+	mask_format = pixman_glyph_get_mask_format (glyph_cache, pg - pglyphs, pglyphs);
+	
+	pixman_composite_glyphs (_pixman_operator (op),
+				 ((cairo_image_source_t *)_src)->pixman_image,
+				 to_pixman_image (_dst),
+				 mask_format,
+				 info->extents.x + src_x, info->extents.y + src_y,
+				 info->extents.x, info->extents.y,
+				 info->extents.x - dst_x, info->extents.y - dst_y,
+				 info->extents.width, info->extents.height,
+				 glyph_cache, pg - pglyphs, pglyphs);
+    }
+    else
+    {
+	pixman_composite_glyphs_no_mask (_pixman_operator (op),
+					 ((cairo_image_source_t *)_src)->pixman_image,
+					 to_pixman_image (_dst),
+					 src_x, src_y,
+					 - dst_x, - dst_y,
+					 glyph_cache, pg - pglyphs, pglyphs);
     }
 
+out:
+    pixman_glyph_cache_thaw (glyph_cache);
+
+out_no_glyph_cache:
+    CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
+    
     return status;
 }
 
diff --git a/src/cairo-mutex-list-private.h b/src/cairo-mutex-list-private.h
index 4016f8e..f46afad 100644
--- a/src/cairo-mutex-list-private.h
+++ b/src/cairo-mutex-list-private.h
@@ -45,6 +45,7 @@ CAIRO_MUTEX_DECLARE (_cairo_intern_string_mutex)
 CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex)
 CAIRO_MUTEX_DECLARE (_cairo_scaled_glyph_page_cache_mutex)
 CAIRO_MUTEX_DECLARE (_cairo_scaled_font_error_mutex)
+CAIRO_MUTEX_DECLARE (_cairo_glyph_cache_mutex)
 
 #if CAIRO_HAS_FT_FONT
 CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex)
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index fe22f54..8c2b645 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -212,6 +212,8 @@ _cairo_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
 	private->destroy (private, scaled_glyph, scaled_font);
     }
 
+    _cairo_image_scaled_glyph_fini (scaled_font, scaled_glyph);
+    
     if (scaled_glyph->surface != NULL)
 	cairo_surface_destroy (&scaled_glyph->surface->base);
 
diff --git a/src/cairoint.h b/src/cairoint.h
index d531caf..ff101c1 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1489,6 +1489,10 @@ _pixman_format_to_masks (pixman_format_code_t	 pixman_format,
 			 cairo_format_masks_t	*masks);
 
 cairo_private void
+_cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
+				cairo_scaled_glyph_t *scaled_glyph);
+
+cairo_private void
 _cairo_image_reset_static_data (void);
 
 cairo_private cairo_surface_t *


More information about the cairo-commit mailing list