[cairo] Reduce number of floating point operations
Aivars Kalvans
aivars.kalvans at inbox.lv
Thu Sep 14 15:30:06 PDT 2006
This is basicly the same patch I sent a while ago to
performance-list at gnome.org
It simplifies matrix operations for identity matrices which are very
common. I also wrote a very simple performance test although
improvements will be noticeable on platforms without FPU.
Some profiles
Before: http://www.o-hand.com/~jorn/pango-benchmarks/210-softfloat/cairo.txt
After:
http://www.o-hand.com/~jorn/pango-benchmarks/210-softfloat/cairo-floating-point.txt
--
Aivars
-------------- next part --------------
diff --git a/perf/Makefile.am b/perf/Makefile.am
index d10c3d0..679187d 100644
--- a/perf/Makefile.am
+++ b/perf/Makefile.am
@@ -18,6 +18,7 @@ cairo_perf_SOURCES = \
cairo-perf.c \
cairo-perf.h \
paint.c \
+ text.c \
tessellate.c
if CAIRO_HAS_WIN32_SURFACE
diff --git a/perf/cairo-perf.c b/perf/cairo-perf.c
index 7b927b3..8438298 100644
--- a/perf/cairo-perf.c
+++ b/perf/cairo-perf.c
@@ -201,5 +201,6 @@ cairo_perf_t perfs[] = {
{ "tessellate-16", tessellate_16, 100, 100},
{ "tessellate-64", tessellate_64, 100, 100},
{ "tessellate-256", tessellate_256, 100, 100},
+ { "show_text", show_text, 400, 400},
{ NULL }
};
diff --git a/perf/cairo-perf.h b/perf/cairo-perf.h
index e365263..545f94f 100644
--- a/perf/cairo-perf.h
+++ b/perf/cairo-perf.h
@@ -61,5 +61,6 @@ CAIRO_PERF_DECL (paint_alpha);
CAIRO_PERF_DECL (tessellate_16);
CAIRO_PERF_DECL (tessellate_64);
CAIRO_PERF_DECL (tessellate_256);
+CAIRO_PERF_DECL (show_text);
#endif
diff --git a/perf/text.c b/perf/text.c
new file mode 100644
index 0000000..f8dfedf
--- /dev/null
+++ b/perf/text.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright © 2006 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "cairo-perf.h"
+
+cairo_perf_ticks_t
+show_text (cairo_t *cr, int width, int height)
+{
+ int i;
+ static const char text[] = "This is a pretty long string with some"
+ " accented chars: Jõe ääres";
+
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_set_font_size (cr, 9);
+ cairo_move_to (cr, 10, 10);
+
+ cairo_perf_timer_start ();
+
+ for (i = 0; i < 256; i++) {
+ cairo_show_text (cr, text);
+ }
+
+ cairo_perf_timer_stop ();
+
+ return cairo_perf_timer_elapsed ();
+}
+
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 2f9079b..7129222 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -564,15 +564,10 @@ _cairo_gstate_get_matrix (cairo_gstate_t
cairo_status_t
_cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
{
- cairo_matrix_t tmp;
-
_cairo_gstate_unset_scaled_font (gstate);
- cairo_matrix_init_translate (&tmp, tx, ty);
- cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
-
- cairo_matrix_init_translate (&tmp, -tx, -ty);
- cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
+ cairo_matrix_translate (&gstate->ctm, tx, ty);
+ _cairo_matrix_translate_inverse (&gstate->ctm_inverse, tx, ty);
return CAIRO_STATUS_SUCCESS;
}
@@ -580,18 +575,13 @@ _cairo_gstate_translate (cairo_gstate_t
cairo_status_t
_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
{
- cairo_matrix_t tmp;
-
if (sx == 0 || sy == 0)
return CAIRO_STATUS_INVALID_MATRIX;
_cairo_gstate_unset_scaled_font (gstate);
- cairo_matrix_init_scale (&tmp, sx, sy);
- cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
-
- cairo_matrix_init_scale (&tmp, 1/sx, 1/sy);
- cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
+ cairo_matrix_scale (&gstate->ctm, sx, sy);
+ _cairo_matrix_scale_inverse (&gstate->ctm_inverse, sx, sy);
return CAIRO_STATUS_SUCCESS;
}
@@ -1409,6 +1399,59 @@ _cairo_gstate_glyph_extents (cairo_gstat
return CAIRO_STATUS_SUCCESS;
}
+static void
+_cairo_gstate_transform_glyphs (cairo_gstate_t *gstate,
+ cairo_glyph_t *glyphs,
+ cairo_glyph_t *transformed_glyphs,
+ int num_glyphs)
+{
+ double tx, ty;
+ int i;
+
+ tx = gstate->font_matrix.x0;
+ ty = gstate->font_matrix.y0;
+
+ if (_cairo_matrix_is_identity (&gstate->ctm) &&
+ _cairo_matrix_is_identity (&gstate->target->device_transform))
+ {
+
+ /* Translation is constant for all glyphs, calculate it once */
+ tx += gstate->ctm.x0 + gstate->target->device_transform.x0;
+ ty += gstate->ctm.y0 + gstate->target->device_transform.y0;
+
+ for (i = 0; i < num_glyphs; ++i)
+ {
+ transformed_glyphs[i] = glyphs[i];
+ transformed_glyphs[i].x += tx;
+ transformed_glyphs[i].y += ty;
+ }
+ }
+ else
+ {
+ /* Merge both matrices and calculate final transformation */
+ cairo_matrix_t transformation;
+ cairo_matrix_multiply (&transformation,
+ &gstate->ctm,
+ &gstate->target->device_transform);
+
+ /* Pre-calculate translation, so we can use
+ * ..._transform_distance() instead of ..._transform_point()
+ * and save 2 add-s per iteration */
+ cairo_matrix_transform_point (&transformation, &tx, &ty);
+
+ for (i = 0; i < num_glyphs; ++i)
+ {
+ transformed_glyphs[i] = glyphs[i];
+ cairo_matrix_transform_distance (&transformation,
+ &transformed_glyphs[i].x,
+ &transformed_glyphs[i].y);
+ transformed_glyphs[i].x += tx;
+ transformed_glyphs[i].y += ty;
+ }
+ }
+
+ }
+
cairo_status_t
_cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
cairo_glyph_t *glyphs,
@@ -1417,7 +1460,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;
@@ -1434,15 +1476,10 @@ _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 (gstate,
+ glyphs,
+ transformed_glyphs,
+ num_glyphs);
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
@@ -1466,7 +1503,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);
@@ -1477,15 +1513,10 @@ _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 (gstate,
+ glyphs,
+ transformed_glyphs,
+ num_glyphs);
status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
transformed_glyphs, num_glyphs,
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index 60cdca3..fe33301 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -164,11 +164,15 @@ slim_hidden_def(cairo_matrix_init_transl
void
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty)
{
- cairo_matrix_t tmp;
-
- cairo_matrix_init_translate (&tmp, tx, ty);
+ matrix->x0 += tx * matrix->xx + ty * matrix->xy;
+ matrix->y0 += tx * matrix->yx + ty * matrix->yy;
+}
- cairo_matrix_multiply (matrix, &tmp, matrix);
+void
+_cairo_matrix_translate_inverse (cairo_matrix_t *matrix, double tx, double ty)
+{
+ matrix->x0 -= tx;
+ matrix->y0 -= ty;
}
slim_hidden_def (cairo_matrix_translate);
@@ -205,14 +209,30 @@ slim_hidden_def(cairo_matrix_init_scale)
void
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy)
{
- cairo_matrix_t tmp;
-
- cairo_matrix_init_scale (&tmp, sx, sy);
+ matrix->xx *= sx;
+ matrix->yx *= sx;
- cairo_matrix_multiply (matrix, &tmp, matrix);
+ matrix->xy *= sy;
+ matrix->yy *= sy;
}
slim_hidden_def(cairo_matrix_scale);
+void
+_cairo_matrix_scale_inverse (cairo_matrix_t *matrix, double sx, double sy)
+{
+ sx = 1.0 / sx;
+ sy = 1.0 / sy;
+
+ matrix->xx *= sx;
+ matrix->yx *= sy;
+
+ matrix->xy *= sx;
+ matrix->yy *= sy;
+
+ matrix->x0 *= sx;
+ matrix->y0 *= sy;
+}
+
/**
* cairo_matrix_init_rotate:
* @matrix: a cairo_matrix_t
@@ -530,11 +550,28 @@ _cairo_matrix_compute_scale_factors (con
}
cairo_bool_t
+_cairo_matrix_has_transform (const cairo_matrix_t *matrix)
+{
+ return (matrix->xx != 1.0 || matrix->yx != 0.0 ||
+ matrix->xy != 0.0 || matrix->yy != 1.0 ||
+ matrix->x0 != 0.0 || matrix->y0 != 0.0);
+}
+
+cairo_bool_t
_cairo_matrix_is_identity (const cairo_matrix_t *matrix)
{
+#if defined (__arm__)
+ /* memcmp() should be faster than 4 soft float operations */
+ static const cairo_matrix_t identity = {
+ 1.0, 0.0,
+ 0.0, 1.0,
+ 0.0, 0.0
+ };
+ return (memcmp (matrix, &identity, 4 * sizeof(double)) == 0);
+#else
return (matrix->xx == 1.0 && matrix->yx == 0.0 &&
- matrix->xy == 0.0 && matrix->yy == 1.0 &&
- matrix->x0 == 0.0 && matrix->y0 == 0.0);
+ matrix->xy == 0.0 && matrix->yy == 1.0);
+#endif
}
cairo_bool_t
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index cbbe89a..a80697a 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -863,7 +863,7 @@ slim_hidden_def (cairo_surface_set_fallb
cairo_bool_t
_cairo_surface_has_device_transform (cairo_surface_t *surface)
{
- return ! _cairo_matrix_is_identity (&surface->device_transform);
+ return _cairo_matrix_has_transform (&surface->device_transform);
}
/**
diff --git a/src/cairoint.h b/src/cairoint.h
index bf7d288..6b24bb3 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2143,6 +2143,15 @@ cairo_private void
_cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
pixman_transform_t *pixman_transform);
+cairo_private cairo_bool_t
+_cairo_matrix_has_transform (const cairo_matrix_t *matrix);
+
+cairo_private void
+_cairo_matrix_translate_inverse (cairo_matrix_t *matrix, double tx, double ty);
+
+cairo_private void
+_cairo_matrix_scale_inverse (cairo_matrix_t *matrix, double sx, double sy);
+
/* cairo_traps.c */
cairo_private void
_cairo_traps_init (cairo_traps_t *traps);
More information about the cairo
mailing list