Bug 30003 - surface change serial / damage API
Summary: surface change serial / damage API
Status: RESOLVED MOVED
Alias: None
Product: cairo
Classification: Unclassified
Component: general (show other bugs)
Version: 1.9.15
Hardware: Other All
: medium normal
Assignee: Carl Worth
QA Contact: cairo-bugs mailing list
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-09-03 13:46 UTC by Havoc Pennington
Modified: 2018-08-25 14:00 UTC (History)
1 user (show)

See Also:
i915 platform:
i915 features:


Attachments

Description Havoc Pennington 2010-09-03 13:46:30 UTC
What do you think of an API like:

uint32_t cairo_surface_get_change_serial(cairo_surface_t*);

where cairo surface would keep a serial that cairo increments whenever it modifies the surface or someone calls mark_dirty().

The purpose would be to allow caching something based on the surface.
For example for an image surface, in GdkPixbuf we might cache a converted copy of the pixels in the GdkPixbuf format. Or for GDK, it might be nice to cache an X-server-side copy of certain images.

the intended usage is:

 cache_something(surface) {
    if (cache.serial != cairo_surface_get_change_serial(surface)) {
      cache.something = something_based_on_surface(surface);
      cache.serial = cairo_surface_get_change_serial(surface);
    }
 }

Since the serial is just checked for equality, don't think it matters that it will wrap around eventually. may not need 32 bits. (could even keep anyone from relying on sequence by rearranging some bits when returning the serial, to be cute)
Comment 1 Benjamin Otte 2010-09-03 16:07:44 UTC
I think I prefer signal handlers for dirty regions like the APIs Søren orignally proposed.
Basically the same as a GSignal for mark_dirty_area().

I don't even think it'd be hard to support - we'd start by just marking the operation's extents we compute anyway as dirty - and it's a much more flexible API than counting some "operation" on a surface.
Comment 2 Havoc Pennington 2010-09-03 21:43:50 UTC
I haven't seen Søren's proposal, link? The serial approach has the advantage of being trivial to implement and zero-overhead...

Agree a signal is more flexible, but it would have to cover all changes, not just "external" changes like mark_dirty does now.

how are you going to do signals in cairo? (have to say: once you're adding signals the gobject reinvention is getting painful. signals are pretty hard, too, if you handle all the weird reentrancy cases only Tim Janik can keep track of)

A damage-based API could be nice. Would probably want to allow multiple damage regions per surface, like

damage* damage_create(surface)
damage_reference(damage)
damage_destroy(damage)
region* damage_subtract(damage)

you could also put a callback here like:
 damage_set_notify(damage, callback, data, dnotify_data)

rather than trying to do a full "signal system" 

fwiw, this is overkill for the two cases I had in mind (detect when to copy cairo pixels to gdkpixbuf pixels; detect when to update a server-side copy of an image surface). The cache invalidation serial is totally fine for cache-expiration purposes.

But I can imagine uses for damage too. For example an incremental image loader could just hand a surface to something like GtkImage and have things magically work. (GtkImage would get damage as new pixels arrived.)
Comment 3 Behdad Esfahbod 2010-09-27 18:12:50 UTC
I also like a serial change API.  I'm more interested in having one on cairo_t though.  My usecase is that in pango entry points, I want to quickly check the serial to see if the font matrix / options / ... may have changed on the context.  Only if the context has changed I want to do the heavier query on all those stuff.
Comment 4 Havoc Pennington 2010-09-28 15:23:13 UTC
After thinking about this for a bit I like the idea of a damage API on surface, if you have a Damage object per subscriber then each subscriber gets their own damage region and the only overhead in cairo_surface_t could be one pointer for the head of a list of Damage objects. Also you avoid worrying about generic signals (callback lists) since each Damage object could just support a single notifier function.

For cairo_context_t it seems like you'd get into what "counts" as a change ? Maybe you end up wanting the equivalent of a damage object:

 CairoContextChanges { 
    unsigned int matrix_changed : 1;
    unsigned int font_changed : 1;
    // ... etc. 
 }

cairo_context_changes_t* changes_create();
changes_reset()
changes_get_matrix_changed() // changed since reset
changes_get_font_changed()

and just like surface damage object, have a changes_set_notify().

Maybe both surface and context "change trackers" should be named the same,
cairo_surface_changes_t
cairo_context_changes_t

or

cairo_surface_damage_t
cairo_context_damage_t

just thinking out loud.

But yeah, the change serial is definitely a lot simpler and gives you a global "are caches invalid?" flag that's already useful.
Comment 5 Uli Schlachter 2013-03-23 16:42:08 UTC
This only adresses the original "callback when surface content changes", but you can (ab)use cairo_surface_set_mime_data() to get a callback when a surface is modified.

An example for this can be found here: https://bugzilla.mozilla.org/attachment.cgi?id=624394&action=diff
Comment 6 GitLab Migration User 2018-08-25 14:00:08 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/cairo/cairo/issues/308.


Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.