diff options
author | Benjamin Otte <otte.benjamin@googlemail.com> | 2022-06-04 20:26:58 +0000 |
---|---|---|
committer | Benjamin Otte <otte.benjamin@googlemail.com> | 2022-06-04 20:26:58 +0000 |
commit | 45422f7b613f93d670b82dbf418f1e110d01e17c (patch) | |
tree | 831cbd3ed3476ba4d0f63515fde43d8b8a2d9a8b | |
parent | 31da5f7e2a1ff51a05a8d87c704a0cef541edc1f (diff) | |
parent | c4feca13118fa4a1e2d263c76458fa60de9a608e (diff) | |
download | gtk+-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.c | 452 | ||||
-rw-r--r-- | gdk/gdkglcontextprivate.h | 26 | ||||
-rw-r--r-- | gdk/macos/gdkmacosglcontext.c | 5 | ||||
-rw-r--r-- | gdk/win32/gdkglcontext-win32-wgl.c | 16 | ||||
-rw-r--r-- | gdk/x11/gdkglcontext-glx.c | 309 |
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 |