glcontext: Refactor realize function, fix interaction with shared context

This commit is contained in:
Pablo Correa Gómez 2022-05-06 21:43:30 +02:00
parent f4f0daa113
commit 549a2b4c86
No known key found for this signature in database
GPG Key ID: 7A342565FF635F79
2 changed files with 166 additions and 112 deletions

View File

@ -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 static GdkGLAPI
gdk_gl_context_realize_egl (GdkGLContext *context, gdk_gl_context_create_egl_context (GdkGLContext *context,
GError **error) GdkGLAPI api,
gboolean legacy)
{ {
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context); GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
GdkDisplay *display = gdk_gl_context_get_display (context); GdkDisplay *display = gdk_gl_context_get_display (context);
EGLDisplay egl_display = gdk_display_get_egl_display (display); EGLDisplay egl_display = gdk_display_get_egl_display (display);
EGLConfig egl_config;
GdkGLContext *share = gdk_display_get_gl_context (display); GdkGLContext *share = gdk_display_get_gl_context (display);
GdkGLContextPrivate *share_priv = gdk_gl_context_get_instance_private (share); GdkGLContextPrivate *share_priv = gdk_gl_context_get_instance_private (share);
EGLConfig egl_config;
EGLContext ctx; EGLContext ctx;
EGLint context_attribs[N_EGL_ATTRS]; EGLint context_attribs[N_EGL_ATTRS], i = 0, flags = 0;
int major, minor, flags; gboolean debug_bit, forward_bit;
gboolean debug_bit, forward_bit, legacy_bit; int min_major, min_minor, major = 0, minor = 0;
GdkGLAPI api;
int i = 0;
G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME; G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
if (share != NULL) if (!gdk_gl_context_is_api_allowed (context, api, NULL))
gdk_gl_context_get_required_version (share, &major, &minor); return 0;
else
gdk_gl_context_get_required_version (context, &major, &minor); /* 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); debug_bit = gdk_gl_context_get_debug_enabled (context);
forward_bit = gdk_gl_context_get_forward_compatible (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) if (display->have_egl_no_config_context)
egl_config = NULL; egl_config = NULL;
else else
egl_config = gdk_display_get_egl_config (display); egl_config = gdk_display_get_egl_config (display);
flags = 0;
if (debug_bit) if (debug_bit)
flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
if (forward_bit) if (forward_bit)
flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
if (gdk_gl_context_is_api_allowed (context, GDK_GL_API_GL, NULL) && if (api == GDK_GL_API_GL)
eglBindAPI (EGL_OPENGL_API))
{ {
/* We want a core profile, unless in legacy mode */ /* We want a core profile, unless in legacy mode */
context_attribs[i++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR; context_attribs[i++] = EGL_CONTEXT_OPENGL_PROFILE_MASK;
context_attribs[i++] = legacy_bit context_attribs[i++] = legacy
? EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR ? EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT
: EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; : EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT;
/* 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 */ 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++] = EGL_CONTEXT_FLAGS_KHR;
context_attribs[i++] = flags; context_attribs[i++] = flags;
@ -343,91 +343,82 @@ gdk_gl_context_realize_egl (GdkGLContext *context,
major, minor, major, minor,
debug_bit ? "yes" : "no", debug_bit ? "yes" : "no",
forward_bit ? "yes" : "no", forward_bit ? "yes" : "no",
legacy_bit ? "yes" : "no", legacy ? "yes" : "no",
api == GDK_GL_API_GLES ? "yes" : "no")); api == GDK_GL_API_GLES ? "yes" : "no"));
ctx = eglCreateContext (egl_display, ctx = eglCreateContext (egl_display,
egl_config, egl_config,
share != NULL ? share_priv->egl_context share ? share_priv->egl_context : EGL_NO_CONTEXT,
: EGL_NO_CONTEXT,
context_attribs); 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) if (ctx == NULL)
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("Unable to create a GL context"));
return 0; return 0;
}
GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Created EGL context[%p]", ctx)); GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Created EGL context[%p]", ctx));
priv->egl_context = ctx; priv->egl_context = ctx;
gdk_gl_context_set_is_legacy (context, legacy);
gdk_gl_context_set_is_legacy (context, legacy_bit);
if (epoxy_has_egl_extension (egl_display, "EGL_KHR_swap_buffers_with_damage")) 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")) 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); gdk_profiler_end_mark (start_time, "realize GdkWaylandGLContext", NULL);
return api; 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 static GdkGLAPI
gdk_gl_context_default_realize (GdkGLContext *context, gdk_gl_context_default_realize (GdkGLContext *context,
GError **error) GError **error)
@ -966,6 +957,48 @@ gdk_gl_context_get_forward_compatible (GdkGLContext *context)
return priv->forward_compatible; 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: * gdk_gl_context_set_required_version:
* @context: a `GdkGLContext` * @context: a `GdkGLContext`

View File

@ -33,6 +33,22 @@ G_BEGIN_DECLS
#define GDK_EGL_MIN_VERSION_MAJOR (1) #define GDK_EGL_MIN_VERSION_MAJOR (1)
#define GDK_EGL_MIN_VERSION_MINOR (4) #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 { typedef enum {
GDK_GL_NONE = 0, GDK_GL_NONE = 0,
GDK_GL_EGL, GDK_GL_EGL,
@ -122,6 +138,11 @@ void gdk_gl_context_get_clipped_version (GdkGLContext
int min_minor, int min_minor,
int *major, int *major,
int *minor); 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); gboolean gdk_gl_context_has_unpack_subimage (GdkGLContext *context);
void gdk_gl_context_push_debug_group (GdkGLContext *context, void gdk_gl_context_push_debug_group (GdkGLContext *context,