Re: Fixed point cairo.. or no cairo?



Cool. And here's the profile:

http://www.o-hand.com/~jorn/pango-benchmarks/210-softfloat/cairo-floating-point.txt

Thanks,

Jorn

On Sat, 2006-08-19 at 10:03 +0000, Aivars Kalvans wrote:
> 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
> >
> >   
> 
> 
> plain text document attachment (cairo-floating-point.diff)
> 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);
> 
-- 
OpenedHand Ltd.
http://o-hand.com/




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]