[cairo] OVER / SOURCE optimization for cairo_paint

Behdad Esfahbod behdad at behdad.org
Sun Feb 17 02:51:26 PST 2008


Hi Antoine,

Good stuff.  Comments below.

On Sat, 2008-02-16 at 18:57 -0500, Antoine Azar wrote:

> >Here, you're introducing a very long 'if' block for the 
> >optimization. I think this would be much readable as a separate 
> >function. Maybe something 
> >like  cairo_gstate_paint_opaque_with_source or so. Fortunately, the 
> >current function is accepting only a single parameter, so it's not 
> >painful to pass a lot of arguments down to a
> >new function, (nested functions would be really nice---and support 
> >for them in gcc is rather tempting).
> 
> I don't know the code well enough yet, but it seems many 
> optimizations have been implemented here and there at various levels. 
> If it's possible at all, it would be good to move these optimizations 
> as early in the code path as possible, and engineer our functions 
> based on that. That was kind of the idea I mentionned to have a layer 
> between the user and the gstate functions to convert between "what 
> the user asked for" and "what we really want to do internally". Or is 
> that already the role of the functions in cairo.c or in gstate?

cairo.c should really be a wrapper around gstate.  And gstate should
really be a wrapper around surface and scaled-font.  This particular
optimization for example is more suitable to go in the surface layer,
for example because we use cairo_surface_paint() internally when we
don't have and don't need any gstate.

That said, there's this comment in cairo-surface.c that seems wrong:

    /* These operators aren't interpreted the same way by the backends;
     * they are implemented in terms of other operators in cairo-gstate.c
     */
    assert (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_CLEAR);

as gstate doesn't do anything specific about those operators.  That
happens in other places, not gstate.


> Looking forward to your feedback!
> Thanks,
> Antoine
> 
> diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
> index 0b775ca..9c764ec 100644
> --- a/src/cairo-gstate.c
> +++ b/src/cairo-gstate.c
> @@ -879,6 +879,16 @@ _cairo_gstate_paint (cairo_gstate_t *gstate)
>   {
>       cairo_status_t status;
>       cairo_pattern_union_t pattern;
> +    cairo_operator_t op = gstate->op;
> +
> +    //optimization related declarations
> +    cairo_rectangle_int_t extents;
> +    const cairo_pattern_union_t *pattern_union;
> +    cairo_fixed_t x_fixed, y_fixed;
> +    cairo_fixed_t dx_fixed, dy_fixed;
> +    cairo_rectangle_t surface_rect;
> +    cairo_path_fixed_t *path;
> +    cairo_matrix_t matrix_invert;

Most of these can be moved into the inner blocks they are used.  Inside the if for example.

> +                    surface_rect.x = floor(surface_rect.x);
> +                    surface_rect.y = floor(surface_rect.y);
> +                    surface_rect.width = ceil(surface_rect.width);
> +                    surface_rect.height = ceil(surface_rect.height);

Why is the floor/ceil needed here in the first place?

> +                    if (surface_rect.width <= 0 || surface_rect.height <= 0)
> +                       return CAIRO_STATUS_SUCCESS;
> +
> +                    cairo_matrix_transform_point 
> (&gstate->target->device_transform, &surface_rect.x, &surface_rect.y);
> +                    cairo_matrix_transform_point 
> (&gstate->target->device_transform, &surface_rect.width, &surface_rect.height);
> +
> +                    //FIXME: why doesn't user_to_backend implement 
> the floor and ceil as done above (and why do we need them in the 
> first place anyways?)?
...
> +                    status = _cairo_path_fixed_move_to (path, 
> x_fixed, y_fixed);
> +                    status |= _cairo_path_fixed_rel_line_to (path, 
> dx_fixed, 0);
> +                    status |= _cairo_path_fixed_rel_line_to (path, 
> 0, dy_fixed);
> +                    status |= _cairo_path_fixed_rel_line_to (path, 
> -dx_fixed, 0);
> +                    status |= _cairo_path_fixed_rel_line_to (path, 
> 0, -dy_fixed);
> +                    status |= _cairo_path_fixed_close_path (path);

The last line_to is not necessary.  It's included in close_path().


> +                    if (status) {
> +                        printf("ERROR\n");
> +                       return status; //instead continue without optimization?
> +                    }

No, no need to continue without the optimization.  If something went
wrong, something like out-of-memory should have happened.


-- 
behdad
http://behdad.org/

"Those who would give up Essential Liberty to purchase a little
 Temporary Safety, deserve neither Liberty nor Safety."
        -- Benjamin Franklin, 1759



More information about the cairo mailing list