[cairo] [PATCH] scaled-font: optimize cairo_scaled_font_text_to_glyphs()
Dmitri Vorobiev
dmitri.vorobiev at movial.com
Wed Jun 9 09:20:27 PDT 2010
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
---
src/cairo-scaled-font.c | 171 ++++++++++++++++++++++++++++++++---------------
1 files changed, 117 insertions(+), 54 deletions(-)
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index f928c08..ab3e2d1 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -1570,6 +1570,105 @@ ZERO_EXTENTS:
}
slim_hidden_def (cairo_scaled_font_glyph_extents);
+#define GLYPH_LUT_SIZE 256
+static void
+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,
+ cairo_status_t *status
+ )
+{
+
+ int i;
+ const char *p;
+ 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];
+
+ for (i = 0; i < ARRAY_LENGTH (glyph_lut_unicode); 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 {
+ (*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))
+ return;
+
+ x += scaled_glyph->metrics.x_advance;
+ y += scaled_glyph->metrics.y_advance;
+
+ glyph_lut_unicode[idx] = 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;
+ }
+ }
+}
+
+static void
+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,
+ cairo_status_t *status
+ )
+{
+ 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;
+ }
+}
+
/**
* cairo_scaled_font_text_to_glyphs:
* @x: X position to place first glyph
@@ -1717,18 +1816,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 +1957,24 @@ 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)
+ cairo_scaled_font_text_to_glyphs_internal_multiple (scaled_font,
+ x,
+ y,
+ utf8,
+ glyphs,
+ clusters,
+ num_chars,
+ &status);
+ else
+ cairo_scaled_font_text_to_glyphs_internal_single (scaled_font,
+ x,
+ y,
+ utf8,
+ glyphs,
+ clusters,
+ num_chars,
+ &status);
DONE: /* error that should be logged on scaled_font happened */
_cairo_scaled_font_thaw_cache (scaled_font);
--
1.6.3.3
More information about the cairo
mailing list