From 1d6f7b7a0282d1b24bec82d9ad113b0d0a0cde98 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 19 Apr 2007 13:01:52 +0100 Subject: [PATCH] [cairo-xlib] Cache freed GCs Maintain a cache of freed GCs, one for each used depth. --- src/cairo-xlib-display.c | 6 +++- src/cairo-xlib-private.h | 10 ++++++ src/cairo-xlib-screen.c | 70 ++++++++++++++++++++++++++++++++++++++++ src/cairo-xlib-surface.c | 22 +++++++------ 4 files changed, 98 insertions(+), 10 deletions(-) diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c index 64286cd29..b11eb5ee1 100644 --- a/src/cairo-xlib-display.c +++ b/src/cairo-xlib-display.c @@ -67,11 +67,15 @@ static cairo_xlib_display_t *_cairo_xlib_display_list; static void _cairo_xlib_call_close_display_hooks (cairo_xlib_display_t *display) { - cairo_xlib_hook_t *hooks; + cairo_xlib_screen_info_t *screen; + cairo_xlib_hook_t *hooks; /* call all registered shutdown routines */ CAIRO_MUTEX_LOCK (display->mutex); + for (screen = display->screens; screen != NULL; screen = screen->next) + _cairo_xlib_screen_info_close_display (screen); + hooks = display->close_display_hooks; while (hooks != NULL) { display->close_display_hooks = NULL; diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h index 436c67f90..bdbd7b759 100644 --- a/src/cairo-xlib-private.h +++ b/src/cairo-xlib-private.h @@ -74,6 +74,9 @@ struct _cairo_xlib_screen_info { cairo_bool_t has_render; cairo_font_options_t font_options; + + GC gc[6]; + unsigned int gc_needs_clip_reset; }; cairo_private cairo_xlib_display_t * @@ -109,6 +112,13 @@ _cairo_xlib_screen_info_reference (cairo_xlib_screen_info_t *info); cairo_private void _cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t *info); +cairo_private void +_cairo_xlib_screen_info_close_display (cairo_xlib_screen_info_t *info); + +cairo_private GC +_cairo_xlib_screen_get_gc (cairo_xlib_screen_info_t *info, int depth); +cairo_private cairo_status_t +_cairo_xlib_screen_put_gc (cairo_xlib_screen_info_t *info, int depth, GC gc, cairo_bool_t reset_clip); #if CAIRO_HAS_XLIB_XRENDER_SURFACE diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c index 470524462..0245a43e6 100644 --- a/src/cairo-xlib-screen.c +++ b/src/cairo-xlib-screen.c @@ -254,6 +254,19 @@ _cairo_xlib_screen_info_reference (cairo_xlib_screen_info_t *info) return info; } +void +_cairo_xlib_screen_info_close_display (cairo_xlib_screen_info_t *info) +{ + int i; + + for (i = 0; i < ARRAY_LENGTH (info->gc); i++) { + if (info->gc[i] != NULL) { + XFreeGC (info->display->display, info->gc[i]); + info->gc[i] = NULL; + } + } +} + void _cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t *info) { @@ -277,6 +290,8 @@ _cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t *info) assert (list != NULL); CAIRO_MUTEX_UNLOCK (info->display->mutex); + _cairo_xlib_screen_info_close_display (info); + _cairo_xlib_display_destroy (info->display); free (info); @@ -323,6 +338,8 @@ _cairo_xlib_screen_info_get (Display *dpy, Screen *screen) info->screen = screen; info->has_render = FALSE; _cairo_font_options_init_default (&info->font_options); + memset (info->gc, 0, sizeof (info->gc)); + info->gc_needs_clip_reset = 0; if (screen) { int event_base, error_base; @@ -343,3 +360,56 @@ DONE: return info; } + +static int +depth_to_index (int depth) +{ + switch(depth){ + case 1: return 0; + case 8: return 1; + case 15: return 2; + case 16: return 3; + case 24: return 4; + case 32: return 5; + } + return 0; +} + +GC +_cairo_xlib_screen_get_gc (cairo_xlib_screen_info_t *info, int depth) +{ + GC gc; + + depth = depth_to_index (depth); + + gc = info->gc[depth]; + info->gc[depth] = NULL; + + if (info->gc_needs_clip_reset & (1 << depth)) + XSetClipMask(info->display->display, gc, None); + + return gc; +} + +cairo_status_t +_cairo_xlib_screen_put_gc (cairo_xlib_screen_info_t *info, int depth, GC gc, cairo_bool_t reset_clip) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + depth = depth_to_index (depth); + + if (info->gc[depth] != NULL) { + status = _cairo_xlib_display_queue_work (info->display, + (cairo_xlib_notify_func) XFreeGC, + info->gc[depth], + NULL); + } + + info->gc[depth] = gc; + if (reset_clip) + info->gc_needs_clip_reset |= 1 << depth; + else + info->gc_needs_clip_reset &= ~(1 << depth); + + return status; +} diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 851d282f8..52af255b5 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -309,10 +309,10 @@ _cairo_xlib_surface_finish (void *abstract_surface) if (surface->gc != NULL) { cairo_status_t status2; - status2 = _cairo_xlib_display_queue_work (display, - (cairo_xlib_notify_func) XFreeGC, - surface->gc, - NULL); + status2 = _cairo_xlib_screen_put_gc (surface->screen_info, + surface->depth, + surface->gc, + surface->have_clip_rects); if (status2 == CAIRO_STATUS_SUCCESS) surface->gc = NULL; else if (status == CAIRO_STATUS_SUCCESS) @@ -731,11 +731,15 @@ _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface) if (surface->gc) return CAIRO_STATUS_SUCCESS; - gcv.graphics_exposures = False; - surface->gc = XCreateGC (surface->dpy, surface->drawable, - GCGraphicsExposures, &gcv); - if (!surface->gc) - return CAIRO_STATUS_NO_MEMORY; + surface->gc = _cairo_xlib_screen_get_gc (surface->screen_info, + surface->depth); + if (surface->gc == NULL) { + gcv.graphics_exposures = False; + surface->gc = XCreateGC (surface->dpy, surface->drawable, + GCGraphicsExposures, &gcv); + if (!surface->gc) + return CAIRO_STATUS_NO_MEMORY; + } _cairo_xlib_surface_set_gc_clip_rects (surface);