gdk: Add private GLContext::is_current() check
authorBenjamin Otte <otte@redhat.com>
Thu, 2 Feb 2023 01:49:56 +0000 (02:49 +0100)
committerBenjamin Otte <otte@redhat.com>
Thu, 2 Feb 2023 03:23:51 +0000 (04:23 +0100)
... and use this check in gdk_gl_context_make_current() and
gdk_gl_context_get_current() to make sure the context really is still
current.

The context no longer being current can happen when external GL
implementations make their own contexts current in the same threads GDK
contexts are used in.
And that can happen for example by WebKit.

Theoretically, this should also allow external EGL code to run in X11
applications when GDK chooses to use GLX, but I didn't try it.

Fixes #5392

gdk/gdkglcontext.c
gdk/gdkglcontextprivate.h
gdk/macos/gdkmacosglcontext.c
gdk/win32/gdkglcontext-win32-wgl.c
gdk/x11/gdkglcontext-glx.c

index 599b946de9f27d13839ac568373c6b7172e6c680..a46ffdb9d9c63940419b75f52141c961fa72f2d6 100644 (file)
@@ -501,6 +501,18 @@ gdk_gl_context_real_is_shared (GdkGLContext *self,
   return TRUE;
 }
 
+static gboolean
+gdk_gl_context_real_is_current (GdkGLContext *self)
+{
+#ifdef HAVE_EGL
+  GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
+
+  return priv->egl_context == eglGetCurrentContext ();
+#else
+  return TRUE;
+#endif
+}
+
 static gboolean
 gdk_gl_context_real_clear_current (GdkGLContext *context)
 {
@@ -670,6 +682,7 @@ gdk_gl_context_class_init (GdkGLContextClass *klass)
   klass->is_shared = gdk_gl_context_real_is_shared;
   klass->make_current = gdk_gl_context_real_make_current;
   klass->clear_current = gdk_gl_context_real_clear_current;
+  klass->is_current = gdk_gl_context_real_is_current;
   klass->get_default_framebuffer = gdk_gl_context_real_get_default_framebuffer;
 
   draw_context_class->begin_frame = gdk_gl_context_real_begin_frame;
@@ -1551,6 +1564,12 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
   priv->extensions_checked = TRUE;
 }
 
+static gboolean
+gdk_gl_context_check_is_current (GdkGLContext *context)
+{
+  return GDK_GL_CONTEXT_GET_CLASS (context)->is_current (context);
+}
+
 /**
  * gdk_gl_context_make_current:
  * @context: a `GdkGLContext`
@@ -1569,7 +1588,7 @@ gdk_gl_context_make_current (GdkGLContext *context)
   masked_context = mask_context (context, surfaceless);
 
   current = g_private_get (&thread_current_context);
-  if (current == masked_context)
+  if (current == masked_context && gdk_gl_context_check_is_current (context))
     return;
 
   /* we need to realize the GdkGLContext if it wasn't explicitly realized */
@@ -1740,10 +1759,18 @@ GdkGLContext *
 gdk_gl_context_get_current (void)
 {
   MaskedContext *current;
+  GdkGLContext *context;
 
   current = g_private_get (&thread_current_context);
+  context = unmask_context (current);
+
+  if (context && !gdk_gl_context_check_is_current (context))
+    {
+      g_private_replace (&thread_current_context, NULL);
+      context = NULL;
+    }
 
-  return unmask_context (current);
+  return context;
 }
 
 gboolean
index bd66172ebab8d0123712cb19221567b06b386dd9..2ed799d6f74cc8665a47fcb0a72b05f9c20def56 100644 (file)
@@ -83,6 +83,7 @@ struct _GdkGLContextClass
   gboolean              (* make_current)                        (GdkGLContext          *context,
                                                                  gboolean               surfaceless);
   gboolean              (* clear_current)                       (GdkGLContext          *context);
+  gboolean              (* is_current)                          (GdkGLContext          *context);
   cairo_region_t *      (* get_damage)                          (GdkGLContext          *context);
 
   gboolean              (* is_shared)                           (GdkGLContext          *self,
index 8b6b928d5f99efd26be298f416ad7c45f8f65082..5dc7c202ef143288e445036f77d66d11058221ef 100644 (file)
@@ -548,6 +548,14 @@ gdk_macos_gl_context_clear_current (GdkGLContext *context)
   return TRUE;
 }
 
+static gboolean
+gdk_macos_gl_context_is_current (GdkGLContext *context)
+{
+  GdkMacosGLContext *self = GDK_MACOS_GL_CONTEXT (context);
+
+  return self->cgl_context == CGLGetCurrentContext ();
+}
+
 static gboolean
 gdk_macos_gl_context_make_current (GdkGLContext *context,
                                    gboolean      surfaceless)
@@ -639,6 +647,7 @@ gdk_macos_gl_context_class_init (GdkMacosGLContextClass *klass)
 
   gl_class->get_damage = gdk_macos_gl_context_get_damage;
   gl_class->clear_current = gdk_macos_gl_context_clear_current;
+  gl_class->is_current = gdk_macos_gl_context_is_current;
   gl_class->make_current = gdk_macos_gl_context_make_current;
   gl_class->realize = gdk_macos_gl_context_real_realize;
   gl_class->get_default_framebuffer = gdk_macos_gl_context_get_default_framebuffer;
index f15d64d34b9f086a68fcbd672ae9ec1b3536f6a1..4c32a74f887e3d0bcbf56f883450ae3aab57a738 100644 (file)
@@ -631,6 +631,14 @@ gdk_win32_gl_context_wgl_clear_current (GdkGLContext *context)
   return wglMakeCurrent (NULL, NULL);
 }
 
+static gboolean
+gdk_win32_gl_context_wgl_is_current (GdkGLContext *context)
+{
+  GdkWin32GLContextWGL *self = GDK_WIN32_GL_CONTEXT_WGL (context);
+
+  return self->wgl_context == wglGetCurrentContext ();
+}
+
 static gboolean
 gdk_win32_gl_context_wgl_make_current (GdkGLContext *context,
                                        gboolean      surfaceless)
@@ -682,6 +690,7 @@ gdk_win32_gl_context_wgl_class_init (GdkWin32GLContextWGLClass *klass)
   context_class->realize = gdk_win32_gl_context_wgl_realize;
   context_class->make_current = gdk_win32_gl_context_wgl_make_current;
   context_class->clear_current = gdk_win32_gl_context_wgl_clear_current;
+  context_class->is_current = gdk_win32_gl_context_wgl_is_current;
 
   draw_context_class->begin_frame = gdk_win32_gl_context_wgl_begin_frame;
   draw_context_class->end_frame = gdk_win32_gl_context_wgl_end_frame;
index 6be6eb7e16dea5ceba3153f93a13e85bc2cd7d26..db3040442ceaae57e0d2a05f4b98fd87f63667ea 100644 (file)
@@ -210,6 +210,14 @@ gdk_x11_gl_context_glx_clear_current (GdkGLContext *context)
   return TRUE;
 }
 
+static gboolean
+gdk_x11_gl_context_glx_is_current (GdkGLContext *context)
+{
+  GdkX11GLContextGLX *self = GDK_X11_GL_CONTEXT_GLX (context);
+
+  return self->glx_context == glXGetCurrentContext ();
+}
+
 static gboolean
 gdk_x11_gl_context_glx_make_current (GdkGLContext *context,
                                      gboolean      surfaceless)
@@ -685,6 +693,7 @@ gdk_x11_gl_context_glx_class_init (GdkX11GLContextGLXClass *klass)
   context_class->realize = gdk_x11_gl_context_glx_realize;
   context_class->make_current = gdk_x11_gl_context_glx_make_current;
   context_class->clear_current = gdk_x11_gl_context_glx_clear_current;
+  context_class->is_current = gdk_x11_gl_context_glx_is_current;
   context_class->get_damage = gdk_x11_gl_context_glx_get_damage;
 
   draw_context_class->end_frame = gdk_x11_gl_context_glx_end_frame;