diff options
Diffstat (limited to 'src/cairo-xlib-screen.c')
-rw-r--r-- | src/cairo-xlib-screen.c | 331 |
1 files changed, 204 insertions, 127 deletions
diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c index 8f1e949..fc2535b 100644 --- a/src/cairo-xlib-screen.c +++ b/src/cairo-xlib-screen.c @@ -144,7 +144,7 @@ get_integer_default (Display *dpy, static void _cairo_xlib_init_screen_font_options (Display *dpy, - cairo_xlib_screen_info_t *info) + cairo_xlib_screen_t *info) { cairo_bool_t xft_hinting; cairo_bool_t xft_antialias; @@ -254,8 +254,8 @@ _cairo_xlib_init_screen_font_options (Display *dpy, cairo_font_options_set_hint_metrics (&info->font_options, CAIRO_HINT_METRICS_ON); } -cairo_xlib_screen_info_t * -_cairo_xlib_screen_info_reference (cairo_xlib_screen_info_t *info) +cairo_xlib_screen_t * +_cairo_xlib_screen_reference (cairo_xlib_screen_t *info) { assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&info->ref_count)); @@ -265,48 +265,49 @@ _cairo_xlib_screen_info_reference (cairo_xlib_screen_info_t *info) } void -_cairo_xlib_screen_info_close_display (cairo_xlib_screen_info_t *info) +_cairo_xlib_screen_close_display (cairo_xlib_screen_t *info) { cairo_xlib_visual_info_t **visuals; + Display *dpy; + cairo_atomic_int_t old; int i; CAIRO_MUTEX_LOCK (info->mutex); + + dpy = _cairo_xlib_display_get_dpy (info->display); + +#if HAS_ATOMIC_OPS + do { + old = _cairo_atomic_int_get (&info->gc_depths); + } while (_cairo_atomic_int_cmpxchg (&info->gc_depths, old, 0) != old); +#else + old = info->gc_depths; +#endif + 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; - } + if ((old >> (8*i)) & 0xff) + XFreeGC (dpy, info->gc[i]); } visuals = _cairo_array_index (&info->visuals, 0); for (i = 0; i < _cairo_array_num_elements (&info->visuals); i++) - _cairo_xlib_visual_info_destroy (info->display->display, visuals[i]); + _cairo_xlib_visual_info_destroy (dpy, visuals[i]); _cairo_array_truncate (&info->visuals, 0); CAIRO_MUTEX_UNLOCK (info->mutex); } void -_cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t *info) +_cairo_xlib_screen_destroy (cairo_xlib_screen_t *info) { - cairo_xlib_screen_info_t **prev; - cairo_xlib_screen_info_t *list; - assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&info->ref_count)); if (! _cairo_reference_count_dec_and_test (&info->ref_count)) return; - CAIRO_MUTEX_LOCK (info->display->mutex); - for (prev = &info->display->screens; (list = *prev); prev = &list->next) { - if (list == info) { - *prev = info->next; - break; - } - } - CAIRO_MUTEX_UNLOCK (info->display->mutex); + _cairo_xlib_display_remove_screen (info->display, info); - _cairo_xlib_screen_info_close_display (info); + _cairo_xlib_screen_close_display (info); _cairo_xlib_display_destroy (info->display); @@ -318,146 +319,222 @@ _cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t *info) } cairo_status_t -_cairo_xlib_screen_info_get (cairo_xlib_display_t *display, - Screen *screen, - cairo_xlib_screen_info_t **out) +_cairo_xlib_screen_get (Display *dpy, + Screen *screen, + cairo_xlib_screen_t **out) { - cairo_xlib_screen_info_t *info = NULL, **prev; + cairo_xlib_display_t *display; + cairo_xlib_screen_t *info; + cairo_status_t status; + + status = _cairo_xlib_display_get (dpy, &display); + if (likely (status == CAIRO_STATUS_SUCCESS)) + status = _cairo_xlib_display_get_screen (display, screen, &info); + if (unlikely (status)) + goto CLEANUP_DISPLAY; - CAIRO_MUTEX_LOCK (display->mutex); - if (display->closed) { - CAIRO_MUTEX_UNLOCK (display->mutex); - return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); + if (info != NULL) { + *out = _cairo_xlib_screen_reference (info); + goto CLEANUP_DISPLAY; } - for (prev = &display->screens; (info = *prev); prev = &(*prev)->next) { - if (info->screen == screen) { - /* - * MRU the list - */ - if (prev != &display->screens) { - *prev = info->next; - info->next = display->screens; - display->screens = info; - } - break; - } + info = malloc (sizeof (cairo_xlib_screen_t)); + if (unlikely (info == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_DISPLAY; } - CAIRO_MUTEX_UNLOCK (display->mutex); - if (info != NULL) { - info = _cairo_xlib_screen_info_reference (info); - } else { - info = malloc (sizeof (cairo_xlib_screen_info_t)); - if (unlikely (info == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - CAIRO_REFERENCE_COUNT_INIT (&info->ref_count, 2); /* Add one for display cache */ - CAIRO_MUTEX_INIT (info->mutex); - info->display = _cairo_xlib_display_reference (display); - info->screen = screen; - info->has_render = FALSE; - info->has_font_options = FALSE; - memset (info->gc, 0, sizeof (info->gc)); - info->gc_needs_clip_reset = 0; - - _cairo_array_init (&info->visuals, - sizeof (cairo_xlib_visual_info_t*)); - - if (screen) { - Display *dpy = display->display; - int event_base, error_base; - - info->has_render = (XRenderQueryExtension (dpy, &event_base, &error_base) && - (XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != 0)); - } + CAIRO_REFERENCE_COUNT_INIT (&info->ref_count, 2); /* Add one for display cache */ + CAIRO_MUTEX_INIT (info->mutex); + info->display = display; + info->screen = screen; + info->has_render = FALSE; + info->has_font_options = FALSE; + info->gc_depths = 0; + memset (info->gc, 0, sizeof (info->gc)); + + _cairo_array_init (&info->visuals, + sizeof (cairo_xlib_visual_info_t*)); - /* Small window of opportunity for two screen infos for the same - * Screen - just wastes a little bit of memory but should not cause - * any corruption. - */ - CAIRO_MUTEX_LOCK (display->mutex); - info->next = display->screens; - display->screens = info; - CAIRO_MUTEX_UNLOCK (display->mutex); + if (screen) { + int event_base, error_base; + + info->has_render = + XRenderQueryExtension (dpy, &event_base, &error_base) && + (XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != 0); } + /* Small window of opportunity for two screen infos for the same + * Screen - just wastes a little bit of memory but should not cause + * any corruption. + */ + _cairo_xlib_display_add_screen (display, info); + *out = info; return CAIRO_STATUS_SUCCESS; + + CLEANUP_DISPLAY: + _cairo_xlib_display_destroy (display); + return status; } -static int -depth_to_index (int depth) +#if HAS_ATOMIC_OPS +GC +_cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info, + int depth, + Drawable drawable) { - switch(depth){ - case 1: return 1; - case 8: return 2; - case 12: return 3; - case 15: return 4; - case 16: return 5; - case 24: return 6; - case 30: return 7; - case 32: return 8; + XGCValues gcv; + cairo_atomic_int_t old, new; + int i; + GC gc; + + do { + gc = NULL; + old = info->gc_depths; + if (old == 0) + break; + + if (((old >> 0) & 0xff) == (unsigned) depth) + i = 0; + else if (((old >> 8) & 0xff) == (unsigned) depth) + i = 1; + else if (((old >> 16) & 0xff) == (unsigned) depth) + i = 2; + else if (((old >> 24) & 0xff) == (unsigned) depth) + i = 3; + else + break; + + gc = info->gc[i]; + new = old & ~(0xff << (8*i)); + } while (_cairo_atomic_int_cmpxchg (&info->gc_depths, old, new) != old); + + if (likely (gc != NULL)) { + (void) _cairo_atomic_ptr_cmpxchg (&info->gc[i], gc, NULL); + return gc; } - return 0; + + gcv.graphics_exposures = False; + gcv.fill_style = FillTiled; + return XCreateGC (_cairo_xlib_display_get_dpy (info->display), + drawable, + GCGraphicsExposures | GCFillStyle, &gcv); } +void +_cairo_xlib_screen_put_gc (cairo_xlib_screen_t *info, + int depth, + GC gc) +{ + int i, old, new; + + do { + do { + i = -1; + old = info->gc_depths; + + if (((old >> 0) & 0xff) == 0) + i = 0; + else if (((old >> 8) & 0xff) == 0) + i = 1; + else if (((old >> 16) & 0xff) == 0) + i = 2; + else if (((old >> 24) & 0xff) == 0) + i = 3; + else + goto out; + + new = old | (depth << (8*i)); + } while (_cairo_atomic_ptr_cmpxchg (&info->gc[i], NULL, gc) != NULL); + } while (_cairo_atomic_int_cmpxchg (&info->gc_depths, old, new) != old); + + return; + +out: + if (unlikely (_cairo_xlib_display_queue_work (info->display, + (cairo_xlib_notify_func) XFreeGC, + gc, + NULL))) + { + /* leak the server side resource... */ + XFree ((char *) gc); + } +} +#else GC -_cairo_xlib_screen_get_gc (cairo_xlib_screen_info_t *info, +_cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info, int depth, - unsigned int *dirty) + Drawable drawable) { - GC gc; - cairo_bool_t needs_reset; - - depth = depth_to_index (depth); + GC gc = NULL; + int i; CAIRO_MUTEX_LOCK (info->mutex); - gc = info->gc[depth]; - info->gc[depth] = NULL; - needs_reset = info->gc_needs_clip_reset & (1 << depth); - info->gc_needs_clip_reset &= ~(1 << depth); + for (i = 0; i < ARRAY_LENGTH (info->gc); i++) { + if (((info->gc_depths >> (8*i)) & 0xff) == depth) { + info->gc_depths &= ~(0xff << (8*i)); + gc = info->gc[i]; + break; + } + } CAIRO_MUTEX_UNLOCK (info->mutex); - if (needs_reset) - *dirty |= CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC; + if (gc == NULL) { + XGCValues gcv; + + gcv.graphics_exposures = False; + gcv.fill_style = FillTiled; + gc = XCreateGC (_cairo_xlib_display_get_dpy (info->display), + drawable, + GCGraphicsExposures | GCFillStyle, &gcv); + } 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) +void +_cairo_xlib_screen_put_gc (cairo_xlib_screen_t *info, + int depth, + GC gc) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; - GC oldgc; - - depth = depth_to_index (depth); + int i; CAIRO_MUTEX_LOCK (info->mutex); - oldgc = info->gc[depth]; - info->gc[depth] = gc; - if (reset_clip) - info->gc_needs_clip_reset |= 1 << depth; - else - info->gc_needs_clip_reset &= ~(1 << depth); - CAIRO_MUTEX_UNLOCK (info->mutex); + for (i = 0; i < ARRAY_LENGTH (info->gc); i++) { + if (((info->gc_depths >> (8*i)) & 0xff) == 0) + break; + } - if (oldgc != NULL) { - status = _cairo_xlib_display_queue_work (info->display, - (cairo_xlib_notify_func) XFreeGC, - oldgc, - NULL); + if (i == ARRAY_LENGTH (info->gc)) { + cairo_status_t status; + + /* perform random substitution to ensure fair caching over depths */ + i = rand () % ARRAY_LENGTH (info->gc); + status = + _cairo_xlib_display_queue_work (info->display, + (cairo_xlib_notify_func) XFreeGC, + info->gc[i], + NULL); + if (unlikely (status)) { + /* leak the server side resource... */ + XFree ((char *) info->gc[i]); + } } - return status; + info->gc[i] = gc; + info->gc_depths &= ~(0xff << (8*i)); + info->gc_depths |= depth << (8*i); + CAIRO_MUTEX_UNLOCK (info->mutex); } +#endif cairo_status_t -_cairo_xlib_screen_get_visual_info (cairo_xlib_screen_info_t *info, +_cairo_xlib_screen_get_visual_info (cairo_xlib_screen_t *info, Visual *visual, cairo_xlib_visual_info_t **out) { - Display *dpy = info->display->display; + Display *dpy = _cairo_xlib_display_get_dpy (info->display); cairo_xlib_visual_info_t **visuals, *ret = NULL; cairo_status_t status; int i, n_visuals; @@ -513,19 +590,19 @@ _cairo_xlib_screen_get_visual_info (cairo_xlib_screen_info_t *info, } cairo_font_options_t * -_cairo_xlib_screen_get_font_options (cairo_xlib_screen_info_t *info) +_cairo_xlib_screen_get_font_options (cairo_xlib_screen_t *info) { if (info->has_font_options) return &info->font_options; CAIRO_MUTEX_LOCK (info->mutex); if (! info->has_font_options) { - Display *dpy = info->display->display; - _cairo_font_options_init_default (&info->font_options); - if (info->screen != NULL) - _cairo_xlib_init_screen_font_options (dpy, info); + if (info->screen != NULL) { + _cairo_xlib_init_screen_font_options (_cairo_xlib_display_get_dpy (info->display), + info); + } info->has_font_options = TRUE; } |