diff options
author | Pablo Correa Gómez <ablocorrea@hotmail.com> | 2022-05-06 21:43:30 +0200 |
---|---|---|
committer | Pablo Correa Gómez <ablocorrea@hotmail.com> | 2022-06-04 20:48:40 +0200 |
commit | 549a2b4c866e988b791244ca5d67d16bdbf5e006 (patch) | |
tree | 7114b3d919485c50c32c45ef0c51a7b7b6bcda2f | |
parent | f4f0daa113ecd8bdec4e1f09cd00407c648650c3 (diff) | |
download | gtk+-549a2b4c866e988b791244ca5d67d16bdbf5e006.tar.gz |
glcontext: Refactor realize function, fix interaction with shared context
-rw-r--r-- | gdk/gdkglcontext.c | 257 | ||||
-rw-r--r-- | gdk/gdkglcontextprivate.h | 21 |
2 files changed, 166 insertions, 112 deletions
diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c index 484dee3200..41f261f2d8 100644 --- a/gdk/gdkglcontext.c +++ b/gdk/gdkglcontext.c @@ -255,83 +255,83 @@ 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_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; + 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 (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)) + if (api == GDK_GL_API_GL) { /* 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; + context_attribs[i++] = EGL_CONTEXT_OPENGL_PROFILE_MASK; + context_attribs[i++] = legacy + ? EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT + : EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT; } - /* Specify the flags */ + 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; @@ -343,85 +343,26 @@ gdk_gl_context_realize_egl (GdkGLContext *context, 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); @@ -429,6 +370,56 @@ gdk_gl_context_realize_egl (GdkGLContext *context, } 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) { @@ -966,6 +957,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 b97d07f34f..7537b71225 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, |