summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cairo-surface.c4
-rw-r--r--src/cairo-xcb-private.h9
-rw-r--r--src/cairo-xcb-screen.c83
-rw-r--r--src/cairo-xcb-surface-render.c21
4 files changed, 113 insertions, 4 deletions
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 47cfe2a2..0f704e13 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -645,6 +645,8 @@ cairo_surface_finish (cairo_surface_t *surface)
cairo_surface_flush (surface);
+ surface->finished = TRUE;
+
/* call finish even if in error mode */
if (surface->backend->finish) {
status = surface->backend->finish (surface);
@@ -652,8 +654,6 @@ cairo_surface_finish (cairo_surface_t *surface)
status = _cairo_surface_set_error (surface, status);
}
- surface->finished = TRUE;
-
if (surface->snapshot_of != NULL)
_cairo_surface_detach_snapshot (surface);
}
diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h
index e9abe211..c8ab5092 100644
--- a/src/cairo-xcb-private.h
+++ b/src/cairo-xcb-private.h
@@ -115,6 +115,7 @@ struct _cairo_xcb_screen_t {
} solid_cache[16];
int solid_cache_size;
+ cairo_cache_t surface_pattern_cache;
cairo_cache_t linear_pattern_cache;
cairo_cache_t radial_pattern_cache;
cairo_freelist_t pattern_cache_entry_freelist;
@@ -244,6 +245,14 @@ _cairo_xcb_screen_stash_id (cairo_xcb_screen_t *screen, uint32_t xid);
#endif
cairo_private cairo_status_t
+_cairo_xcb_screen_store_surface_picture (cairo_xcb_screen_t *screen,
+ cairo_surface_t *picture,
+ unsigned int size);
+cairo_private void
+_cairo_xcb_screen_remove_surface_picture (cairo_xcb_screen_t *screen,
+ cairo_surface_t *picture);
+
+cairo_private cairo_status_t
_cairo_xcb_screen_store_linear_picture (cairo_xcb_screen_t *screen,
const cairo_linear_pattern_t *linear,
cairo_surface_t *picture);
diff --git a/src/cairo-xcb-screen.c b/src/cairo-xcb-screen.c
index baec2941..27e92bf0 100644
--- a/src/cairo-xcb-screen.c
+++ b/src/cairo-xcb-screen.c
@@ -55,6 +55,7 @@ _cairo_xcb_screen_destroy (cairo_xcb_screen_t *screen)
/* As the cached pictures hold a reference to the screen,
* the caches must already be empty.
*/
+ _cairo_cache_fini (&screen->surface_pattern_cache);
_cairo_cache_fini (&screen->linear_pattern_cache);
_cairo_cache_fini (&screen->radial_pattern_cache);
_cairo_freelist_fini (&screen->pattern_cache_entry_freelist);
@@ -64,6 +65,14 @@ _cairo_xcb_screen_destroy (cairo_xcb_screen_t *screen)
}
static cairo_bool_t
+_surface_pattern_cache_entry_equal (const void *A, const void *B)
+{
+ const struct pattern_cache_entry *a = A, *b = B;
+
+ return a->key.hash == b->key.hash;
+}
+
+static cairo_bool_t
_linear_pattern_cache_entry_equal (const void *A, const void *B)
{
const struct pattern_cache_entry *a = A, *b = B;
@@ -88,6 +97,21 @@ _radial_pattern_cache_entry_equal (const void *A, const void *B)
}
static void
+_surface_cache_entry_destroy (void *closure)
+{
+ struct pattern_cache_entry *entry = closure;
+ cairo_xcb_screen_t *screen;
+
+ screen = _cairo_xcb_screen_reference (entry->screen);
+
+ cairo_surface_finish (entry->picture);
+ cairo_surface_destroy (entry->picture);
+ _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
+
+ _cairo_xcb_screen_destroy (screen);
+}
+
+static void
_pattern_cache_entry_destroy (void *closure)
{
struct pattern_cache_entry *entry = closure;
@@ -144,13 +168,22 @@ _cairo_xcb_screen_create (xcb_connection_t *xcb_connection,
screen->solid_cache_size = 0;
+ status = _cairo_cache_init (&screen->surface_pattern_cache,
+ _surface_pattern_cache_entry_equal,
+ NULL,
+ _surface_cache_entry_destroy,
+ 16*1024*1024);
+ if (unlikely (status))
+ goto error_screen;
+
+
status = _cairo_cache_init (&screen->linear_pattern_cache,
_linear_pattern_cache_entry_equal,
NULL,
_pattern_cache_entry_destroy,
16);
if (unlikely (status))
- goto error_screen;
+ goto error_surface;
status = _cairo_cache_init (&screen->radial_pattern_cache,
_radial_pattern_cache_entry_equal,
@@ -170,6 +203,8 @@ unlock:
return screen;
+error_surface:
+ _cairo_cache_fini (&screen->surface_pattern_cache);
error_linear:
_cairo_cache_fini (&screen->linear_pattern_cache);
error_screen:
@@ -346,6 +381,52 @@ _cairo_xcb_screen_put_gc (cairo_xcb_screen_t *screen, int depth, GC gc)
#endif
cairo_status_t
+_cairo_xcb_screen_store_surface_picture (cairo_xcb_screen_t *screen,
+ cairo_surface_t *picture,
+ unsigned int size)
+{
+ struct pattern_cache_entry *entry;
+ cairo_status_t status;
+
+ entry = _cairo_freelist_alloc (&screen->pattern_cache_entry_freelist);
+ if (unlikely (entry == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ entry->key.hash = picture->unique_id;
+ entry->key.size = size;
+
+ entry->picture = cairo_surface_reference (picture);
+ entry->screen = screen;
+
+ CAIRO_MUTEX_LOCK (screen->mutex);
+ status = _cairo_cache_insert (&screen->surface_pattern_cache,
+ &entry->key);
+ CAIRO_MUTEX_UNLOCK (screen->mutex);
+ if (unlikely (status)) {
+ _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
+ return status;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_xcb_screen_remove_surface_picture (cairo_xcb_screen_t *screen,
+ cairo_surface_t *picture)
+{
+ struct pattern_cache_entry tmpl;
+ struct pattern_cache_entry *entry;
+
+ tmpl.key.hash = picture->unique_id;
+
+ CAIRO_MUTEX_LOCK (screen->mutex);
+ entry = _cairo_cache_lookup (&screen->surface_pattern_cache, &tmpl.key);
+ if (entry != NULL)
+ _cairo_cache_remove (&screen->surface_pattern_cache, &entry->key);
+ CAIRO_MUTEX_UNLOCK (screen->mutex);
+}
+
+cairo_status_t
_cairo_xcb_screen_store_linear_picture (cairo_xcb_screen_t *screen,
const cairo_linear_pattern_t *linear,
cairo_surface_t *picture)
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index d77ea62d..e3f31831 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -917,6 +917,15 @@ setup_picture:
return picture;
}
+static void
+_decouple_cached_picture (cairo_surface_t *surface)
+{
+ cairo_xcb_picture_t *picture = (cairo_xcb_picture_t *) surface;
+
+ if (! picture->base.finished)
+ _cairo_xcb_screen_remove_surface_picture (picture->screen, &picture->base);
+}
+
static cairo_xcb_picture_t *
_cairo_xcb_surface_picture (cairo_xcb_surface_t *target,
const cairo_surface_pattern_t *pattern,
@@ -985,7 +994,17 @@ _cairo_xcb_surface_picture (cairo_xcb_surface_t *target,
return picture;
}
- status = _cairo_surface_attach_snapshot (source, &picture->base, NULL);
+ status = _cairo_xcb_screen_store_surface_picture (target->screen,
+ &picture->base,
+ CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP (picture->pixman_format)) * picture->height);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&picture->base);
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+ }
+
+ status = _cairo_surface_attach_snapshot (source,
+ &picture->base,
+ _decouple_cached_picture);
if (unlikely (status)) {
cairo_surface_destroy (&picture->base);
return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);