Re: Fixed point cairo.. or no cairo?
- From: Aivars Kalvans <aivars kalvans inbox lv>
- To: Jorn Baayen <jorn openedhand com>
- Cc: performance-list gnome org
- Subject: Re: Fixed point cairo.. or no cairo?
- Date: Sat, 19 Aug 2006 10:03:08 +0000
I've made few more changes, to cover real-life situations when matrices
are identity matrices with some translation:
cairo_matrix_translate(), _cairo_matrix_translate_inverse(): just
translate x0 and y0 and do not multiply whole matrix with identity matrix
_cairo_color_init_rgb(): do not multiply with alpha
_cairo_color_init_rgba(): did the same thing a compiler should do with
-Ox flag turned on (just in case optimization is disabled)
_cairo_gstate_glyph_path(), _cairo_gstate_show_glyphs(): since
translation is constant for all glyphs, precalculate it - that saves 2
or 4 adds per iteration. For other cases (not identity matrices)
precalculate matrix with final transformation: saves one matrix
multiplication (4 muls and 2 adds) per iteration. I hope my math is
correct here.
Jorn Baayen wrote:
> On Wed, 2006-08-16 at 00:19 +0000, Aivars Kalvans wrote:
>
>> Jorn Baayen wrote:
>>
>>> On Fri, 2006-08-11 at 09:42 +0100, Michael Meeks wrote:
>>>
>>>
>>>> Is the common case of that a multiplication by a unit matrix, [ ie. a
>>>> no-op ;-] that could be elided if that's detectable / propagate-able ?
>>>> [ though it seems there is no space in 'matrix' to ram an 'unsigned int
>>>> is-unit : 1' into ;-) Or is it perhaps a simple scaling [ reduce by 2x
>>>> the muls ? ].
>>>>
>>>>
>>> I'm not so sure. Carl?
>>>
>>>
>> Matrix with values like { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 } does not
>> require any multiplication, because result is the same as input. Both
>> gstate->ctm and gstate->target->device_transform had such values when I
>> run your test program. This often seems to be true for "real"
>> applications as well (tried gedit). Sometimes x0 and y0 are not 0.0, but
>> for such cases we could add another workaround (x += x0, y+= y0).
>>
>
> Yea, I was not sure whether this was a common case. Apparently it is,
> because your patch causes __muldf3() to drop from 7.7% to 3.9% :)
> The full patched cairo profile is here:
> http://www.o-hand.com/~jorn/pango-benchmarks/210-softfloat/cairo-must-transform.txt
>
> Cool stuff.
>
> Thanks,
>
> Jorn
>
>
--
Aivars
diff --git a/src/cairo-color.c b/src/cairo-color.c
index e202af2..ff56fc2 100644
--- a/src/cairo-color.c
+++ b/src/cairo-color.c
@@ -82,26 +82,35 @@ _cairo_color_init (cairo_color_t *color)
*color = cairo_color_white;
}
-void
-_cairo_color_init_rgb (cairo_color_t *color,
- double red, double green, double blue)
-{
- _cairo_color_init_rgba (color, red, green, blue, 1.0);
-}
-
/* We multiply colors by (0x10000 - epsilon), such that we get a uniform
* range even for 0xffff. In other words, (1.0 - epsilon) would convert
* to 0xffff, not 0xfffe.
*/
#define CAIRO_COLOR_ONE_MINUS_EPSILON (65536.0 - 1e-5)
+void
+_cairo_color_init_rgb (cairo_color_t *color,
+ double red, double green, double blue)
+{
+ color->red = red;
+ color->green = green;
+ color->blue = blue;
+ color->alpha = 1.0;
+
+ color->red_short = color->red * CAIRO_COLOR_ONE_MINUS_EPSILON;
+ color->green_short = color->green * CAIRO_COLOR_ONE_MINUS_EPSILON;
+ color->blue_short = color->blue * CAIRO_COLOR_ONE_MINUS_EPSILON;
+ color->alpha_short = 0xffff;
+}
+
static void
_cairo_color_compute_shorts (cairo_color_t *color)
{
- color->red_short = color->red * color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON;
- color->green_short = color->green * color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON;
- color->blue_short = color->blue * color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON;
- color->alpha_short = color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON;
+ double alpha = color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON;
+ color->red_short = color->red * alpha;
+ color->green_short = color->green * alpha;
+ color->blue_short = color->blue * alpha;
+ color->alpha_short = alpha;
}
void
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 2f9079b..4ed2cf3 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -564,15 +564,11 @@ _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_translate (&gstate->ctm, tx, ty);
- cairo_matrix_init_translate (&tmp, -tx, -ty);
- cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
+ _cairo_matrix_translate_inverse (&gstate->ctm_inverse, -tx, -ty);
return CAIRO_STATUS_SUCCESS;
}
@@ -1417,6 +1413,9 @@ _cairo_gstate_show_glyphs (cairo_gstate_
cairo_status_t status;
cairo_pattern_union_t source_pattern;
cairo_glyph_t *transformed_glyphs;
+ cairo_matrix_t transformation;
+ cairo_bool_t ctm_is_identity, device_is_identity;
+ double tx, ty;
int i;
if (gstate->source->status)
@@ -1434,14 +1433,40 @@ _cairo_gstate_show_glyphs (cairo_gstate_
if (transformed_glyphs == NULL)
return CAIRO_STATUS_NO_MEMORY;
- for (i = 0; i < num_glyphs; ++i)
+ ctm_is_identity = _cairo_matrix_is_identity (&gstate->ctm);
+ device_is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform);
+
+ tx = gstate->font_matrix.x0;
+ ty = gstate->font_matrix.y0;
+
+ if (ctm_is_identity && device_is_identity)
+ {
+ 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
{
- 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_matrix_multiply (&transformation,
+ &gstate->ctm,
+ &gstate->target->device_transform);
+
+ 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_gstate_copy_transformed_source (gstate, &source_pattern.base);
@@ -1468,6 +1493,9 @@ _cairo_gstate_glyph_path (cairo_gstate_t
cairo_status_t status;
int i;
cairo_glyph_t *transformed_glyphs = NULL;
+ cairo_matrix_t transformation;
+ cairo_bool_t ctm_is_identity, device_is_identity;
+ double tx, ty;
status = _cairo_gstate_ensure_scaled_font (gstate);
if (status)
@@ -1477,14 +1505,40 @@ _cairo_gstate_glyph_path (cairo_gstate_t
if (transformed_glyphs == NULL)
return CAIRO_STATUS_NO_MEMORY;
- for (i = 0; i < num_glyphs; ++i)
+ ctm_is_identity = _cairo_matrix_is_identity (&gstate->ctm);
+ device_is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform);
+
+ tx = gstate->font_matrix.x0;
+ ty = gstate->font_matrix.y0;
+
+ if (ctm_is_identity && device_is_identity)
+ {
+ 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
{
- 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_matrix_multiply (&transformation,
+ &gstate->ctm,
+ &gstate->target->device_transform);
+
+ 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;
+ }
}
status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index e418ef3..7723209 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;
}
/**
@@ -529,11 +533,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 for soft float */
+ static 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 0468ca2..40e31a7 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -853,7 +853,7 @@ cairo_surface_set_fallback_resolution (c
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 13d19b1..81963a0 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2141,6 +2141,12 @@ 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_traps.c */
cairo_private void
_cairo_traps_init (cairo_traps_t *traps);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]