[gtk/wip.win32.fixes: 13/23] glcontext: Refactor realize function, fix interaction with shared context




commit 6437843f8280069705bc59aa369cc7904acda55b
Author: Pablo Correa Gómez <ablocorrea hotmail com>
Date:   Fri May 6 21:43:30 2022 +0200

    glcontext: Refactor realize function, fix interaction with shared context

 gdk/gdkglcontext.c        | 294 +++++++++++++++++++++++++++-------------------
 gdk/gdkglcontextprivate.h |  21 ++++
 2 files changed, 195 insertions(+), 120 deletions(-)
---
diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c
index 92b08ceafc..1fe7b7b06b 100644
--- a/gdk/gdkglcontext.c
+++ b/gdk/gdkglcontext.c
@@ -256,179 +256,191 @@ gdk_gl_context_get_property (GObject    *object,
     }
 }
 
-#define N_EGL_ATTRS     16
+#define N_EGL_ATTRS 16
+
+#ifdef HAVE_EGL
+static inline EGLenum
+gdk_api_to_egl_api (GdkGLAPI api)
+{
+  switch (api)
+    {
+    case GDK_GL_API_GLES:
+      return EGL_OPENGL_ES_API;
+    case GDK_GL_API_GL:
+    default:
+      return EGL_OPENGL_API;
+    }
+}
+
+static void
+
+gdk_gl_context_setup_context_attributes (EGLint   *context_attribs,
+                                         GdkGLAPI  api,
+                                         int       major,
+                                         int       minor,
+                                         gboolean  legacy,
+                                         int       flags)
+{
+  int i = 0;
+
+  if (api == GDK_GL_API_GL)
+    {
+      /* We want a core profile, unless in legacy mode */
+      context_attribs[i++] = EGL_CONTEXT_OPENGL_PROFILE_MASK;
+      context_attribs[i++] = legacy
+        ? EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT
+        : EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT;
+    }
+
+  /* Before, ~FORWARD_COMPATIBLE was only in one of the code paths.
+   * Does it make sense to have legacy with FORWARD_COMPATIBLE?
+   * If not, then there should likely also be some assert somewhere!
+   *
+   * TODO: Remove this comment before merging!
+   */
+  if (legacy || api == GDK_GL_API_GLES)
+    flags &= ~EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
+
+  context_attribs[i++] = EGL_CONTEXT_MAJOR_VERSION;
+  context_attribs[i++] = major;
+  context_attribs[i++] = EGL_CONTEXT_MINOR_VERSION;
+  context_attribs[i++] = minor;
+  context_attribs[i++] = EGL_CONTEXT_FLAGS_KHR;
+  context_attribs[i++] = flags;
+
+  context_attribs[i++] = EGL_NONE;
+  g_assert (i < N_EGL_ATTRS);
+}
+
 
 static GdkGLAPI
-gdk_gl_context_realize_egl (GdkGLContext  *context,
-                            GError       **error)
+gdk_gl_context_create_egl_context (GdkGLContext *context,
+                                   GdkGLAPI      api,
+                                   gboolean      legacy)
 {
   GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
   GdkDisplay *display = gdk_gl_context_get_display (context);
   EGLDisplay egl_display = gdk_display_get_egl_display (display);
-
-  EGLConfig egl_config;
   GdkGLContext *share = gdk_display_get_gl_context (display);
   GdkGLContextPrivate *share_priv = gdk_gl_context_get_instance_private (share);
+  EGLConfig egl_config;
   EGLContext ctx;
   EGLint context_attribs[N_EGL_ATTRS];
-  int major, minor, flags;
-  gboolean debug_bit, forward_bit, legacy_bit;
-  GdkGLAPI api;
-  int i = 0;
+  gboolean debug_bit, forward_bit;
+  int min_major, min_minor, major = 0, minor = 0, flags = 0;
   G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
 
-  if (share != NULL)
-    gdk_gl_context_get_required_version (share, &major, &minor);
-  else
-    gdk_gl_context_get_required_version (context, &major, &minor);
+  if (!gdk_gl_context_is_api_allowed (context, api, NULL))
+    return 0;
+
+  /* We will use the default version matching the context status
+   * unless the user requested a version which makes sense */
+  gdk_gl_context_get_matching_version (api, legacy,
+                                       display->have_egl_win32_libangle,
+                                       &min_major, &min_minor);
+  gdk_gl_context_get_clipped_version (context,
+                                      min_major, min_minor,
+                                      &major, &minor);
+
+  if (!eglBindAPI (gdk_api_to_egl_api (api)))
+    return 0;
 
   debug_bit = gdk_gl_context_get_debug_enabled (context);
   forward_bit = gdk_gl_context_get_forward_compatible (context);
-  legacy_bit = GDK_DISPLAY_DEBUG_CHECK (display, GL_LEGACY) ||
-    (share != NULL && gdk_gl_context_is_legacy (share));
 
   if (display->have_egl_no_config_context)
     egl_config = NULL;
   else
     egl_config = gdk_display_get_egl_config (display);
 
-  flags = 0;
-
   if (debug_bit)
     flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
   if (forward_bit)
     flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
 
-  if (gdk_gl_context_is_api_allowed (context, GDK_GL_API_GL, NULL) &&
-      eglBindAPI (EGL_OPENGL_API))
-    {
-      /* We want a core profile, unless in legacy mode */
-      context_attribs[i++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
-      context_attribs[i++] = legacy_bit
-        ? EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR
-        : EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
-
-      /* Specify the version */
-      context_attribs[i++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
-      context_attribs[i++] = legacy_bit ? 3 : major;
-      context_attribs[i++] = EGL_CONTEXT_MINOR_VERSION_KHR;
-      context_attribs[i++] = legacy_bit ? 0 : minor;
-      api = GDK_GL_API_GL;
-    }
-  else if (gdk_gl_context_is_api_allowed (context, GDK_GL_API_GLES, NULL) &&
-           eglBindAPI (EGL_OPENGL_ES_API))
-    {
-      context_attribs[i++] = EGL_CONTEXT_CLIENT_VERSION;
-      if (major == 3)
-        context_attribs[i++] = 3;
-      else
-        context_attribs[i++] = 2;
-      api = GDK_GL_API_GLES;
-    }
-  else
-    {
-      g_set_error_literal (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
-                           _("The EGL implementation does not support any allowed APIs"));
-      return 0;
-    }
-
-  /* Specify the flags */
-  context_attribs[i++] = EGL_CONTEXT_FLAGS_KHR;
-  context_attribs[i++] = flags;
-
-  context_attribs[i++] = EGL_NONE;
-  g_assert (i < N_EGL_ATTRS);
+  gdk_gl_context_setup_context_attributes (context_attribs, api, major, minor, legacy, flags);
 
   GDK_DISPLAY_NOTE (display, OPENGL,
                     g_message ("Creating EGL context version %d.%d (debug:%s, forward:%s, legacy:%s, es:%s)",
                                major, minor,
                                debug_bit ? "yes" : "no",
                                forward_bit ? "yes" : "no",
-                               legacy_bit ? "yes" : "no",
+                               legacy ? "yes" : "no",
                                api == GDK_GL_API_GLES ? "yes" : "no"));
 
   ctx = eglCreateContext (egl_display,
                           egl_config,
-                          share != NULL ? share_priv->egl_context
-                          : EGL_NO_CONTEXT,
+                          share ? share_priv->egl_context : EGL_NO_CONTEXT,
                           context_attribs);
 
-  /* If context creation failed without the ES bit, let's try again with it */
-  if (ctx == NULL && gdk_gl_context_is_api_allowed (context, GDK_GL_API_GLES, NULL) && eglBindAPI 
(EGL_OPENGL_ES_API))
-    {
-      i = 0;
-      context_attribs[i++] = EGL_CONTEXT_MAJOR_VERSION;
-      context_attribs[i++] = 2;
-      context_attribs[i++] = EGL_CONTEXT_MINOR_VERSION;
-      context_attribs[i++] = 0;
-      context_attribs[i++] = EGL_CONTEXT_FLAGS_KHR;
-      context_attribs[i++] = flags & ~EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
-      context_attribs[i++] = EGL_NONE;
-      g_assert (i < N_EGL_ATTRS);
-
-      legacy_bit = FALSE;
-      api = GDK_GL_API_GLES;
-
-      GDK_DISPLAY_NOTE (display, OPENGL,
-                        g_message ("eglCreateContext failed, switching to OpenGL ES"));
-      ctx = eglCreateContext (egl_display,
-                              egl_config,
-                              share != NULL ? share_priv->egl_context
-                              : EGL_NO_CONTEXT,
-                              context_attribs);
-    }
-
-  /* If context creation failed without the legacy bit, let's try again with it */
-  if (ctx == NULL && gdk_gl_context_is_api_allowed (context, GDK_GL_API_GL, NULL) && eglBindAPI 
(EGL_OPENGL_API))
-    {
-      i = 0;
-      context_attribs[i++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
-      context_attribs[i++] = EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR;
-      context_attribs[i++] = EGL_CONTEXT_MAJOR_VERSION;
-      context_attribs[i++] = 3;
-      context_attribs[i++] = EGL_CONTEXT_MINOR_VERSION;
-      context_attribs[i++] = 0;
-      context_attribs[i++] = EGL_CONTEXT_FLAGS_KHR;
-      context_attribs[i++] = flags & ~EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
-      context_attribs[i++] = EGL_NONE;
-      g_assert (i < N_EGL_ATTRS);
-
-      legacy_bit = TRUE;
-      api = GDK_GL_API_GL;
-
-      GDK_DISPLAY_NOTE (display, OPENGL,
-                        g_message ("eglCreateContext failed, switching to legacy"));
-      ctx = eglCreateContext (egl_display,
-                              egl_config,
-                              share != NULL ? share_priv->egl_context
-                              : EGL_NO_CONTEXT,
-                              context_attribs);
-    }
-
   if (ctx == NULL)
-    {
-      g_set_error_literal (error, GDK_GL_ERROR,
-                           GDK_GL_ERROR_NOT_AVAILABLE,
-                           _("Unable to create a GL context"));
       return 0;
-    }
 
   GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Created EGL context[%p]", ctx));
 
   priv->egl_context = ctx;
-
-  gdk_gl_context_set_is_legacy (context, legacy_bit);
+  gdk_gl_context_set_is_legacy (context, legacy);
 
   if (epoxy_has_egl_extension (egl_display, "EGL_KHR_swap_buffers_with_damage"))
-    priv->eglSwapBuffersWithDamage = (gpointer)epoxy_eglGetProcAddress ("eglSwapBuffersWithDamageKHR");
+    priv->eglSwapBuffersWithDamage = (gpointer) epoxy_eglGetProcAddress ("eglSwapBuffersWithDamageKHR");
   else if (epoxy_has_egl_extension (egl_display, "EGL_EXT_swap_buffers_with_damage"))
-    priv->eglSwapBuffersWithDamage = (gpointer)epoxy_eglGetProcAddress ("eglSwapBuffersWithDamageEXT");
+    priv->eglSwapBuffersWithDamage = (gpointer) epoxy_eglGetProcAddress ("eglSwapBuffersWithDamageEXT");
 
   gdk_profiler_end_mark (start_time, "realize GdkWaylandGLContext", NULL);
 
   return api;
 }
 
+static GdkGLAPI
+gdk_gl_context_realize_egl (GdkGLContext  *context,
+                            GError       **error)
+{
+  GdkDisplay *display = gdk_gl_context_get_display (context);
+  GdkGLContext *share = gdk_display_get_gl_context (display);
+  GdkGLAPI api, preferred_api;
+  gboolean prefer_legacy;
+
+  if (share && gdk_gl_context_is_api_allowed (context,
+                                              gdk_gl_context_get_api (share),
+                                              NULL))
+    preferred_api = gdk_gl_context_get_api (share);
+  else if (gdk_gl_context_is_api_allowed (context, GDK_GL_API_GL, NULL))
+    preferred_api = GDK_GL_API_GL;
+  else if (gdk_gl_context_is_api_allowed (context, GDK_GL_API_GLES, NULL))
+    preferred_api = GDK_GL_API_GLES;
+  else
+    {
+      g_set_error_literal (error, GDK_GL_ERROR,
+                           GDK_GL_ERROR_NOT_AVAILABLE,
+                           _("No GL API allowed."));
+      return 0;
+    }
+
+  prefer_legacy = (GDK_DISPLAY_DEBUG_CHECK (display, GL_LEGACY) ||
+                   (share != NULL && gdk_gl_context_is_legacy (share)));
+
+  if (preferred_api == GDK_GL_API_GL)
+    {
+      if ((api = gdk_gl_context_create_egl_context (context, GDK_GL_API_GL, prefer_legacy)) ||
+          (api = gdk_gl_context_create_egl_context (context, GDK_GL_API_GLES, FALSE)) ||
+          (api = gdk_gl_context_create_egl_context (context, GDK_GL_API_GL, TRUE)))
+        return api;
+    }
+  else
+    {
+      if ((api = gdk_gl_context_create_egl_context (context, GDK_GL_API_GLES, FALSE)) ||
+          (api = gdk_gl_context_create_egl_context (context, GDK_GL_API_GL, prefer_legacy)) ||
+          (api = gdk_gl_context_create_egl_context (context, GDK_GL_API_GL, TRUE)))
+        return api;
+    }
+
+  g_set_error_literal (error, GDK_GL_ERROR,
+                       GDK_GL_ERROR_NOT_AVAILABLE,
+                       _("Unable to create a GL context"));
+  return 0;
+}
+#endif /* HAVE_EGL */
+
 static GdkGLAPI
 gdk_gl_context_default_realize (GdkGLContext  *context,
                                 GError       **error)
@@ -961,6 +973,48 @@ gdk_gl_context_get_forward_compatible (GdkGLContext *context)
   return priv->forward_compatible;
 }
 
+void
+gdk_gl_context_get_matching_version (GdkGLAPI  api,
+                                     gboolean  legacy,
+                                     gboolean  win32_libangle,
+                                     int      *major,
+                                     int      *minor)
+{
+  int maj, min;
+
+  if (api == GDK_GL_API_GL)
+    {
+      if (legacy)
+        {
+          maj = GDK_GL_MIN_GL_LEGACY_VERSION_MAJOR;
+          min = GDK_GL_MIN_GL_LEGACY_VERSION_MINOR;
+        }
+      else
+        {
+          maj = GDK_GL_MIN_GL_VERSION_MAJOR;
+          min = GDK_GL_MIN_GL_VERSION_MINOR;
+        }
+    }
+  else
+    {
+      if (win32_libangle)
+        {
+          maj = GDK_GL_MIN_GLES_WIN32_ANGLE_VERSION_MAJOR;
+          min = GDK_GL_MIN_GLES_WIN32_ANGLE_VERSION_MINOR;
+        }
+      else
+        {
+          maj = GDK_GL_MIN_GLES_VERSION_MAJOR;
+          min = GDK_GL_MIN_GLES_VERSION_MINOR;
+        }
+    }
+
+  if (major != NULL)
+    *major = maj;
+  if (minor != NULL)
+    *minor = min;
+}
+
 /**
  * gdk_gl_context_set_required_version:
  * @context: a `GdkGLContext`
diff --git a/gdk/gdkglcontextprivate.h b/gdk/gdkglcontextprivate.h
index 0bd9cbad57..bd66172eba 100644
--- a/gdk/gdkglcontextprivate.h
+++ b/gdk/gdkglcontextprivate.h
@@ -33,6 +33,22 @@ G_BEGIN_DECLS
 #define GDK_EGL_MIN_VERSION_MAJOR (1)
 #define GDK_EGL_MIN_VERSION_MINOR (4)
 
+/* Minimum OpenGL versions supported by GTK.
+ * Backends should make sure to never create a context of a previous version.
+ *
+ * The macros refer to OpenGL; OpenGL with OPENGL_COMPATIBILITY_PROFILE_BIT as
+ * OPENGL_PROFILE_MASK; OpenGL ES; and OpenGL ES win32 Angle implementation,
+ * respectively
+ */
+#define GDK_GL_MIN_GL_VERSION_MAJOR (3)
+#define GDK_GL_MIN_GL_VERSION_MINOR (2)
+#define GDK_GL_MIN_GL_LEGACY_VERSION_MAJOR (3)
+#define GDK_GL_MIN_GL_LEGACY_VERSION_MINOR (0)
+#define GDK_GL_MIN_GLES_VERSION_MAJOR (2)
+#define GDK_GL_MIN_GLES_VERSION_MINOR (0)
+#define GDK_GL_MIN_GLES_WIN32_ANGLE_VERSION_MAJOR (3)
+#define GDK_GL_MIN_GLES_WIN32_ANGLE_VERSION_MINOR (0)
+
 typedef enum {
   GDK_GL_NONE = 0,
   GDK_GL_EGL,
@@ -122,6 +138,11 @@ void                    gdk_gl_context_get_clipped_version      (GdkGLContext
                                                                  int              min_minor,
                                                                  int             *major,
                                                                  int             *minor);
+void                    gdk_gl_context_get_matching_version     (GdkGLAPI         api,
+                                                                 gboolean         legacy,
+                                                                 gboolean         win32_libangle,
+                                                                 int             *major,
+                                                                 int             *minor);
 
 gboolean                gdk_gl_context_has_unpack_subimage      (GdkGLContext    *context);
 void                    gdk_gl_context_push_debug_group         (GdkGLContext    *context,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]