[cairo] Clip region problems

Owen Taylor otaylor at redhat.com
Wed May 18 09:27:43 PDT 2005


On Tue, 2005-05-17 at 23:00 -0700, Keith Packard wrote:
> On Mon, 2005-05-02 at 16:48 -0400, Owen Taylor wrote:
> 
> (a long discussion about clip lists in surfaces)
> 
> I've redone the nickle binding (cairo-5c) and the
> new restriction that each surface be targetted by only one cairo_t at a
> time is causing existing code to break.
> 
> I have a multi-threaded application drawing several different objects to
> the same surface; each thread wants to have a private graphics state,
> but they all want to share the same surface.

I assume you have application locking in place here? Or are you
proposing we add explicit locking for the internal state of
cairo_surface_t and the various backends.

(Note that we do things like temporarily change the picture 
attributes of surfaces when using them as sources... the need
to lock *two* surfaces for a drawing operation would definitely
raise some fun deadlock issues)

> Before the BAD_NESTING state, this worked just fine.  

Actually, no it didn't, not if you were using clipping :-)

> Now I get an assertion failure and my program aborts.

I'm actually curious why you got an assertion failure rather than
a silent status (I have the suspicion that there might be some bugs in 
cairo in this area)

But in any case, it seems that the BAD_NESTING error handling is
achieving its purpose ... to catch problems and make people think
about better ways of handling the situation :-)

> I think we should revisit the discussion which prompted the current
> state and see if we really want to keep things like this.
> 
> To me, a surface is an object without any state aside from the image
> drawn there. 

Any *public* state presumably. But this model really only applies at
most to "pixel" surfaces. There is obviously other state in, for 
example, a paginated surface.

> Ok, so I believe the BAD_NESTING status was added to allow the cairo_t
> to place clipping information directly into the backend for efficient
> rectangular pixel-aligned clipping.  A key requirement for efficient
> cairo usage in a windowed environment.

Well, that's a bit ahistorical ... the clipping was placed into the
backend, and then later the clipping stack (and thus the BAD_NESTING
error) was added to make it actually work.

(Clipping isn't usable in 0.4.0, because it leaks out onto the next
user of the surface. This was a huge problem for GTK+.)

One of the understandings of adding nesting restrictions is that they
could always be loosened later if we figured out better ways of doing
things.

> The cairo_surface_t clip region is usually just a copy of the gstate
> clip region, at which times it would be more efficient to just use the
> gstate clip_region directly and not store it in the cairo_surface_t as
> well.  The only unusual case is when compositing trapezoids, the
> cairo_surface_t clip region is temporarily set to the trapezoid region.
> 
> It seems to me what we want is instead of making the surface push/pop
> clip lists, we just want the gstate to tell the surface which clip list
> is in use for each operation and then have the surface cache updates to
> the backend itself.

One thing to be aware of here is that we almost certainly need clip
*paths* in the surface vtable for the metasurface and the PDF/PS
backends. The interface that I've been discussing with Kristian is
along the lines of:

 surface.intersect_clip_with_path (path);
 surface.reset_clip ();

(The reason it's intersect_clip_with_path() rather than set_clip_path()
is to allow us to avoid doing complex computation geometry for 
path intersection)

So any solution that is specific to rectangular clip lists (for example,
the COW pixman_region objects that were discussed earlier), isn't going
to work.

> We just need a way to globally identify region contents and the surface
> can tell when the backend must be informed about a new clip list.  In a
> similar situation, the X server uses 'serial numbers' -- integers
> created by a global counter.  This will be hard in cairo without
> locking, but as a cairo_t (and gstate, by associatio) can only be used
> with a single surface_t, it seems like we can place a serial number
> generator in each surface and use that.
> 
> Surely I'm missing something here; this seems like it will be both more
> general (allowing parallel cairo_t objects to reference the same
> surface) and more efficient (by eliminating duplicate regions in the
> cairo_surface_t).

So, what you are proposing is basically, that before every drawing
operation, we do:

 if (gstate->clip_serial != gstate->surface->clip_serial)
    gstate_reestablish_clip (gstate);

(With some available invalid value used initially for gstate-
>clip_serial)

It's an approach I hadn't thought of, and might in fact be workable.

* It does remove some information from the backend. It's going to 
be harder to optimize sequences like:

 - Clip to one path
 - Save
 - Clip to another path
 - draw
 - Restore
 - draw 

In the PS or PDF backend, because the surface no longer sees the
stack of clips. While in PS/PDF it would be possible to encode the
above with only two clips, with the clip serial approach, the
end result is:

 - Save
 - Clip to one path
 - Clip to another path
 - draw
 - Restore
 - Save
 - Clip to one path
 - draw
 - Restore

Nested clipping when drawing to paper isn't probably common enough
to make this a big worry.

* Using a surface as a source for drawing to itself is going to be a
problem, but it's already a problem, so that's nothing new.

In general, it seems like a promising idea.

Regards,
						Owen

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part
Url : http://lists.freedesktop.org/archives/cairo/attachments/20050518/207f6b08/attachment.pgp


More information about the cairo mailing list