diff options
Diffstat (limited to 'src/cairo-glx-context.c')
-rw-r--r-- | src/cairo-glx-context.c | 78 |
1 files changed, 63 insertions, 15 deletions
diff --git a/src/cairo-glx-context.c b/src/cairo-glx-context.c index 47634f191..ebe536081 100644 --- a/src/cairo-glx-context.c +++ b/src/cairo-glx-context.c @@ -53,6 +53,10 @@ typedef struct _cairo_glx_context { Window dummy_window; GLXContext context; + Display *previous_display; + GLXDrawable previous_drawable; + GLXContext previous_context; + cairo_bool_t has_multithread_makecurrent; } cairo_glx_context_t; @@ -62,19 +66,54 @@ typedef struct _cairo_glx_surface { Window win; } cairo_glx_surface_t; +static cairo_bool_t +_context_acquisition_changed_glx_state (cairo_glx_context_t *ctx, + GLXDrawable current_drawable) +{ + return !(ctx->previous_display == ctx->display && + ctx->previous_drawable == current_drawable && + ctx->previous_context == ctx->context); +} + +static GLXDrawable +_glx_get_current_drawable (cairo_glx_context_t *ctx) +{ + if (ctx->base.current_target == NULL || + _cairo_gl_surface_is_texture (ctx->base.current_target)) { + return ctx->dummy_window; + } + + return ((cairo_glx_surface_t *) ctx->base.current_target)->win; +} + +static void +_glx_query_current_state (cairo_glx_context_t * ctx) +{ + ctx->previous_drawable = glXGetCurrentDrawable (); + ctx->previous_display = glXGetCurrentDisplay (); + ctx->previous_context = glXGetCurrentContext (); + + /* If any of the values were none, assume they are all none. Not all + drivers seem well behaved when it comes to using these values across + multiple threads. */ + if (ctx->previous_drawable == None + || ctx->previous_display == None + || ctx->previous_context == None) { + ctx->previous_drawable = None; + ctx->previous_display = None; + ctx->previous_context = None; + } +} + static void _glx_acquire (void *abstract_ctx) { cairo_glx_context_t *ctx = abstract_ctx; - GLXDrawable current_drawable; + GLXDrawable current_drawable = _glx_get_current_drawable (ctx); - if (ctx->base.current_target == NULL || - _cairo_gl_surface_is_texture (ctx->base.current_target)) { - current_drawable = ctx->dummy_window; - } else { - cairo_glx_surface_t *surface = (cairo_glx_surface_t *) ctx->base.current_target; - current_drawable = surface->win; - } + _glx_query_current_state (ctx); + if (!_context_acquisition_changed_glx_state (ctx, current_drawable)) + return; glXMakeCurrent (ctx->display, current_drawable, ctx->context); } @@ -94,8 +133,11 @@ _glx_release (void *abstract_ctx) { cairo_glx_context_t *ctx = abstract_ctx; - if (ctx->has_multithread_makecurrent || !ctx->base.thread_aware) + if (ctx->has_multithread_makecurrent || !ctx->base.thread_aware || + !_context_acquisition_changed_glx_state (ctx, + _glx_get_current_drawable (ctx))) { return; + } glXMakeCurrent (ctx->display, None, None); } @@ -118,11 +160,11 @@ _glx_destroy (void *abstract_ctx) if (ctx->dummy_window != None) XDestroyWindow (ctx->display, ctx->dummy_window); - glXMakeCurrent (ctx->display, 0, 0); + glXMakeCurrent (ctx->display, None, None); } static cairo_status_t -_glx_dummy_ctx (Display *dpy, GLXContext gl_ctx, Window *dummy) +_glx_dummy_window (Display *dpy, GLXContext gl_ctx, Window *dummy) { int attr[3] = { GLX_FBCONFIG_ID, 0, None }; GLXFBConfig *config; @@ -181,14 +223,20 @@ cairo_glx_device_create (Display *dpy, GLXContext gl_ctx) Window dummy = None; const char *glx_extensions; - status = _glx_dummy_ctx (dpy, gl_ctx, &dummy); - if (unlikely (status)) - return _cairo_gl_context_create_in_error (status); - ctx = calloc (1, sizeof (cairo_glx_context_t)); if (unlikely (ctx == NULL)) return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY); + /* glx_dummy_window will call glXMakeCurrent, so we need to + * query the current state of the context now. */ + _glx_query_current_state (ctx); + + status = _glx_dummy_window (dpy, gl_ctx, &dummy); + if (unlikely (status)) { + free (ctx); + return _cairo_gl_context_create_in_error (status); + } + ctx->display = dpy; ctx->dummy_window = dummy; ctx->context = gl_ctx; |