[cairo] cacheable image representation now on a branch

Paolo Bonzini bonzini at gnu.org
Mon Dec 1 00:37:02 PST 2008


Hi all,

I've implemented the cacheable representation idea and pushed it to
http://www.inf.unisi.ch/~bonzini/webdav/cairo.git in branch "cache".

To recap, the idea is to replace Quartz image surfaces with a cache
living in a "standard" image surface, which can be queried by backends.
 This removes the need to explicitly create special surfaces such as the
Quartz image surfaces, or to paint the surfaces onto other
backend-specific surfaces just to avoid creating repeatedly a
backend-specific representation.  To test the performance impact, I
modified cairogears (the Glitz benchmark) to use image surfaces instead
of Glitz surfaces for the .png files it loads.  The fps impact was -90%
with non-cacheable surfaces, while no slowdown was measurable with
cacheable surfaces.

The branch uses the idea in the Quartz and Glitz backends.  Other
branches that would benefit are Xlib/XCB (to cache a shared memory copy
of an image surface), or PDF (to automatically generate and cache PNG
representations of the surface).


The branch includes a few preparatory patches that clean up the code or
add some side features.  These may be worth considering indpendent of
the cacheable representation idea, so I placed them at the beginning of
the branch; the cache implementation proper is done only in the last two
patches.  In particular:

1) I fixed the large-source failure for Quartz.

2) the branch also includes the addition of a new surface backend
function, _cairo_acquire_snapshot_image, which avoids generating an
extra copy for surface backends where _cairo_acquire_source_image
already snapshots the surface.

3) finally, the branch also includes a small change in
_cairo_surface_snapshot, where the copying of device transforms and MIME
data is done in _cairo_surface_snapshot rather than in the fallback.
With this change, more backends can easily implement snapshotting
without having to take care about MIME data etc.


Regarding the implementation of the idea, a few design choices worth
pointing out are:

1) I explicitly chose to store opaque pointers instead of surfaces in
the cache.  Doing the latter would have simplified the destruction of
cache entries.  The reason is that storing void * is more flexible.  For
example, the Quartz backend stores CGImages in the cache, which could be
easily changed to store a surface; but if the xlib backend was to use
the cache to map image surfaces to their data's address in XShm shared
memory, it would be inflexible to be able to store surfaces only.

2) There is no capping of the cache, because the user controls
explicitly what to cache.

3) The cache is implemented only for image surfaces even though it would
not be harder to push it up to all surfaces.  This is because usually
you need a mapping of image surfaces to other backends, and of other
backends to image surfaces.  The latter can be done with a single field
in the surface, which is what the Quartz backend does to optimize
acquire_source_image.


The implementation resembles the message I posted last week to the
mailing list with a few changes:

1) the _cairo_image_surface_flush_cache function was replaced by a more
flexible _cairo_image_surface_set_cache;

2) I implemented three cache policies: the one in the message, one that
does the same as Quartz image surfaces, one that minimizes memory usage.


Testing the branch fixed four failures, two in Quartz and two in Glitz.
 The bugs that are fixed are mostly unrelated, which means they might be
latent now rather than fixed for good, I admit.

Paolo



More information about the cairo mailing list