[cairo-commit] src/cairo-scaled-font.c

Chris Wilson ickle at kemper.freedesktop.org
Mon Jun 14 07:44:04 PDT 2010


 src/cairo-scaled-font.c |   61 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 45 insertions(+), 16 deletions(-)

New commits:
commit 4a0bd91ff77c8afddde6d09495bc9ca7242f953d
Author: Dmitri Vorobiev <dmitri.vorobiev at movial.com>
Date:   Mon Jun 14 16:40:39 2010 +0300

    scaled-font: fine-tune caching
    
    This patch implements the ideas outlined by Behdad Esfahbod in the following
    mailing list message:
    
    http://lists.cairographics.org/archives/cairo/2010-June/020065.html
    
    Specifically, two things have been adjusted. First, the size of the look-up
    table was reduced to 64. Second, cache codepath is now bypassed for strings
    that are shorter than 16, not only for one-character strings. This allowed
    us to reduce the LUT initialization overhead while still retaining the
    advantage of caching for common-case string sizes.
    
    We have experimented with different LUT sizes, and it came out that the size
    of 64 is the best one in view of speed, at least for our language-neutral
    benchmark, which generated random strings of printable ASCII characters.
    
    Below is a table presenting benchmark results for different values of LUT
    size:
    
    ===============================================================================
     Benchmark		| [1]	| [2]	| [3]	| [4]	| [5]	| [6]	| [7]
    ===============================================================================
    8px text, 1 chars	| 0.41	| 0.41	| 0	| 0.41	| 0	| 0.41	| 0
    8px text, 10 chars	| 2.13	| 2.21	| 3.76	| 2.19	| 2.82	| 2.09	| -1.88
    8px text, 20 chars	| 2.97	| 3.04	| 2.36	| 3.01	| 1.35	| 2.98	| 0.34
    12px text, 1 chars	| 0.94	| 0.94	| 0	| 0.95	| 1.06	| 0.94	| 0
    12px text, 10 chars	| 4.73	| 4.89	| 3.38	| 4.9	| 3.59	| 4.82	| 1.9
    12px text, 20 chars	| 6.32	| 6.42	| 1.58	| 6.46	| 2.22	| 6.32	| 0
    16px text, 1 chars	| 1.75	| 1.76	| 0.57	| 1.77	| 1.14	| 1.76	| 0.57
    16px text, 10 chars	| 8.13	| 8.45	| 3.94	| 8.43	| 3.69	| 8.44	| 3.81
    16px text, 20 chars	| 10.41	| 10.69	| 2.69	| 10.64	| 2.21	| 10.65	| 2.31
    24px text, 1 chars	| 3.3	| 3.3	| 0	| 3.32	| 0.61	| 3.3	| 0
    24px text, 10 chars	| 14.68	| 14.97	| 1.98	| 14.97	| 1.98	| 14.87	| 1.29
    24px text, 20 chars	| 17.93	| 18.01	| 0.45	| 18.06	| 0.73	| 17.81	| -0.67
    96px text, 1 chars	| 23.65	| 23.38	| -1.14	| 23.74	| 0.38	| 23.65	| 0
    96px text, 5 chars	| 50.52	| 51.34	| 1.62	| 51.48	| 1.9	| 51.41	| 1.76
    96px text, 10 chars	| 57.5	| 58.11	| 1.06	| 58.27	| 1.34	| 58.04	| 0.94
    ===============================================================================
    
    [1]: Git head, Mpix/s
    [2]: {GLYPH_LUT_SIZE = 32, CACHING_THRESHOLD = 16}
    [3]: Gain of {32, 16} w.r.t. Git head
    [4]: {GLYPH_LUT_SIZE = 64, CACHING_THRESHOLD = 16}
    [5]: Gain of {64, 16} w.r.t. Git head
    [6]: {GLYPH_LUT_SIZE = 128, CACHING_THRESHOLD = 16}
    [7]: Gain of {128, 16} w.r.t. Git head
    
    The benchmark itself can be found from this mailing list message:
    
    http://lists.cairographics.org/archives/cairo/2010-June/020064.html

diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index d70c555..418f90a 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -1570,9 +1570,9 @@ ZERO_EXTENTS:
 }
 slim_hidden_def (cairo_scaled_font_glyph_extents);
 
-#define GLYPH_LUT_SIZE 256
+#define GLYPH_LUT_SIZE 64
 static cairo_status_t
-cairo_scaled_font_text_to_glyphs_internal_multiple (cairo_scaled_font_t		 *scaled_font,
+cairo_scaled_font_text_to_glyphs_internal_cached (cairo_scaled_font_t		 *scaled_font,
 						    double			  x,
 						    double			  y,
 						    const char			 *utf8,
@@ -1644,7 +1644,7 @@ cairo_scaled_font_text_to_glyphs_internal_multiple (cairo_scaled_font_t		 *scale
 }
 
 static cairo_status_t
-cairo_scaled_font_text_to_glyphs_internal_single (cairo_scaled_font_t	 *scaled_font,
+cairo_scaled_font_text_to_glyphs_internal_uncached (cairo_scaled_font_t	 *scaled_font,
 						  double		  x,
 						  double		  y,
 						  const char		 *utf8,
@@ -1652,19 +1652,47 @@ cairo_scaled_font_text_to_glyphs_internal_single (cairo_scaled_font_t	 *scaled_f
 						  cairo_text_cluster_t	**clusters,
 						  int			  num_chars)
 {
-    uint32_t unicode;
-    int num_bytes;
+    const char *p;
+    int i;
 
-    glyphs[0].x = x;
-    glyphs[0].y = y;
+    p = utf8;
+    for (i = 0; i < num_chars; i++) {
+	unsigned long g;
+	int num_bytes;
+	uint32_t unicode;
+	cairo_scaled_glyph_t *scaled_glyph;
+	cairo_status_t status;
 
-    num_bytes = _cairo_utf8_get_char_validated (utf8, &unicode);
-    glyphs[0].index =
-	scaled_font->backend->ucs4_to_index (scaled_font, unicode);
+	num_bytes = _cairo_utf8_get_char_validated (p, &unicode);
+	p += num_bytes;
 
-    if (clusters) {
-	(*clusters)[0].num_bytes  = num_bytes;
-	(*clusters)[0].num_glyphs = 1;
+	glyphs[i].x = x;
+	glyphs[i].y = y;
+
+	g = scaled_font->backend->ucs4_to_index (scaled_font, unicode);
+
+	/*
+	 * No advance needed for a single character string. So, let's speed up
+	 * one-character strings by skipping glyph lookup.
+	 */
+	if (num_chars > 1) {
+	    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;
+	}
+
+	glyphs[i].index = g;
+
+	if (clusters) {
+	    (*clusters)[i].num_bytes  = num_bytes;
+	    (*clusters)[i].num_glyphs = 1;
+	}
     }
 
     return CAIRO_STATUS_SUCCESS;
@@ -1805,6 +1833,7 @@ cairo_scaled_font_text_to_glyphs_internal_single (cairo_scaled_font_t	 *scaled_f
  *
  * Since: 1.8
  **/
+#define CACHING_THRESHOLD 16
 cairo_status_t
 cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t   *scaled_font,
 				  double		 x,
@@ -1958,15 +1987,15 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t   *scaled_font,
 	*num_clusters = num_chars;
     }
 
-    if (num_chars > 1)
-	status = cairo_scaled_font_text_to_glyphs_internal_multiple (scaled_font,
+    if (num_chars > CACHING_THRESHOLD)
+	status = cairo_scaled_font_text_to_glyphs_internal_cached (scaled_font,
 								     x, y,
 								     utf8,
 								     *glyphs,
 								     clusters,
 								     num_chars);
     else
-	status = cairo_scaled_font_text_to_glyphs_internal_single (scaled_font,
+	status = cairo_scaled_font_text_to_glyphs_internal_uncached (scaled_font,
 								   x, y,
 								   utf8,
 								   *glyphs,


More information about the cairo-commit mailing list