[cairo] Reduce number of floating point operations

Aivars Kalvans aivars.kalvans at inbox.lv
Mon Sep 25 13:55:36 PDT 2006


Hi!

At first I should explain that I added some printf's to print ctm and
device_transform matrices. Often matrix had non-zero x0 and y0 while
xx=1, yx=0, xy=0 and yy=1. So I used it as a common case, not
{1,0,0,1,0,0}. That should explain why I check only first 4 doubles in
cairo_matrix_is_identity.

Carl Worth wrote:
>> +    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;
>>     
>
> I'm confused here. These identity matrices have translation components
> of (0,0) by definition. So why are we adding them in here?
>   
I hope I answered it above.
>> +	cairo_matrix_t transformation;
>> +	cairo_matrix_multiply (&transformation,
>> +			       &gstate->ctm,
>> +			       &gstate->target->device_transform);
>>     
>
> Again, as far as making the code more self-documenting, a much better
> name than transformation here would be user_to_backend. And would we
> want to similar merging of ctm and device_transform in more general
> ways?
>
>   
No, unless it's used in loop. Merging two matrices and then doing one
transformation most likely has more floating point operations than 2
transformations.
>>  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;
>>  }
>>     
>
> OK. I've got a big problem with the above two functions, (and the same
> problem with cairo_matrix_scale and _cairo_matrix_scale_inverse). The
> problem is that each pair of functions is too-similarly named for
> having such different operations, (different not only in inverting the
> translation/scale values but also in reversing the effective order of
> the two matrices being implicitly multiplied here.
>
> So, it's really hard to look at the two implementations above and not
> be convinced that there are bugs in that one uses xx, xy, yx, and yy
> while the other one does not.
>   

I can't be 100% sure that it's correct, but I did the math at least twice.

cairo_matrix_t tmp;
cairo_matrix_init_translate (&tmp, tx, ty);

tmp = {
1, 0,
0, 1,
tx, ty}

cairo_matrix_multiply (matrix, &tmp, matrix);

r.xx = tmp->xx * matrix->xx + tmp->yx * matrix->xy;
r.yx = tmp->xx * matrix->yx + tmp->yx * matrix->yy;
r.xy = tmp->xy * matrix->xx + tmp->yy * matrix->xy;
r.yy = tmp->xy * matrix->yx + tmp->yy * matrix->yy;
r.x0 = tmp->x0 * matrix->xx + tmp->y0 * matrix->xy + matrix->x0;
r.y0 = tmp->x0 * matrix->yx + tmp->y0 * matrix->yy + matrix->y0;
---------------------
r.xx = 1 * matrix->xx + 0 * matrix->xy;
r.yx = 1 * matrix->yx + 0 * matrix->yy;
r.xy = 0 * matrix->xx + 1 * matrix->xy;
r.yy = 0 * matrix->yx + 1 * matrix->yy;
r.x0 = tx * matrix->xx + ty * matrix->xy + matrix->x0;
r.y0 = tx * matrix->yx + ty * matrix->yy + matrix->y0;
---------------------
r.xx = matrix->xx
r.yx = matrix->yx
r.xy = matrix->xy;
r.yy = matrix->yy;
r.x0 = tx * matrix->xx + ty * matrix->xy + matrix->x0;
r.y0 = tx * matrix->yx + ty * matrix->yy + matrix->y0;
------------------
matrix->x0 += tx * matrix->xx + ty * matrix->xy;
matrix->y0 += tx * matrix->yx + ty * matrix->yy;

... and so on for other operations.

Unfortunately, I'm very busy at work lately, so I don't have time to
work on this patch and won't have it in near future. It would be nice if
someone could continue to work on this patch.

-- 
Aivars



More information about the cairo mailing list