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