[cairo] drawing a subimage

Carl Worth cworth at cworth.org
Mon May 8 11:59:26 PDT 2006

On Sun, 07 May 2006 17:38:00 -0400, Jeff Bezanson wrote:
> First, thank you all for your excellent work on Cairo.

You're welcome, (at least for that subset of my work that has been
excellent and not the total garbage that I often do).

> In my application, I need to draw part of an image. Something like
> XCopyArea would be ideal, where you can specify a source width and
> height. Right now I'm doing this with Cairo like so:
>     cairo_rectangle(cr, 0, 0, w, h);
>     cairo_clip(cr);
>     cairo_set_source(cr, pt);
>     cairo_matrix_init_translate(&matrix, xoffs, yoffs);
>     cairo_pattern_set_matrix(pt, &matrix);
>     cairo_paint(cr);

That looks reasonable enough. I would have used
cairo_rectangle;cairo_fill myself as Christian already mentioned. But
no matter, the performance characteristics of the two approaches
should be comparable.

> in other words clipping the output and shifting the image to draw only
> the correct part of it. However, the performance I'm getting suggests
> that the library (somewhere) is touching the entire image, since display
> gets significantly slower as the image gets larger even though the
> visible portion is the same size.

That performance characteristic definitely sounds like a bug.

> Searching the archives of this list I've seen the function
> cairo_surface_clip_rectangle() mentioned, but it does not seem to exist.
> Is there a better way to do this?

No, what you're doing is fine, and you don't need any mystic function
that doesn't exist.

You don't mention what backend you are using, but you do mention
XCopyArea, so I'll say a bit about what the xlib backend has of
interest here.

First, I'll make the assumption that there isn't any scaling, skew, or
rotation going on in your cairo graphics state, (which otherwise
wouldn't be anything like XCopyArea). I'll also assume that w, h,
xoffs, and yoffs above are all integers, (since otherwise you
definitely won't be getting the performance you want).

If those conditions hold, then you should be able to hit an
optimization in cairo-xlib-surface which eventually does lead to a
call to XCopyArea. The code of interest appears is as follows:

    cairo_bool_t is_integer_translation =
        _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL);
    cairo_bool_t needs_alpha_composite =
        _operator_needs_alpha_composite (op, _surface_has_alpha (src));

    if (!have_mask &&
        is_integer_translation &&
        src_attr->extend == CAIRO_EXTEND_NONE &&
        !needs_alpha_composite &&
        _surfaces_compatible(src, dst))
        return DO_XCOPYAREA;

where the _operator_needs_alpha_composite function is:

static cairo_bool_t
_operator_needs_alpha_composite (cairo_operator_t op,
                                 cairo_bool_t     surface_has_alpha)
    if (op == CAIRO_OPERATOR_SOURCE ||
        (!surface_has_alpha &&
         (op == CAIRO_OPERATOR_OVER ||
          op == CAIRO_OPERATOR_ATOP ||
          op == CAIRO_OPERATOR_IN)))
        return FALSE;

    return TRUE;

So it would be worthwhile to chase that down and find out why you're
not hitting that optimization. For example, is it possible you've got
a surface with alpha (perhaps uniformly set to 1 everywhere)? If so,
that would prevent the optimization above, but it could be worked
around by you doing:

	cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);

before your drawing operation.

Also, the above optimization that treats OVER, ATOP, and IN as
equivalent to SOURCE when there is no alpha is currently a
special-case in cairo-xlib-surface.c. It would be worthwhile to start
moving operator re-classification like this up into cairo-surface.c so
that all backends could more easily benefit from it.

Finally, even if you're not hitting the XCopyArea optimization,
(whether for legitimate reasons or not), the code still shouldn't be
touching/transmitting/fetching-and-storing every pixel in the
source. And if the operation is slowing down based on the total size
of the source when only a fixed size is being copied, then I agree
that is sounds like something like that is happening somewhere.

So it would be useful to track that down a bit better.

Maybe a little test program that does the fixed-size copy with a
source of doubling size and just spits out the times for each? Then we
could let any profiling-loving friends on the list go crazy on that.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://lists.freedesktop.org/archives/cairo/attachments/20060508/e950d937/attachment.pgp

More information about the cairo mailing list