From 712919223d08f8b4c43f828322fdc285560c137f Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 26 Mar 2010 15:50:10 +0100 Subject: [PATCH] gl: Make code safe for multithreaded access The code callss the gl device's acquire/release in cairo_device_acquire/release(). This way, external APIs can use these functions to prepare for rendering GL. Also adds code to unset the glx context if it wasn't set when acquiring the device. This allows multithreaded apps to work fine with just using cairo APIs, but might introduce penalties in single-threaded applications. --- src/cairo-egl-context.c | 2 ++ src/cairo-gl-private.h | 5 ++++- src/cairo-gl-surface.c | 20 +++++++++++++++++++- src/cairo-glx-context.c | 37 +++++++++++++++++++++++++++++++++++-- 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/cairo-egl-context.c b/src/cairo-egl-context.c index 7093ea032..c373bd8ed 100644 --- a/src/cairo-egl-context.c +++ b/src/cairo-egl-context.c @@ -104,6 +104,8 @@ cairo_egl_device_create (EGLDisplay dpy, EGLContext egl) ctx->display = dpy; ctx->context = egl; + ctx->base.acquire = NULL; /* FIXME */ + ctx->base.release = NULL; /* FIXME */ ctx->base.make_current = _egl_make_current; ctx->base.swap_buffers = _egl_swap_buffers; ctx->base.destroy = _egl_destroy; diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h index cfb563b5b..c283620d9 100644 --- a/src/cairo-gl-private.h +++ b/src/cairo-gl-private.h @@ -136,7 +136,10 @@ typedef struct _cairo_gl_context { cairo_gl_glyph_cache_t glyph_cache[2]; cairo_list_t fonts; - void (*make_current)(void *ctx, cairo_gl_surface_t *surface); + void (*acquire) (void *ctx); + void (*release) (void *ctx); + + void (*make_current) (void *ctx, cairo_gl_surface_t *surface); void (*swap_buffers)(void *ctx, cairo_gl_surface_t *surface); void (*destroy) (void *ctx); } cairo_gl_context_t; diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c index 9107d4d8e..5fca01814 100644 --- a/src/cairo-gl-surface.c +++ b/src/cairo-gl-surface.c @@ -67,6 +67,23 @@ static cairo_bool_t _cairo_surface_is_gl (cairo_surface_t *surface) return surface->backend == &_cairo_gl_surface_backend; } +static void +_gl_lock (void *device) +{ + cairo_gl_context_t *ctx = (cairo_gl_context_t *) device; + + ctx->acquire (ctx); +} + +static void +_gl_unlock (void *device) +{ + cairo_gl_context_t *ctx = (cairo_gl_context_t *) device; + + ctx->release (ctx); + ctx->current_target = NULL; +} + static void _gl_destroy (void *device) { @@ -94,7 +111,8 @@ _gl_destroy (void *device) static const cairo_device_backend_t _cairo_gl_device_backend = { CAIRO_DEVICE_TYPE_GL, - NULL, NULL, /* lock, unlock */ + _gl_lock, + _gl_unlock, NULL, /* flush */ NULL, /* finish */ diff --git a/src/cairo-glx-context.c b/src/cairo-glx-context.c index 0cc31d35c..f519443d2 100644 --- a/src/cairo-glx-context.c +++ b/src/cairo-glx-context.c @@ -52,6 +52,9 @@ typedef struct _cairo_glx_context { Display *display; Window dummy_window; GLXContext context; + + GLXContext prev_context; + GLXDrawable prev_drawable; } cairo_glx_context_t; typedef struct _cairo_glx_surface { @@ -61,8 +64,20 @@ typedef struct _cairo_glx_surface { } cairo_glx_surface_t; static void -_glx_make_current (void *abstract_ctx, - cairo_gl_surface_t *abstract_surface) +_glx_acquire (void *abstract_ctx) +{ + cairo_glx_context_t *ctx = abstract_ctx; + + ctx->prev_context = glXGetCurrentContext (); + ctx->prev_drawable = glXGetCurrentDrawable (); + + /* XXX: This is necessary with current code, but shouldn't be */ + if (ctx->prev_context != ctx->context) + glXMakeCurrent (ctx->display, ctx->dummy_window, ctx->context); +} + +static void +_glx_make_current (void *abstract_ctx, cairo_gl_surface_t *abstract_surface) { cairo_glx_context_t *ctx = abstract_ctx; cairo_glx_surface_t *surface = (cairo_glx_surface_t *) abstract_surface; @@ -71,6 +86,18 @@ _glx_make_current (void *abstract_ctx, glXMakeCurrent (ctx->display, surface->win, ctx->context); } +static void +_glx_release (void *abstract_ctx) +{ + cairo_glx_context_t *ctx = abstract_ctx; + + if (ctx->prev_context != glXGetCurrentContext () || + ctx->prev_drawable != glXGetCurrentDrawable ()) + glXMakeCurrent (ctx->display, + ctx->prev_drawable, + ctx->prev_context); +} + static void _glx_swap_buffers (void *abstract_ctx, cairo_gl_surface_t *abstract_surface) @@ -162,7 +189,11 @@ cairo_glx_device_create (Display *dpy, GLXContext gl_ctx) ctx->display = dpy; ctx->dummy_window = dummy; ctx->context = gl_ctx; + ctx->prev_context = NULL; + ctx->prev_drawable = None; + ctx->base.acquire = _glx_acquire; + ctx->base.release = _glx_release; ctx->base.make_current = _glx_make_current; ctx->base.swap_buffers = _glx_swap_buffers; ctx->base.destroy = _glx_destroy; @@ -173,6 +204,8 @@ cairo_glx_device_create (Display *dpy, GLXContext gl_ctx) return _cairo_gl_context_create_in_error (status); } + ctx->base.release (ctx); + return &ctx->base.base; }