[cairo] I don't see the pattern

Carl Worth cworth at cworth.org
Thu Dec 6 13:15:30 PST 2007


On Thu, 6 Dec 2007 22:17:01 +0200, Donn wrote:
> Is there any speed difference between your example and the pattern approach?

Not only is there not a speed difference, there aren't even two
different approaches.

In cairo, you only ever paint from a pattern. It *looks* like you
paint from a surface with:

	cairo_set_source_surface (cr, surface, x, y);
	cairo_paint (cr);

but that's really just a convenience for what is literally happening:

	cairo_matrix_t matrix;
	cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);

	cairo_matrix_init_translate (&matrix, -x, -y);
	cairo_pattern_set_matrix (pattern, &matrix);

	cairo_set_source (cr, pattern);
	cairo_pattern_destroy (pattern);

So there's no performance difference there, (whether "you" create the
pattern or let cairo do it doesn't matter). True you could save a
single malloc by holding onto a pattern, but I doubt will be
significant.

But maybe by "pattern approach" you were asking about the notion of using
cairo_push_group;cairo_pop_group to construct your intermediate
surface and pattern? Let's see which is more convenient.

> As to using C, go for it! I'm far too thick to use it, but I can mangle it
> into Python as I need to.

Thanks. That does help. First, let's first start with a function
shell:

void
draw_cached_object (object_t *obj, cairo_t *cr)
{
    cairo_save (cr);

    ...

    cairo_restore (cr);
}

Each of the below examples could be inserted in the place of "..."
above. We assume there's a draw_object function that does the actual
drawing, (and that the object is drawn right up against the (0,0)
origin).

First, my previous example using cairo_surface_create_similar:

    if (! obj->cached_surface)
    {
	cairo_surface_t *target = cairo_get_target (cr);
	cairo_t *cr2;

	obj->cached_surface = cairo_surface_create_similar (target,
					CAIRO_CONTENT_COLOR_ALPHA,
					obj->width, obj->height);
	cr2 = cairo_create (obj->cached_surface);
	draw_object (obj, cr2);
	/* XXX: Should check cairo_status here */
	cairo_destroy (cr2);
    }
    cairo_set_source_surface (cr, obj->cached_surface, obj->x, obj->y);
    cairo_paint (cr);

Now let's try that again with cairo_push_group:

    if (! obj->cached_pattern)
    {
	cairo_push_group (cr);
	draw_object (obj, cr);
	obj->cached_pattern = cairo_pop_group (cr);
    }
    cairo_set_source (cr, obj->cached_pattern);
    cairo_paint (cr);

Cool! That's definitely a lot more convenient.

Potential problems though are positioning and size. With the first
approach you can change the object's position each time with the
explicit arguments to cairo_set_source_surface. In the second example,
to achieve the same result you'll have to add something more.

Also, since cairo_push_group is implicitly creating the intermediate
surface for you,you're not directly controlling its size. You can
indirectly influence that with cairo_clip first.

So here's the second example rewritten to address both of those
issues:

    if (! obj->cached_pattern)
    {
	cairo_save (cr);
	cairo_rectangle (cr, 0, 0, obj->width, obj->height);
	cairo_clip (cr);

	cairo_push_group (cr);
	draw_object (obj, cr);
	obj->cached_pattern = cairo_pop_group (cr);

	cairo_restore (cr);
    }
    cairo_translate (cr, obj->x, obj->y);
    cairo_set_source (cr, obj->cached_pattern);
    cairo_paint (cr);

At that point this approach looks like a bit more typing. But it is
still simpler in not having to deal with the two intermediate
cairo_surface_t* and cairo_t* variables, (especially that ugly and
potentially confusing cr2). And avoiding an intermediate cairo_t* even
means that any error status isn't lost in the final example, (no need
to check cairo_status like in the first case).

But really none of this should have much performance impact. For the
real work that's happening, it's all the same, (unless you have a tiny
object and a huge surface and don't do the cairo_clip before
cairo_push_group).

I hope that helps, and that you keep having fun with cairo.

-Carl
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://lists.cairographics.org/archives/cairo/attachments/20071206/0845407c/attachment.pgp 


More information about the cairo mailing list