summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann Pedersen <ssp@redhat.com>2012-04-30 09:41:44 -0400
committerSøren Sandmann Pedersen <ssp@redhat.com>2012-06-02 09:38:26 -0400
commit4fa907b62bb528b04cb06167776e23373c2810c9 (patch)
treecda79ede6457869b327388c7607f4682fccf3dc1
parent5b512a31871212d72a8cd82ccbb6b6ef91fea182 (diff)
Use the new pixman_glyph_cache_t API that will be in pixman 0.28.0glyphs2
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
-rw-r--r--src/cairo-image-compositor.c361
-rw-r--r--src/cairo-mutex-list-private.h1
-rw-r--r--src/cairo-scaled-font.c2
-rw-r--r--src/cairoint.h4
4 files changed, 120 insertions, 248 deletions
diff --git a/src/cairo-image-compositor.c b/src/cairo-image-compositor.c
index a36a9918..a55dadef 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 4016f8e5..f46afadb 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 59440b2c..2a489789 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 b27f8ad4..41c3e81c 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 *