gl: Clear current when destroying current's surface
authorBenjamin Otte <otte@redhat.com>
Wed, 22 Dec 2021 18:49:13 +0000 (19:49 +0100)
committerBenjamin Otte <otte@redhat.com>
Wed, 22 Dec 2021 19:00:52 +0000 (20:00 +0100)
When destroying the EGLSurface or GLXDrawable of a GdkSurface, make sure
the current context is not still bound to it.

If it is, clear the current context.

Fixes #4554

gdk/gdkglcontext.c
gdk/gdkglcontextprivate.h
gdk/gdksurface.c
gdk/x11/gdkglcontext-glx.c

index 23c5eba8bf6643705bc6d5a6880680c7e9cfb883..9ab690f6fa110858a89bebb157754b71d8e395a3 100644 (file)
@@ -151,6 +151,12 @@ unmask_context (MaskedContext *mask)
   return GDK_GL_CONTEXT (GSIZE_TO_POINTER (GPOINTER_TO_SIZE (mask) & ~(gsize) 1));
 }
 
+static inline gboolean
+mask_is_surfaceless (MaskedContext *mask)
+{
+  return GPOINTER_TO_SIZE (mask) & (gsize) 1;
+}
+
 static void
 unref_unmasked (gpointer data)
 {
@@ -1655,6 +1661,31 @@ gdk_gl_context_clear_current (void)
     }
 }
 
+/*<private>
+ * gdk_gl_context_clear_current_if_surface:
+ * @surface: surface to clear for
+ *
+ * Does a gdk_gl_context_clear_current() if the current context is attached
+ * to @surface, leaves the current context alone otherwise.
+ **/
+void
+gdk_gl_context_clear_current_if_surface (GdkSurface *surface)
+{
+  MaskedContext *current;
+
+  current = g_private_get (&thread_current_context);
+  if (current != NULL && !mask_is_surfaceless (current))
+    {
+      GdkGLContext *context = unmask_context (current);
+
+      if (gdk_gl_context_get_surface (context) != surface)
+        return;
+
+      if (GDK_GL_CONTEXT_GET_CLASS (context)->clear_current (context))
+        g_private_replace (&thread_current_context, NULL);
+    }
+}
+
 /**
  * gdk_gl_context_get_current:
  *
index e07420f1c11706870727f291d338534892849cb6..fccffdb013dd3d12bb9c924cb943a08310a231c9 100644 (file)
@@ -99,6 +99,8 @@ gboolean                gdk_gl_backend_can_be_used              (GdkGLBackend
                                                                  GError         **error);
 void                    gdk_gl_backend_use                      (GdkGLBackend     backend_type);
 
+void                    gdk_gl_context_clear_current_if_surface (GdkSurface      *surface);
+
 GdkGLContext *          gdk_gl_context_new                      (GdkDisplay      *display,
                                                                  GdkSurface      *surface);
 
index a8c6cab390df50f90177b2c8f82ed70d1bb73ca7..1f176b9b87ba79a92aa2f91e98a8fdba842c5f25 100644 (file)
@@ -1095,6 +1095,7 @@ gdk_surface_set_egl_native_window (GdkSurface *self,
 
   if (priv->egl_surface != NULL)
     {
+      gdk_gl_context_clear_current_if_surface (self);
       eglDestroySurface (gdk_surface_get_display (self), priv->egl_surface);
       priv->egl_surface = NULL;
     }
@@ -1123,6 +1124,7 @@ gdk_surface_ensure_egl_surface (GdkSurface *self,
       priv->egl_surface != NULL &&
       gdk_display_get_egl_config_high_depth (display) != gdk_display_get_egl_config (display))
     {
+      gdk_gl_context_clear_current_if_surface (self);
       eglDestroySurface (gdk_surface_get_display (self), priv->egl_surface);
       priv->egl_surface = NULL;
     }
index 334acf8ff924efd868e924138e40db504614e5bc..d768ccf35ce53a9a6abbc6dfa05cddcd53c33b36 100644 (file)
@@ -71,6 +71,8 @@ gdk_x11_surface_destroy_glx_drawable (GdkX11Surface *self)
   if (self->glx_drawable == None)
     return;
 
+  gdk_gl_context_clear_current_if_surface (GDK_SURFACE (self));
+
   glXDestroyWindow (gdk_x11_display_get_xdisplay (gdk_surface_get_display (GDK_SURFACE (self))),
                     self->glx_drawable);