From 5cb764850f7c405085739647bac2809045e7cdf3 Mon Sep 17 00:00:00 2001 From: Dmitri Vorobiev Date: Wed, 9 Jun 2010 19:20:27 +0300 Subject: scaled-font: optimize cairo_scaled_font_text_to_glyphs() This patch serves two purposes. First, it factors out the heavy part of the cairo_scaled_font_text_to_glyphs() routine thus allowing GCC to better optimize the cache cleanup loop. Keeping the look-up table indices in a separate array speeds up array initialization even further. Second, this patch introduces a shortcut for the case when the string to be rendered consists of a single character. In this case, caching is not necessary at all. We have a benchmark that uses Cairo to render a large amount of random strings of consisting of printable ASCII characters. Below are Oprofile results collected while running this benchmark. It is easy to see that the heavy part becomes noticeably lighter. Before: Profiling through timer interrupt samples % app name symbol name 198755 13.5580 libcairo.so.2.10907.0 cairo_scaled_font_text_to_glyphs 88580 6.0424 libcairo.so.2.10907.0 _cairo_scaled_glyph_lookup 81127 5.5340 libcairo.so.2.10907.0 _cairo_hash_table_lookup 68186 4.6513 libcairo.so.2.10907.0 cairo_scaled_font_glyph_extents 47145 3.2160 libcairo.so.2.10907.0 _composite_glyphs_via_mask 46327 3.1602 libcairo.so.2.10907.0 _cairo_scaled_font_glyph_device_extents 44817 3.0572 libcairo.so.2.10907.0 _composite_glyphs 40431 2.7580 libcairo.so.2.10907.0 .plt After (note that cairo_scaled_font_text_to_glyphs_internal_single() was inlined): Profiling through timer interrupt samples % app name symbol name 107264 7.6406 libcairo.so.2.10907.0 cairo_scaled_font_text_to_glyphs_internal_multiple 87888 6.2604 libcairo.so.2.10907.0 _cairo_scaled_glyph_lookup 79011 5.6281 libcairo.so.2.10907.0 _cairo_hash_table_lookup 71723 5.1090 libcairo.so.2.10907.0 cairo_scaled_font_glyph_extents 48084 3.4251 libcairo.so.2.10907.0 _composite_glyphs_via_mask 46636 3.3220 libcairo.so.2.10907.0 _cairo_scaled_font_glyph_device_extents 44740 3.1869 libcairo.so.2.10907.0 _composite_glyphs 42472 3.0254 libc-2.8.so _int_malloc 39194 2.7919 libcairo.so.2.10907.0 _cairo_gstate_transform_glyphs_to_backend 38614 2.7506 libcairo.so.2.10907.0 .plt 37063 2.6401 libcairo.so.2.10907.0 _cairo_ft_ucs4_to_index 36856 2.6253 libc-2.8.so random 36376 2.5911 libcairo.so.2.10907.0 _cairo_scaled_glyphs_equal 34545 2.4607 libcairo.so.2.10907.0 cairo_matrix_transform_point 31690 2.2573 libc-2.8.so malloc 29395 2.0939 libcairo.so.2.10907.0 _cairo_matrix_is_identity 26142 1.8621 libcairo.so.2.10907.0 _cairo_utf8_to_ucs4 24406 1.7385 libc-2.8.so free 24059 1.7138 libcairo.so.2.10907.0 cairo_scaled_font_text_to_glyphs [ickle: slightly amended for stylistic consistency.] --- src/cairo-scaled-font.c | 168 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 114 insertions(+), 54 deletions(-) diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index f928c08d..d70c5555 100644 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -1570,6 +1570,106 @@ ZERO_EXTENTS: } slim_hidden_def (cairo_scaled_font_glyph_extents); +#define GLYPH_LUT_SIZE 256 +static cairo_status_t +cairo_scaled_font_text_to_glyphs_internal_multiple (cairo_scaled_font_t *scaled_font, + double x, + double y, + const char *utf8, + cairo_glyph_t *glyphs, + cairo_text_cluster_t **clusters, + int num_chars) +{ + struct glyph_lut_elt { + unsigned long index; + double x_advance; + double y_advance; + } glyph_lut[GLYPH_LUT_SIZE]; + uint32_t glyph_lut_unicode[GLYPH_LUT_SIZE]; + cairo_status_t status; + const char *p; + int i; + + for (i = 0; i < GLYPH_LUT_SIZE; i++) + glyph_lut_unicode[i] = ~0U; + + p = utf8; + for (i = 0; i < num_chars; i++) { + int idx, num_bytes; + uint32_t unicode; + cairo_scaled_glyph_t *scaled_glyph; + struct glyph_lut_elt *glyph_slot; + + num_bytes = _cairo_utf8_get_char_validated (p, &unicode); + p += num_bytes; + + glyphs[i].x = x; + glyphs[i].y = y; + + idx = unicode % ARRAY_LENGTH (glyph_lut); + glyph_slot = &glyph_lut[idx]; + if (glyph_lut_unicode[idx] == unicode) { + glyphs[i].index = glyph_slot->index; + x += glyph_slot->x_advance; + y += glyph_slot->y_advance; + } else { + unsigned long g; + + g = scaled_font->backend->ucs4_to_index (scaled_font, unicode); + status = _cairo_scaled_glyph_lookup (scaled_font, + g, + CAIRO_SCALED_GLYPH_INFO_METRICS, + &scaled_glyph); + if (unlikely (status)) + return status; + + x += scaled_glyph->metrics.x_advance; + y += scaled_glyph->metrics.y_advance; + + glyph_lut_unicode[idx] = unicode; + glyph_slot->index = g; + glyph_slot->x_advance = scaled_glyph->metrics.x_advance; + glyph_slot->y_advance = scaled_glyph->metrics.y_advance; + + glyphs[i].index = g; + } + + if (clusters) { + (*clusters)[i].num_bytes = num_bytes; + (*clusters)[i].num_glyphs = 1; + } + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_scaled_font_text_to_glyphs_internal_single (cairo_scaled_font_t *scaled_font, + double x, + double y, + const char *utf8, + cairo_glyph_t *glyphs, + cairo_text_cluster_t **clusters, + int num_chars) +{ + uint32_t unicode; + int num_bytes; + + glyphs[0].x = x; + glyphs[0].y = y; + + num_bytes = _cairo_utf8_get_char_validated (utf8, &unicode); + glyphs[0].index = + scaled_font->backend->ucs4_to_index (scaled_font, unicode); + + if (clusters) { + (*clusters)[0].num_bytes = num_bytes; + (*clusters)[0].num_glyphs = 1; + } + + return CAIRO_STATUS_SUCCESS; +} + /** * cairo_scaled_font_text_to_glyphs: * @x: X position to place first glyph @@ -1717,18 +1817,10 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, int *num_clusters, cairo_text_cluster_flags_t *cluster_flags) { - int i; int num_chars = 0; - const char *p; cairo_status_t status; cairo_glyph_t *orig_glyphs; cairo_text_cluster_t *orig_clusters; - struct glyph_lut_elt { - uint32_t unicode; - unsigned long index; - double x_advance; - double y_advance; - } glyph_lut[256]; status = scaled_font->status; if (unlikely (status)) @@ -1866,52 +1958,20 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, *num_clusters = num_chars; } - for (i = 0; i < ARRAY_LENGTH (glyph_lut); i++) - glyph_lut[i].unicode = ~0U; - - p = utf8; - for (i = 0; i < num_chars; i++) { - int num_bytes; - uint32_t unicode; - cairo_scaled_glyph_t *scaled_glyph; - struct glyph_lut_elt *glyph_slot; - - num_bytes = _cairo_utf8_get_char_validated (p, &unicode); - p += num_bytes; - - (*glyphs)[i].x = x; - (*glyphs)[i].y = y; - - glyph_slot = &glyph_lut[unicode % ARRAY_LENGTH (glyph_lut)]; - if (glyph_slot->unicode == unicode) { - (*glyphs)[i].index = glyph_slot->index; - x += glyph_slot->x_advance; - y += glyph_slot->y_advance; - } else { - (*glyphs)[i].index = - (*scaled_font->backend->ucs4_to_index) (scaled_font, unicode); - - status = _cairo_scaled_glyph_lookup (scaled_font, - (*glyphs)[i].index, - CAIRO_SCALED_GLYPH_INFO_METRICS, - &scaled_glyph); - if (unlikely (status)) - goto DONE; - - x += scaled_glyph->metrics.x_advance; - y += scaled_glyph->metrics.y_advance; - - glyph_slot->unicode = unicode; - glyph_slot->index = (*glyphs)[i].index; - glyph_slot->x_advance = scaled_glyph->metrics.x_advance; - glyph_slot->y_advance = scaled_glyph->metrics.y_advance; - } - - if (clusters) { - (*clusters)[i].num_bytes = num_bytes; - (*clusters)[i].num_glyphs = 1; - } - } + if (num_chars > 1) + status = cairo_scaled_font_text_to_glyphs_internal_multiple (scaled_font, + x, y, + utf8, + *glyphs, + clusters, + num_chars); + else + status = cairo_scaled_font_text_to_glyphs_internal_single (scaled_font, + x, y, + utf8, + *glyphs, + clusters, + num_chars); DONE: /* error that should be logged on scaled_font happened */ _cairo_scaled_font_thaw_cache (scaled_font); -- cgit v1.2.3