[cairo] Speeding up transforming glyphs in cairo-gstate

Daniel Amelang daniel.amelang at gmail.com
Tue Nov 21 11:32:35 PST 2006


After the rounding code dropped from the profile (see previous post),
the next to show up was all the transforming of glyphs that goes on in
_cairo_gstate_show_glyphs. So, I pulled out the part of Aivars patch
that addressed this and rewrote it to address Carl's suggestions. I'm
hoping that this version is more readable, and I've also confirmed
that it's faster. This is because Aivars wasn't checking the very
common case that both the ctm and device_transform are identity.

Again, about 1.5x speedup on my softfloat text test cases, but someone
with a Nokia 770 needs to post the real deal.

Dan
-------------- next part --------------
From nobody Mon Sep 17 00:00:00 2001
From: Dan Amelang <dan at amelang.net>
Date: Mon Nov 20 10:42:50 2006 -0800
Subject: [PATCH] Add _cairo_matrix_is_translation

---

 src/cairo-matrix.c |    7 +++++++
 src/cairoint.h     |    3 +++
 2 files changed, 10 insertions(+), 0 deletions(-)

37f60842ccffb08c61bab0342f27458d2b2e9b8f
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index e2f353b..ee30058 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -549,6 +549,13 @@ _cairo_matrix_is_identity (const cairo_m
 }
 
 cairo_bool_t
+_cairo_matrix_is_translation (const cairo_matrix_t *matrix)
+{
+    return (matrix->xx == 1.0 && matrix->yx == 0.0 &&
+	    matrix->xy == 0.0 && matrix->yy == 1.0);
+}
+
+cairo_bool_t
 _cairo_matrix_is_integer_translation(const cairo_matrix_t *m,
 				     int *itx, int *ity)
 {
diff --git a/src/cairoint.h b/src/cairoint.h
index 1f86fba..7af988a 100755
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2195,6 +2195,9 @@ cairo_private cairo_bool_t
 _cairo_matrix_is_identity (const cairo_matrix_t *matrix);
 
 cairo_private cairo_bool_t
+_cairo_matrix_is_translation (const cairo_matrix_t *matrix);
+
+cairo_private cairo_bool_t
 _cairo_matrix_is_integer_translation(const cairo_matrix_t *matrix,
 				     int *itx, int *ity);
 
-- 
1.2.6
-------------- next part --------------
From nobody Mon Sep 17 00:00:00 2001
From: Dan Amelang <dan at amelang.net>
Date: Mon Nov 20 14:08:46 2006 -0800
Subject: [PATCH] Refactor _cairo_matrix_is_integer_translation

Now that we have _cairo_matrix_is_translation, we can change
_cairo_matrix_is_integer_translation to use it and thus reduce code
duplication.

---

 src/cairo-matrix.c |   42 +++++++++++++++++++-----------------------
 1 files changed, 19 insertions(+), 23 deletions(-)

625300ceacad713313608a1ce7fa480a4fdab1ca
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index ee30058..ed5da92 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -556,31 +556,27 @@ _cairo_matrix_is_translation (const cair
 }
 
 cairo_bool_t
-_cairo_matrix_is_integer_translation(const cairo_matrix_t *m,
-				     int *itx, int *ity)
+_cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix,
+				      int *itx, int *ity)
 {
-    cairo_bool_t is_integer_translation;
-    cairo_fixed_t x0_fixed, y0_fixed;
+    if (_cairo_matrix_is_translation (matrix))
+    {
+        cairo_fixed_t x0_fixed = _cairo_fixed_from_double (matrix->x0);
+        cairo_fixed_t y0_fixed = _cairo_fixed_from_double (matrix->y0);
+
+        if (_cairo_fixed_is_integer (x0_fixed) &&
+            _cairo_fixed_is_integer (y0_fixed))
+        {
+            if (itx)
+                *itx = _cairo_fixed_integer_part (x0_fixed);
+            if (ity)
+                *ity = _cairo_fixed_integer_part (y0_fixed);
+
+            return TRUE;
+        }
+    }
 
-    x0_fixed = _cairo_fixed_from_double (m->x0);
-    y0_fixed = _cairo_fixed_from_double (m->y0);
-
-    is_integer_translation = ((m->xx == 1.0) &&
-			      (m->yx == 0.0) &&
-			      (m->xy == 0.0) &&
-			      (m->yy == 1.0) &&
-			      (_cairo_fixed_is_integer(x0_fixed)) &&
-			      (_cairo_fixed_is_integer(y0_fixed)));
-
-    if (! is_integer_translation)
-	return FALSE;
-
-    if (itx)
-	*itx = _cairo_fixed_integer_part(x0_fixed);
-    if (ity)
-	*ity = _cairo_fixed_integer_part(y0_fixed);
-
-    return TRUE;
+    return FALSE;
 }
 
 /*
-- 
1.2.6
-------------- next part --------------
From nobody Mon Sep 17 00:00:00 2001
From: Dan Amelang <dan at amelang.net>
Date: Mon Nov 20 14:31:28 2006 -0800
Subject: [PATCH] Add and incorporate _cairo_gstate_transform_glyphs_to_backend

After changing _cairo_gstate_show_glyphs and _cairo_gstate_glyph_path to use
this function, we see a significant speedup due to the elimination of redundant
FP calculations.

---

 src/cairo-gstate.c |   92 +++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 72 insertions(+), 20 deletions(-)

c795c41c946810e11c7d8505c81609e055cea928
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 8568186..d04c332 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -61,6 +61,12 @@ _cairo_gstate_ensure_scaled_font (cairo_
 static void
 _cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate);
 
+static void
+_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t      *gstate,
+                                           const cairo_glyph_t *glyphs,
+                                           int                  num_glyphs,
+                                           cairo_glyph_t *transformed_glyphs);
+
 /**
  * _cairo_gstate_create:
  * @target: a #cairo_surface_t, not NULL
@@ -1466,7 +1472,6 @@ _cairo_gstate_show_glyphs (cairo_gstate_
     cairo_status_t status;
     cairo_pattern_union_t source_pattern;
     cairo_glyph_t *transformed_glyphs;
-    int i;
 
     if (gstate->source->status)
 	return gstate->source->status;
@@ -1483,15 +1488,8 @@ _cairo_gstate_show_glyphs (cairo_gstate_
     if (transformed_glyphs == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
-    for (i = 0; i < num_glyphs; ++i)
-    {
-	transformed_glyphs[i].index = glyphs[i].index;
-	transformed_glyphs[i].x = glyphs[i].x + gstate->font_matrix.x0;
-	transformed_glyphs[i].y = glyphs[i].y + gstate->font_matrix.y0;
-	_cairo_gstate_user_to_backend (gstate,
-				       &transformed_glyphs[i].x,
-				       &transformed_glyphs[i].y);
-    }
+    _cairo_gstate_transform_glyphs_to_backend (gstate, glyphs, num_glyphs,
+                                               transformed_glyphs);
 
     _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
 
@@ -1515,7 +1513,6 @@ _cairo_gstate_glyph_path (cairo_gstate_t
 			  cairo_path_fixed_t *path)
 {
     cairo_status_t status;
-    int i;
     cairo_glyph_t *transformed_glyphs = NULL;
 
     status = _cairo_gstate_ensure_scaled_font (gstate);
@@ -1526,15 +1523,8 @@ _cairo_gstate_glyph_path (cairo_gstate_t
     if (transformed_glyphs == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
-    for (i = 0; i < num_glyphs; ++i)
-    {
-	transformed_glyphs[i].index = glyphs[i].index;
-	transformed_glyphs[i].x = glyphs[i].x + gstate->font_matrix.x0;
-	transformed_glyphs[i].y = glyphs[i].y + gstate->font_matrix.y0;
-	_cairo_gstate_user_to_backend (gstate,
-				       &(transformed_glyphs[i].x),
-				       &(transformed_glyphs[i].y));
-    }
+    _cairo_gstate_transform_glyphs_to_backend (gstate, glyphs, num_glyphs,
+                                               transformed_glyphs);
 
     status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
 					    transformed_glyphs, num_glyphs,
@@ -1558,3 +1548,65 @@ _cairo_gstate_get_antialias (cairo_gstat
 {
     return gstate->antialias;
 }
+
+/**
+ * _cairo_gstate_transform_glyphs_to_backend:
+ * @gstate: a #cairo_gstate_t
+ * @glyphs: the array of #cairo_glyph_t objects to be transformed
+ * @num_glyphs: the number of elements in @glyphs
+ * @transformed_glyphs: a pre-allocated array of at least @num_glyphs
+ * #cairo_glyph_t objects
+ *
+ * Transform an array of glyphs to backend space by first adding the offset
+ * of the font matrix, then transforming from user space to backend space.
+ * The result of the transformation is placed in @transformed_glyphs.
+ **/
+static void
+_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t      *gstate,
+                                           const cairo_glyph_t *glyphs,
+                                           int                  num_glyphs,
+                                           cairo_glyph_t *transformed_glyphs)
+{
+    int i;
+    cairo_matrix_t *ctm = &gstate->ctm;
+    cairo_matrix_t *device_transform = &gstate->target->device_transform;
+
+    if (_cairo_matrix_is_identity (ctm) &&
+        _cairo_matrix_is_identity (device_transform))
+    {
+        memcpy (transformed_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
+    }
+    else if (_cairo_matrix_is_translation (ctm) &&
+             _cairo_matrix_is_translation (device_transform))
+    {
+        double tx = gstate->font_matrix.x0 + ctm->x0 + device_transform->x0;
+        double ty = gstate->font_matrix.y0 + ctm->y0 + device_transform->y0;
+
+        for (i = 0; i < num_glyphs; i++)
+        {
+            transformed_glyphs[i].index = glyphs[i].index;
+            transformed_glyphs[i].x = glyphs[i].x + tx;
+            transformed_glyphs[i].y = glyphs[i].y + ty;
+        }
+    }
+    else
+    {
+        cairo_matrix_t aggregate_transform;
+
+        cairo_matrix_init_translate (&aggregate_transform,
+                                     gstate->font_matrix.x0,
+                                     gstate->font_matrix.y0);
+        cairo_matrix_multiply (&aggregate_transform,
+                               &aggregate_transform, ctm);
+        cairo_matrix_multiply (&aggregate_transform,
+                               &aggregate_transform, device_transform);
+
+        for (i = 0; i < num_glyphs; i++)
+        {
+            transformed_glyphs[i] = glyphs[i];
+            cairo_matrix_transform_point (&aggregate_transform,
+                                          &transformed_glyphs[i].x,
+                                          &transformed_glyphs[i].y);
+        }
+    }
+}
-- 
1.2.6


More information about the cairo mailing list