summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte.benjamin@googlemail.com>2022-06-04 20:26:58 +0000
committerBenjamin Otte <otte.benjamin@googlemail.com>2022-06-04 20:26:58 +0000
commit45422f7b613f93d670b82dbf418f1e110d01e17c (patch)
tree831cbd3ed3476ba4d0f63515fde43d8b8a2d9a8b
parent31da5f7e2a1ff51a05a8d87c704a0cef541edc1f (diff)
parentc4feca13118fa4a1e2d263c76458fa60de9a608e (diff)
downloadgtk+-45422f7b613f93d670b82dbf418f1e110d01e17c.tar.gz
Merge branch 'gl-api-es-fix' into 'main'
glcontext: Respect ES API when getting gl version from shared context Closes #4763 See merge request GNOME/gtk!4687
-rw-r--r--gdk/gdkglcontext.c452
-rw-r--r--gdk/gdkglcontextprivate.h26
-rw-r--r--gdk/macos/gdkmacosglcontext.c5
-rw-r--r--gdk/win32/gdkglcontext-win32-wgl.c16
-rw-r--r--gdk/x11/gdkglcontext-glx.c309
5 files changed, 405 insertions, 403 deletions
diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c
index e58c0e57dc..3f22c00065 100644
--- a/gdk/gdkglcontext.c
+++ b/gdk/gdkglcontext.c
@@ -256,181 +256,179 @@ 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 GdkGLAPI
-gdk_gl_context_real_realize (GdkGLContext *context,
- GError **error)
+gdk_gl_context_create_egl_context (GdkGLContext *context,
+ GdkGLAPI api,
+ gboolean legacy)
{
-#ifdef HAVE_EGL
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);
+ 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], i = 0, flags = 0;
+ gboolean debug_bit, forward_bit;
+ int min_major, min_minor, major = 0, minor = 0;
+ G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
+
+ 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);
+
+ if (display->have_egl_no_config_context)
+ egl_config = NULL;
+ else
+ egl_config = gdk_display_get_egl_config (display);
+
+ if (debug_bit)
+ flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
+ if (forward_bit)
+ flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
- if (egl_display)
+ if (api == GDK_GL_API_GL)
{
- EGLConfig egl_config;
- GdkGLContext *share = gdk_display_get_gl_context (display);
- GdkGLContextPrivate *share_priv = gdk_gl_context_get_instance_private (share);
- EGLContext ctx;
- EGLint context_attribs[N_EGL_ATTRS];
- int major, minor, flags;
- gboolean debug_bit, forward_bit, legacy_bit;
- GdkGLAPI api;
- int i = 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);
+ /* 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;
+ }
- 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 (legacy || api == GDK_GL_API_GLES)
+ flags &= ~EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
- if (display->have_egl_no_config_context)
- egl_config = NULL;
- else
- egl_config = gdk_display_get_egl_config (display);
+ 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;
- flags = 0;
+ context_attribs[i++] = EGL_NONE;
+ g_assert (i < N_EGL_ATTRS);
- if (debug_bit)
- flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
- if (forward_bit)
- flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
+ 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 ? "yes" : "no",
+ api == GDK_GL_API_GLES ? "yes" : "no"));
- 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;
- }
+ ctx = eglCreateContext (egl_display,
+ egl_config,
+ share ? share_priv->egl_context : EGL_NO_CONTEXT,
+ context_attribs);
- /* 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_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",
- api == GDK_GL_API_GLES ? "yes" : "no"));
-
- ctx = eglCreateContext (egl_display,
- egl_config,
- share != NULL ? 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 (ctx == NULL)
+ return 0;
- /* 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);
- }
+ GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Created EGL context[%p]", ctx));
- if (ctx == NULL)
- {
- g_set_error_literal (error, GDK_GL_ERROR,
- GDK_GL_ERROR_NOT_AVAILABLE,
- _("Unable to create a GL context"));
- return 0;
- }
+ priv->egl_context = ctx;
+ gdk_gl_context_set_is_legacy (context, legacy);
- GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Created EGL context[%p]", ctx));
+ if (epoxy_has_egl_extension (egl_display, "EGL_KHR_swap_buffers_with_damage"))
+ 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->egl_context = ctx;
+ gdk_profiler_end_mark (start_time, "realize GdkWaylandGLContext", NULL);
- gdk_gl_context_set_is_legacy (context, legacy_bit);
+ return api;
+}
- if (epoxy_has_egl_extension (egl_display, "EGL_KHR_swap_buffers_with_damage"))
- 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");
+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;
+ }
- gdk_profiler_end_mark (start_time, "realize GdkWaylandGLContext", NULL);
+ prefer_legacy = (GDK_DISPLAY_DEBUG_CHECK (display, GL_LEGACY) ||
+ (share != NULL && gdk_gl_context_is_legacy (share)));
- return api;
+ 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)
+{
+#ifdef HAVE_EGL
+ GdkDisplay *display = gdk_gl_context_get_display (context);
+
+ if (gdk_display_get_egl_display (display))
+ return gdk_gl_context_realize_egl (context, error);
#endif
g_set_error_literal (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
@@ -667,7 +665,7 @@ gdk_gl_context_class_init (GdkGLContextClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
- klass->realize = gdk_gl_context_real_realize;
+ klass->realize = gdk_gl_context_default_realize;
klass->get_damage = gdk_gl_context_real_get_damage;
klass->is_shared = gdk_gl_context_real_is_shared;
klass->make_current = gdk_gl_context_real_make_current;
@@ -954,6 +952,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`
@@ -964,7 +1004,10 @@ gdk_gl_context_get_forward_compatible (GdkGLContext *context)
*
* Setting @major and @minor to zero will use the default values.
*
- * The `GdkGLContext` must not be realized or made current prior to calling
+ * Setting @major and @minor lower than the minimum versions required
+ * by GTK will result in the context choosing the minimum version.
+ *
+ * The @context must not be realized or made current prior to calling
* this function.
*/
void
@@ -973,44 +1016,12 @@ gdk_gl_context_set_required_version (GdkGLContext *context,
int minor)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
- gboolean force_gles = FALSE;
- int version, min_ver;
-#ifdef G_ENABLE_DEBUG
- GdkDisplay *display;
-#endif
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
g_return_if_fail (!gdk_gl_context_is_realized (context));
- /* this will take care of the default */
- if (major == 0 && minor == 0)
- {
- priv->major = 0;
- priv->minor = 0;
- return;
- }
-
- version = (major * 100) + minor;
-
-#ifdef G_ENABLE_DEBUG
- display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
- force_gles = GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES);
-#endif
- /* Enforce a minimum context version number of 3.2 for desktop GL,
- * and 2.0 for GLES
- */
- if (gdk_gl_context_get_use_es (context) || force_gles)
- min_ver = 200;
- else
- min_ver = 302;
-
- if (version < min_ver)
- {
- g_warning ("gdk_gl_context_set_required_version - GL context versions less than 3.2 are not supported.");
- version = min_ver;
- }
- priv->major = version / 100;
- priv->minor = version % 100;
+ priv->major = major;
+ priv->minor = minor;
}
gboolean
@@ -1049,7 +1060,10 @@ gdk_gl_context_check_version (GdkGLContext *self,
* @major: (out) (nullable): return location for the major version to request
* @minor: (out) (nullable): return location for the minor version to request
*
- * Retrieves required OpenGL version.
+ * Retrieves required OpenGL version set as a requirement for the @context
+ * realization. It will not change even if a greater OpenGL version is supported
+ * and used after the @context is realized. See
+ * [method@Gdk.GLContext.get_version] for the real version in use.
*
* See [method@Gdk.GLContext.set_required_version].
*/
@@ -1059,48 +1073,33 @@ gdk_gl_context_get_required_version (GdkGLContext *context,
int *minor)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
- gboolean force_gles = FALSE;
- GdkDisplay *display;
- int default_major, default_minor;
- int maj, min;
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
- display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
+ if (major != NULL)
+ *major = priv->major;
+ if (minor != NULL)
+ *minor = priv->minor;
+}
-#ifdef G_ENABLE_DEBUG
- force_gles = GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES);
-#endif
+void
+gdk_gl_context_get_clipped_version (GdkGLContext *context,
+ int min_major,
+ int min_minor,
+ int *major,
+ int *minor)
+{
+ GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
+ int maj = min_major, min = min_minor;
- /* libANGLE on Windows at least requires GLES 3.0+ */
- if (display->have_egl_win32_libangle)
- force_gles = TRUE;
+ g_return_if_fail (GDK_IS_GL_CONTEXT (context));
- /* Default fallback values for uninitialised contexts; we
- * enforce a context version number of 3.2 for desktop GL,
- * and 2.0 for GLES
- */
- if (gdk_gl_context_get_use_es (context) || force_gles)
- {
- default_major = display->have_egl_win32_libangle ? 3 : 2;
- default_minor = 0;
- }
- else
+ if (priv->major > maj || (priv->major == maj && priv->minor > min))
{
- default_major = 3;
- default_minor = 2;
+ maj = priv->major;
+ min = priv->minor;
}
- if (priv->major > 0)
- maj = priv->major;
- else
- maj = default_major;
-
- if (priv->minor > 0)
- min = priv->minor;
- else
- min = default_minor;
-
if (major != NULL)
*major = maj;
if (minor != NULL)
@@ -1336,7 +1335,9 @@ gdk_gl_context_set_use_es (GdkGLContext *context,
*
* Checks whether the @context is using an OpenGL or OpenGL ES profile.
*
- * Returns: %TRUE if the `GdkGLContext` is using an OpenGL ES profile
+ * Returns: %TRUE if the `GdkGLContext` is using an OpenGL ES profile;
+ * %FALSE if other profile is in use of if the @context has not yet
+ * been realized.
*/
gboolean
gdk_gl_context_get_use_es (GdkGLContext *context)
@@ -1667,6 +1668,10 @@ gdk_gl_context_get_shared_context (GdkGLContext *context)
* Retrieves the OpenGL version of the @context.
*
* The @context must be realized prior to calling this function.
+ *
+ * If the @context has never been made current, the version cannot
+ * be known and it will return 0 for both @major and @minor.
+ *
*/
void
gdk_gl_context_get_version (GdkGLContext *context,
@@ -1845,4 +1850,3 @@ gdk_gl_backend_use (GdkGLBackend backend_type)
g_assert (the_gl_backend_type == backend_type);
}
-
diff --git a/gdk/gdkglcontextprivate.h b/gdk/gdkglcontextprivate.h
index cd58c30b4e..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,
@@ -117,6 +133,16 @@ gboolean gdk_gl_context_check_version (GdkGLContext
int required_gl_minor,
int required_gles_major,
int required_gles_minor);
+void gdk_gl_context_get_clipped_version (GdkGLContext *context,
+ int min_major,
+ 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,
diff --git a/gdk/macos/gdkmacosglcontext.c b/gdk/macos/gdkmacosglcontext.c
index ff7ae975c8..069d138b83 100644
--- a/gdk/macos/gdkmacosglcontext.c
+++ b/gdk/macos/gdkmacosglcontext.c
@@ -378,7 +378,10 @@ gdk_macos_gl_context_real_realize (GdkGLContext *context,
existing = CGLGetCurrentContext ();
- gdk_gl_context_get_required_version (context, &major, &minor);
+ gdk_gl_context_get_clipped_version (context,
+ GDK_GL_MIN_GL_VERSION_MAJOR,
+ GDK_GL_MIN_GL_VERSION_MINOR,
+ &major, &minor);
display = gdk_gl_context_get_display (context);
shared = gdk_display_get_gl_context (display);
diff --git a/gdk/win32/gdkglcontext-win32-wgl.c b/gdk/win32/gdkglcontext-win32-wgl.c
index 231f2a6a01..d7ff4367f2 100644
--- a/gdk/win32/gdkglcontext-win32-wgl.c
+++ b/gdk/win32/gdkglcontext-win32-wgl.c
@@ -548,17 +548,12 @@ gdk_win32_gl_context_wgl_realize (GdkGLContext *context,
* wglCreateContextAttribsARB() may only give us the GL context version
* that we ask for here, and nothing more. So, improve things here by
* asking for the GL version that is reported to us via epoxy_gl_version(),
- * rather than the default GL core 3.2 context. Save this up in our
- * GdkGLContext so that subsequent contexts that are shared with this
- * context are created likewise too.
+ * rather than the default GL core 3.2 context.
*/
- if (share != NULL)
- gdk_gl_context_get_required_version (share, &major, &minor);
- else
- {
- major = display_win32->gl_version / 10;
- minor = display_win32->gl_version % 10;
- }
+ gdk_gl_context_get_clipped_version (context,
+ display_win32->gl_version / 10,
+ display_win32->gl_version % 10,
+ &major, &minor);
if (surface != NULL)
hdc = GDK_WIN32_SURFACE (surface)->hdc;
@@ -626,7 +621,6 @@ gdk_win32_gl_context_wgl_realize (GdkGLContext *context,
/* Ensure that any other context is created with a legacy bit set */
gdk_gl_context_set_is_legacy (context, legacy_bit);
- gdk_gl_context_set_required_version (context, major, minor);
return GDK_GL_API_GL;
}
diff --git a/gdk/x11/gdkglcontext-glx.c b/gdk/x11/gdkglcontext-glx.c
index d768ccf35c..d9e60bd747 100644
--- a/gdk/x11/gdkglcontext-glx.c
+++ b/gdk/x11/gdkglcontext-glx.c
@@ -213,7 +213,7 @@ gdk_x11_gl_context_glx_clear_current (GdkGLContext *context)
static gboolean
gdk_x11_gl_context_glx_make_current (GdkGLContext *context,
gboolean surfaceless)
-
+
{
GdkX11GLContextGLX *self = GDK_X11_GL_CONTEXT_GLX (context);
GdkDisplay *display = gdk_gl_context_get_display (context);
@@ -302,68 +302,6 @@ gdk_x11_gl_context_glx_get_damage (GdkGLContext *context)
return GDK_GL_CONTEXT_CLASS (gdk_x11_gl_context_glx_parent_class)->get_damage (context);
}
-static GLXContext
-create_gl3_context (GdkDisplay *display,
- GLXFBConfig config,
- GdkGLContext *share,
- int profile,
- int flags,
- int major,
- int minor)
-{
- int attrib_list[] = {
- GLX_CONTEXT_PROFILE_MASK_ARB, profile,
- GLX_CONTEXT_MAJOR_VERSION_ARB, major,
- GLX_CONTEXT_MINOR_VERSION_ARB, minor,
- GLX_CONTEXT_FLAGS_ARB, flags,
- None,
- };
- GLXContext res;
-
- GdkX11GLContextGLX *share_glx = NULL;
-
- if (share != NULL)
- share_glx = GDK_X11_GL_CONTEXT_GLX (share);
-
- gdk_x11_display_error_trap_push (display);
-
- res = glXCreateContextAttribsARB (gdk_x11_display_get_xdisplay (display),
- config,
- share_glx != NULL ? share_glx->glx_context : NULL,
- True,
- attrib_list);
-
- if (gdk_x11_display_error_trap_pop (display))
- return NULL;
-
- return res;
-}
-
-static GLXContext
-create_legacy_context (GdkDisplay *display,
- GLXFBConfig config,
- GdkGLContext *share)
-{
- GdkX11GLContextGLX *share_glx = NULL;
- GLXContext res;
-
- if (share != NULL)
- share_glx = GDK_X11_GL_CONTEXT_GLX (share);
-
- gdk_x11_display_error_trap_push (display);
-
- res = glXCreateNewContext (gdk_x11_display_get_xdisplay (display),
- config,
- GLX_RGBA_TYPE,
- share_glx != NULL ? share_glx->glx_context : NULL,
- TRUE);
-
- if (gdk_x11_display_error_trap_pop (display))
- return NULL;
-
- return res;
-}
-
#ifdef HAVE_XDAMAGE
static void
bind_context_for_frame_fence (GdkX11GLContextGLX *self)
@@ -507,134 +445,111 @@ on_surface_state_changed (GdkGLContext *context)
*/
finish_frame (context);
}
-#endif
+#endif /* HAVE_XDAMAGE */
+
+#define N_GLX_ATTRS 16
static GdkGLAPI
-gdk_x11_gl_context_glx_realize (GdkGLContext *context,
- GError **error)
+gdk_x11_context_create_glx_context (GdkGLContext *context,
+ GdkGLAPI api,
+ gboolean legacy)
{
- GdkX11Display *display_x11;
- GdkDisplay *display;
- GdkX11GLContextGLX *context_glx;
- Display *dpy;
- GdkSurface *surface;
- GdkGLContext *share;
- gboolean debug_bit, compat_bit, legacy_bit;
- int major, minor, flags;
- GdkGLAPI api = 0;
+ GdkX11GLContextGLX *context_glx = GDK_X11_GL_CONTEXT_GLX (context);;
+ GdkDisplay *display = gdk_gl_context_get_display (context);
+ GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
+ Display *dpy = gdk_x11_display_get_xdisplay (display);
+ GdkGLContext *share = gdk_display_get_gl_context (display);
+ GdkX11GLContextGLX *share_glx = NULL;
+ GdkSurface *surface = gdk_gl_context_get_surface (context);
+ GLXContext ctx;
+ int context_attribs[N_GLX_ATTRS], i = 0, flags = 0;
+ int min_major, min_minor, major, minor;
+ gboolean debug_bit, compat_bit;
- display = gdk_gl_context_get_display (context);
- dpy = gdk_x11_display_get_xdisplay (display);
- context_glx = GDK_X11_GL_CONTEXT_GLX (context);
- display_x11 = GDK_X11_DISPLAY (display);
- share = gdk_display_get_gl_context (display);
- surface = gdk_gl_context_get_surface (context);
+ if (!gdk_gl_context_is_api_allowed (context, api, NULL))
+ return 0;
- gdk_gl_context_get_required_version (context, &major, &minor);
- debug_bit = gdk_gl_context_get_debug_enabled (context);
- compat_bit = gdk_gl_context_get_forward_compatible (context);
+ if (api == GDK_GL_API_GLES && legacy)
+ return 0;
- /* If there is no glXCreateContextAttribsARB() then we default to legacy */
- legacy_bit = !display_x11->has_glx_create_context || GDK_DISPLAY_DEBUG_CHECK (display, GL_LEGACY);
+ /* 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, 0,
+ &min_major, &min_minor);
+ gdk_gl_context_get_clipped_version (context, min_major, min_minor,
+ &major, &minor);
- /* We cannot share legacy contexts with core profile ones, so the
- * shared context is the one that decides if we're going to create
- * a legacy context or not.
- */
- if (share != NULL && gdk_gl_context_is_legacy (share))
- legacy_bit = TRUE;
+ debug_bit = gdk_gl_context_get_debug_enabled (context);
+ compat_bit = gdk_gl_context_get_forward_compatible (context);
- flags = 0;
if (debug_bit)
flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
if (compat_bit)
flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
- GDK_DISPLAY_NOTE (display, OPENGL,
- g_message ("Creating GLX context (GL version:%d.%d, debug:%s, forward:%s, legacy:%s, GL:%s, GLES:%s)",
- major, minor,
- debug_bit ? "yes" : "no",
- compat_bit ? "yes" : "no",
- legacy_bit ? "yes" : "no",
- gdk_gl_context_is_api_allowed (context, GDK_GL_API_GL, NULL) ? "yes" : "no",
- gdk_gl_context_is_api_allowed (context, GDK_GL_API_GLES, NULL) ? "yes" : "no"));
-
- /* If we have access to GLX_ARB_create_context_profile then we can ask for
- * a compatibility profile; if we don't, then we have to fall back to the
- * old GLX 1.3 API.
- */
- if (legacy_bit && !GDK_X11_DISPLAY (display)->has_glx_create_context)
- {
- GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Creating legacy GL context on request"));
- /* do it below */
- }
- else
- {
- if (gdk_gl_context_is_api_allowed (context, GDK_GL_API_GL, NULL))
- {
- int profile = legacy_bit ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
- : GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
+ context_attribs[i++] = GLX_CONTEXT_PROFILE_MASK_ARB;
+ if (api == GDK_GL_API_GL)
+ if (legacy)
+ context_attribs[i++] = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
+ else
+ context_attribs[i++] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
+ else if (api == GDK_GL_API_GLES)
+ context_attribs[i++] = GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
+
+ context_attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
+ context_attribs[i++] = major;
+ context_attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB;
+ context_attribs[i++] = minor;
+ context_attribs[i++] = GLX_CONTEXT_FLAGS_ARB;
+ context_attribs[i++] = flags;
+
+ context_attribs[i++] = None;
+ g_assert (i < N_GLX_ATTRS);
- /* We need to tweak the version, otherwise we may end up requesting
- * a compatibility context with a minimum version of 3.2, which is
- * an error
- */
- if (legacy_bit)
- {
- major = 3;
- minor = 0;
- }
+ GDK_DISPLAY_NOTE (display, OPENGL,
+ g_message ("Creating GLX context version %d.%d (debug:%s, forward:%s, legacy:%s, es:%s)",
+ major, minor,
+ debug_bit ? "yes" : "no",
+ compat_bit ? "yes" : "no",
+ legacy ? "yes" : "no",
+ api == GDK_GL_API_GLES ? "yes" : "no"));
- GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Creating GL3 context"));
- context_glx->glx_context = create_gl3_context (display,
- display_x11->glx_config,
- share,
- profile,
- flags, major, minor);
- api = GDK_GL_API_GL;
- }
+ if (share != NULL)
+ share_glx = GDK_X11_GL_CONTEXT_GLX (share);
- if (context_glx->glx_context == NULL && !legacy_bit &&
- gdk_gl_context_is_api_allowed (context, GDK_GL_API_GLES, NULL))
- {
- GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Creating GL3 GLES context"));
- context_glx->glx_context = create_gl3_context (display,
- display_x11->glx_config,
- share,
- GLX_CONTEXT_ES2_PROFILE_BIT_EXT,
- flags, major, minor);
- api = GDK_GL_API_GLES;
- }
- }
+ gdk_x11_display_error_trap_push (display);
- /* Fall back to legacy in case the GL3 context creation failed */
- if (context_glx->glx_context == NULL &&
- gdk_gl_context_is_api_allowed (context, GDK_GL_API_GL, NULL))
- {
- GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Creating fallback legacy context"));
- context_glx->glx_context = create_legacy_context (display, display_x11->glx_config, share);
- legacy_bit = TRUE;
- api = GDK_GL_API_GL;
- }
+ /* If we don't have access to GLX_ARB_create_context_profile, then
+ * we have to fall back to the old GLX 1.3 API.
+ */
+ if (legacy && !display_x11->has_glx_create_context)
+ ctx = glXCreateNewContext (gdk_x11_display_get_xdisplay (display),
+ display_x11->glx_config,
+ GLX_RGBA_TYPE,
+ share_glx != NULL ? share_glx->glx_context : NULL,
+ TRUE);
- if (context_glx->glx_context == NULL)
- {
- g_set_error_literal (error, GDK_GL_ERROR,
- GDK_GL_ERROR_NOT_AVAILABLE,
- _("Unable to create a GL context"));
- return 0;
- }
+ else
+ ctx = glXCreateContextAttribsARB (gdk_x11_display_get_xdisplay (display),
+ display_x11->glx_config,
+ share_glx != NULL ? share_glx->glx_context : NULL,
+ True,
+ context_attribs);
- /* Ensure that any other context is created with a legacy bit set */
- gdk_gl_context_set_is_legacy (context, legacy_bit);
+ if (gdk_x11_display_error_trap_pop (display) || ctx == NULL)
+ return 0;
GDK_DISPLAY_NOTE (display, OPENGL,
g_message ("Realized GLX context[%p], %s, version: %d.%d",
context_glx->glx_context,
glXIsDirect (dpy, context_glx->glx_context) ? "direct" : "indirect",
display_x11->glx_version / 10,
+
display_x11->glx_version % 10));
+ context_glx->glx_context = ctx;
+ gdk_gl_context_set_is_legacy (context, legacy);
+
#ifdef HAVE_XDAMAGE
if (display_x11->have_damage &&
display_x11->has_async_glx_swap_buffers)
@@ -663,10 +578,70 @@ gdk_x11_gl_context_glx_realize (GdkGLContext *context,
}
}
#endif
-
return api;
}
+static GdkGLAPI
+gdk_x11_gl_context_glx_realize (GdkGLContext *context,
+ GError **error)
+{
+ GdkDisplay *display = gdk_gl_context_get_display (context);
+ GdkGLContext *share = gdk_display_get_gl_context (display);
+ gboolean legacy;
+ GdkGLAPI api, preferred_api;
+
+ 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;
+ }
+
+ /* If there is no glXCreateContextAttribsARB() then we default to legacy */
+ legacy = !GDK_X11_DISPLAY (display)->has_glx_create_context;
+
+ if (GDK_DISPLAY_DEBUG_CHECK (display, GL_LEGACY))
+ legacy = TRUE;
+
+ /* We cannot share legacy contexts with core profile ones, so the
+ * shared context is the one that decides if we're going to create
+ * a legacy context or not.
+ */
+ if (share != NULL && gdk_gl_context_is_legacy (share))
+ legacy = TRUE;
+
+ if (preferred_api == GDK_GL_API_GL)
+ {
+ if ((api = gdk_x11_context_create_glx_context (context, GDK_GL_API_GL, legacy)) ||
+ (api = gdk_x11_context_create_glx_context (context, GDK_GL_API_GLES, legacy)) ||
+ (api = gdk_x11_context_create_glx_context (context, GDK_GL_API_GL, TRUE)))
+ return api;
+ }
+ else
+ {
+ if ((api = gdk_x11_context_create_glx_context (context, GDK_GL_API_GLES, FALSE)) ||
+ (api = gdk_x11_context_create_glx_context (context, GDK_GL_API_GL, legacy)) ||
+ (api = gdk_x11_context_create_glx_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;
+}
+
+#undef N_GLX_ATTRS
+
static void
gdk_x11_gl_context_glx_dispose (GObject *gobject)
{
@@ -820,7 +795,7 @@ gdk_x11_display_create_glx_config (GdkX11Display *self,
XFree (visinfo);
continue;
}
-
+
if (!visual_is_rgba (visinfo))
{
if (best_features < NO_ALPHA_VISUAL)
@@ -894,7 +869,7 @@ gdk_x11_display_get_glx_version (GdkDisplay *display,
/*< private >
* gdk_x11_display_init_glx:
- * @display_x11: an X11 display that has not been inited yet.
+ * @display_x11: an X11 display that has not been inited yet.
* @out_visual: set to the Visual to be used with the returned config
* @out_depth: set to the depth to be used with the returned config
* @error: Return location for error