diff options
-rw-r--r-- | src/cairo-surface.c | 4 | ||||
-rw-r--r-- | src/cairo-xcb-private.h | 9 | ||||
-rw-r--r-- | src/cairo-xcb-screen.c | 83 | ||||
-rw-r--r-- | src/cairo-xcb-surface-render.c | 21 |
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); |