gdk: Make sure only one GL backend is used
authorBenjamin Otte <otte@redhat.com>
Thu, 23 Sep 2021 23:47:03 +0000 (01:47 +0200)
committerBenjamin Otte <otte@redhat.com>
Fri, 24 Sep 2021 11:54:17 +0000 (13:54 +0200)
Creative people managed to create an X11 display and a Wayland display
at once, thereby getting EGL and GLX involved in a fight to the death
over the ownership of the glFoo() symbolspace.

A way to force such a fight with available tools here is (on Wayland)
running something like:
GTK_INSPECTOR_DISPLAY=:1 GTK_DEBUG=interactive gtk4-demo

Related: xdg-desktop-portal-gnome#5

gdk/gdkdisplay.c
gdk/gdkglcontext.c
gdk/gdkglcontextprivate.h
gdk/macos/gdkmacosdisplay.c
gdk/macos/gdkmacosglcontext.c
gdk/wayland/gdkglcontext-wayland.c
gdk/win32/gdkglcontext-win32-egl.c
gdk/win32/gdkglcontext-win32-wgl.c
gdk/x11/gdkglcontext-egl.c
gdk/x11/gdkglcontext-glx.c

index 5067065b03dcac790182da279281c5cb339ed948..1f4b524250f81cbff8b3e75fd186f0a8cf9976ba 100644 (file)
@@ -1233,6 +1233,8 @@ gdk_display_init_gl (GdkDisplay *self)
    */
   priv->gl_context = context;
 
+  gdk_gl_backend_use (GDK_GL_CONTEXT_GET_CLASS (context)->backend_type);
+
   gdk_profiler_end_mark (before, "initialize OpenGL", NULL);
 }
 
index 58dba198abf8a98724469df88d2f2ead575e738c..72e0ecb70fb3d6cc27bb86ab1e38a7156782e2e9 100644 (file)
 #include "config.h"
 
 #include "gdkglcontextprivate.h"
+
+#include "gdkdebug.h"
 #include "gdkdisplayprivate.h"
-#include "gdkmemorytextureprivate.h"
 #include "gdkinternals.h"
-
 #include "gdkintl.h"
+#include "gdkmemorytextureprivate.h"
+
 #include "gdk-private.h"
 
 #ifdef GDK_WINDOWING_WIN32
@@ -1335,3 +1337,68 @@ gdk_gl_context_use_es_bgra (GdkGLContext *context)
 
   return FALSE;
 }
+
+static GdkGLBackend the_gl_backend_type = GDK_GL_NONE;
+
+static const char *gl_backend_names[] = {
+  [GDK_GL_NONE] = "No GL (You should never read this)",
+  [GDK_GL_EGL] = "EGL",
+  [GDK_GL_GLX] = "X11 GLX",
+  [GDK_GL_WGL] = "Windows WGL",
+  [GDK_GL_CGL] = "Apple CGL"
+};
+
+/*<private>
+ * gdk_gl_backend_can_be_used:
+ * @backend_type: Type of backend to check
+ * @error: Return location for an error
+ *
+ * Checks if this backend type can be used. When multiple displays
+ * are opened that use different GL backends, conflicts can arise,
+ * so this function checks that all displays use compatible GL
+ * backends.
+ *
+ * Returns: %TRUE if the backend can still be used
+ */
+gboolean
+gdk_gl_backend_can_be_used (GdkGLBackend   backend_type,
+                            GError       **error)
+{
+  if (the_gl_backend_type == GDK_GL_NONE || 
+      the_gl_backend_type == backend_type)
+    return TRUE;
+
+  g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
+               /* translators: This is about OpenGL backend names, like
+                * "Trying to use X11 GLX, but EGL is already in use" */
+               _("Trying to use %s, but %s is already in use"),
+               gl_backend_names[backend_type],
+               gl_backend_names[the_gl_backend_type]);
+  return FALSE;
+}
+
+/*<private>
+ * gdk_gl_backend_use:
+ * @backend_type: Type of backend
+ *
+ * Ensures that the backend in use is the given one. If another backend
+ * is already in use, this function will abort the program. It should
+ * have previously checked via gdk_gl_backend_can_be_used().
+ **/
+void
+gdk_gl_backend_use (GdkGLBackend backend_type)
+{
+  /* Check that the context class is properly initializing its backend type */
+  g_assert (backend_type != GDK_GL_NONE);
+
+  if (the_gl_backend_type == GDK_GL_NONE)
+    {
+      the_gl_backend_type = backend_type;
+      /* This is important!!!11eleven
+       * (But really: How do I print a message in 2 categories?) */
+      GDK_NOTE (OPENGL, g_print ("Using OpenGL backend %s\n", gl_backend_names[the_gl_backend_type]));
+      GDK_NOTE (MISC, g_message ("Using Opengl backend %s", gl_backend_names[the_gl_backend_type]));
+    }
+
+  g_assert (the_gl_backend_type == backend_type);
+}
index c8afedda02fb768f4ac6adf85aa9c70d934f0b33..050e757608aa06ba6d25be5b0cab488bd971be61 100644 (file)
@@ -34,6 +34,14 @@ G_BEGIN_DECLS
 #define GDK_EGL_MIN_VERSION_MAJOR (1)
 #define GDK_EGL_MIN_VERSION_MINOR (4)
 
+typedef enum {
+  GDK_GL_NONE = 0,
+  GDK_GL_EGL,
+  GDK_GL_GLX,
+  GDK_GL_WGL,
+  GDK_GL_CGL
+} GdkGLBackend;
+
 #define GDK_GL_CONTEXT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_GL_CONTEXT, GdkGLContextClass))
 #define GDK_IS_GL_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_GL_CONTEXT))
 #define GDK_GL_CONTEXT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_GL_CONTEXT, GdkGLContextClass))
@@ -52,6 +60,8 @@ struct _GdkGLContextClass
 {
   GdkDrawContextClass parent_class;
 
+  GdkGLBackend        backend_type;
+
   gboolean              (* realize)                             (GdkGLContext          *context,
                                                                  GError               **error);
 
@@ -86,6 +96,10 @@ typedef struct {
   guint use_es : 1;
 } GdkGLContextPaintData;
 
+gboolean                gdk_gl_backend_can_be_used              (GdkGLBackend     backend_type,
+                                                                 GError         **error);
+void                    gdk_gl_backend_use                      (GdkGLBackend     backend_type);
+
 GdkGLContext *          gdk_gl_context_new_for_surface          (GdkSurface      *surface);
 
 void                    gdk_gl_context_set_is_legacy            (GdkGLContext    *context,
index 450ad2434d55d5d95f8e414aa55d4def43bd83a8..051a92190353ac62cdcba889308950046f5deeee 100644 (file)
@@ -641,6 +641,9 @@ static GdkGLContext *
 gdk_macos_display_init_gl (GdkDisplay  *display,
                            GError     **error)
 {
+  if (!gdk_gl_backend_can_be_used (GDK_GL_CGL, error))
+    return FALSE;
+
   return g_object_new (GDK_TYPE_MACOS_GL_CONTEXT,
                        "display", display,
                        NULL);
index 8e79f7688f055f53404d3e8a9c07e7befcce809b..e959f0e30fb49c71f4b3f72cbd9aa96adfee52c6 100644 (file)
@@ -515,6 +515,8 @@ gdk_macos_gl_context_class_init (GdkMacosGLContextClass *klass)
 
   gl_class->get_damage = gdk_macos_gl_context_get_damage;
   gl_class->realize = gdk_macos_gl_context_real_realize;
+
+  gl_class->backend_type = GDK_GL_CGL;
 }
 
 static void
index 2cf7285fe5e9b6e4631799308863e11353a92ccd..f007ac6576d2a71d2f4247b0c2886333f16a0e54 100644 (file)
@@ -358,6 +358,8 @@ gdk_wayland_gl_context_class_init (GdkWaylandGLContextClass *klass)
   context_class->make_current = gdk_wayland_gl_context_make_current;
   context_class->clear_current = gdk_wayland_gl_context_clear_current;
   context_class->get_damage = gdk_wayland_gl_context_get_damage;
+
+  context_class->backend_type = GDK_GL_EGL;
 }
 
 static void
@@ -475,6 +477,9 @@ gdk_wayland_display_init_gl (GdkDisplay  *display,
   G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
   G_GNUC_UNUSED gint64 start_time2;
 
+  if (!gdk_gl_backend_can_be_used (GDK_GL_EGL, error))
+    return FALSE;
+
   if (!epoxy_has_egl ())
     {
       gboolean sandboxed = gdk_running_in_sandbox ();
index cfc4417a9a3bd11985d7c450205d72e7960d9493..50f57ebe4f23a55cf1994c74f31789496b2cbff1 100644 (file)
@@ -256,6 +256,9 @@ gdk_win32_display_init_egl (GdkDisplay  *display,
   int best_idx = 0;
   EGLDisplay egl_disp;
 
+  if (!gdk_gl_backend_can_be_used (GDK_GL_EGL, error))
+    return FALSE;
+
   if (display_win32->egl_disp != EGL_NO_DISPLAY)
     return TRUE;
   
@@ -488,6 +491,8 @@ gdk_win32_gl_context_egl_class_init (GdkWin32GLContextClass *klass)
   GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS(klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  context_class->backend_type = GDK_GL_EGL;
+
   context_class->realize = gdk_win32_gl_context_egl_realize;
   context_class->make_current = gdk_win32_gl_context_egl_make_current;
   context_class->clear_current = gdk_win32_gl_context_egl_clear_current;
index 010436bd3eae3a80175c081d50de5f3295541e31..64aafbf930df923d3b2c77d89d8c567ae25fd7e7 100644 (file)
@@ -265,6 +265,9 @@ gdk_win32_display_init_wgl (GdkDisplay  *display,
   GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
   HDC hdc;
 
+  if (!gdk_gl_backend_can_be_used (GDK_GL_WGL, error))
+    return FALSE;
+
   if (display_win32->wgl_pixel_format != 0)
     return TRUE;
 
@@ -698,6 +701,8 @@ gdk_win32_gl_context_wgl_class_init (GdkWin32GLContextWGLClass *klass)
   GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  context_class->backend_type = GDK_GL_WGL;
+
   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;
index eb5fd337245c46cbf6546cda1b6dbcfec98c0451..9e3301adf8eee1675e43efc8c25e01b73b2177e9 100644 (file)
@@ -642,6 +642,8 @@ gdk_x11_gl_context_egl_class_init (GdkX11GLContextEGLClass *klass)
   GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  context_class->backend_type = GDK_GL_EGL;
+
   context_class->realize = gdk_x11_gl_context_egl_realize;
   context_class->make_current = gdk_x11_gl_context_egl_make_current;
   context_class->clear_current = gdk_x11_gl_context_egl_clear_current;
@@ -670,6 +672,9 @@ gdk_x11_display_init_egl (GdkX11Display  *self,
   Display *dpy;
   int major, minor;
 
+  if (!gdk_gl_backend_can_be_used (GDK_GL_EGL, error))
+    return FALSE;
+
   dpy = gdk_x11_display_get_xdisplay (display);
 
   if (!epoxy_has_egl ())
index 6e4c46abb147bfed76b5ed1b1ae135d6e3ce05d8..bc1eeb94fb02dc44cebb891d0a41a97a8c621637 100644 (file)
@@ -692,6 +692,8 @@ gdk_x11_gl_context_glx_class_init (GdkX11GLContextGLXClass *klass)
   GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  context_class->backend_type = GDK_GL_GLX;
+
   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;
@@ -905,6 +907,9 @@ gdk_x11_display_init_glx (GdkX11Display  *display_x11,
   Display *dpy;
   int screen_num;
 
+  if (!gdk_gl_backend_can_be_used (GDK_GL_GLX, error))
+    return FALSE;
+
   dpy = gdk_x11_display_get_xdisplay (display);
 
   if (!epoxy_has_glx (dpy))