summaryrefslogtreecommitdiff
path: root/src/cairo-xlib-screen.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-xlib-screen.c')
-rw-r--r--src/cairo-xlib-screen.c331
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;
}