Merge branch 'wip/otte/glcontext' into 'master'

glcontext: Make GLES vs GL configuration clearer

Closes #4221

See merge request GNOME/gtk!4044
This commit is contained in:
Benjamin Otte
2021-10-08 15:57:08 +00:00
8 changed files with 324 additions and 118 deletions

View File

@@ -121,7 +121,7 @@ static const GdkDebugKey gdk_debug_keys[] = {
{ "gl-software", GDK_DEBUG_GL_SOFTWARE, "Force OpenGL software rendering" },
{ "gl-texture-rect", GDK_DEBUG_GL_TEXTURE_RECT, "Use OpenGL texture rectangle extension" },
{ "gl-legacy", GDK_DEBUG_GL_LEGACY, "Use a legacy OpenGL context" },
{ "gl-gles", GDK_DEBUG_GL_GLES, "Use a GLES OpenGL context" },
{ "gl-gles", GDK_DEBUG_GL_GLES, "Only allow OpenGL GLES API" },
{ "gl-debug", GDK_DEBUG_GL_DEBUG, "Insert debugging information in OpenGL" },
{ "gl-egl", GDK_DEBUG_GL_EGL, "Use EGL on X11 or Windows" },
{ "gl-glx", GDK_DEBUG_GL_GLX, "Use GLX on X11" },

View File

@@ -94,12 +94,13 @@
#include <epoxy/egl.h>
#endif
#define DEFAULT_ALLOWED_APIS GDK_GL_API_GL | GDK_GL_API_GLES
typedef struct {
int major;
int minor;
int gl_version;
guint realized : 1;
guint has_khr_debug : 1;
guint use_khr_debug : 1;
guint has_unpack_subimage : 1;
@@ -109,7 +110,8 @@ typedef struct {
guint forward_compatible : 1;
guint is_legacy : 1;
int use_es;
GdkGLAPI allowed_apis;
GdkGLAPI api;
int max_debug_label_length;
@@ -121,12 +123,14 @@ typedef struct {
enum {
PROP_0,
PROP_ALLOWED_APIS,
PROP_API,
PROP_SHARED_CONTEXT,
LAST_PROP
};
static GParamSpec *obj_pspecs[LAST_PROP] = { NULL, };
static GParamSpec *properties[LAST_PROP] = { NULL, };
G_DEFINE_QUARK (gdk-gl-error-quark, gdk_gl_error)
@@ -195,36 +199,53 @@ gdk_gl_context_dispose (GObject *gobject)
}
static void
gdk_gl_context_set_property (GObject *gobject,
gdk_gl_context_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdkGLContext *self = GDK_GL_CONTEXT (object);
switch (prop_id)
{
case PROP_ALLOWED_APIS:
gdk_gl_context_set_allowed_apis (self, g_value_get_flags (value));
break;
case PROP_SHARED_CONTEXT:
g_assert (g_value_get_object (value) == NULL);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gdk_gl_context_get_property (GObject *gobject,
gdk_gl_context_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdkGLContext *self = GDK_GL_CONTEXT (object);
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
switch (prop_id)
{
case PROP_ALLOWED_APIS:
g_value_set_flags (value, priv->allowed_apis);
break;
case PROP_API:
g_value_set_flags (value, priv->api);
break;
case PROP_SHARED_CONTEXT:
g_value_set_object (value, NULL);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
@@ -247,7 +268,7 @@ gdk_gl_context_upload_texture (GdkGLContext *context,
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
if (!gdk_memory_format_gl_format (data_format,
priv->use_es,
gdk_gl_context_get_use_es (context),
&gl_internalformat,
&gl_format,
&gl_type))
@@ -261,7 +282,7 @@ gdk_gl_context_upload_texture (GdkGLContext *context,
data = copy;
data_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
if (!gdk_memory_format_gl_format (data_format,
priv->use_es,
gdk_gl_context_get_use_es (context),
&gl_internalformat,
&gl_format,
&gl_type))
@@ -286,8 +307,8 @@ gdk_gl_context_upload_texture (GdkGLContext *context,
glTexImage2D (texture_target, 0, gl_internalformat, width, height, 0, gl_format, gl_type, data);
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
}
else if ((!priv->use_es ||
(priv->use_es && (priv->gl_version >= 30 || priv->has_unpack_subimage))))
else if ((!gdk_gl_context_get_use_es (context) ||
(priv->gl_version >= 30 || priv->has_unpack_subimage)))
{
glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / bpp);
@@ -308,7 +329,7 @@ gdk_gl_context_upload_texture (GdkGLContext *context,
#define N_EGL_ATTRS 16
static gboolean
static GdkGLAPI
gdk_gl_context_real_realize (GdkGLContext *context,
GError **error)
{
@@ -325,7 +346,8 @@ gdk_gl_context_real_realize (GdkGLContext *context,
EGLContext ctx;
EGLint context_attribs[N_EGL_ATTRS];
int major, minor, flags;
gboolean debug_bit, forward_bit, legacy_bit, use_es;
gboolean debug_bit, forward_bit, legacy_bit;
GdkGLAPI api;
int i = 0;
G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
@@ -334,8 +356,6 @@ gdk_gl_context_real_realize (GdkGLContext *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));
use_es = GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES) ||
(share != NULL && gdk_gl_context_get_use_es (share));
if (display->have_egl_no_config_context)
egl_config = NULL;
@@ -349,7 +369,8 @@ gdk_gl_context_real_realize (GdkGLContext *context,
if (forward_bit)
flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
if (!use_es && eglBindAPI (EGL_OPENGL_API))
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;
@@ -362,20 +383,23 @@ gdk_gl_context_real_realize (GdkGLContext *context,
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 (eglBindAPI (EGL_OPENGL_ES_API))
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 supports neither OpenGL nor GLES"));
return FALSE;
_("The EGL implementation does not support any allowed APIs"));
return 0;
}
/* Specify the flags */
@@ -391,7 +415,7 @@ gdk_gl_context_real_realize (GdkGLContext *context,
debug_bit ? "yes" : "no",
forward_bit ? "yes" : "no",
legacy_bit ? "yes" : "no",
use_es ? "yes" : "no"));
api == GDK_GL_API_GLES ? "yes" : "no"));
ctx = eglCreateContext (egl_display,
egl_config,
@@ -400,7 +424,7 @@ gdk_gl_context_real_realize (GdkGLContext *context,
context_attribs);
/* If context creation failed without the ES bit, let's try again with it */
if (ctx == NULL && eglBindAPI (EGL_OPENGL_ES_API))
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;
@@ -413,7 +437,7 @@ gdk_gl_context_real_realize (GdkGLContext *context,
g_assert (i < N_EGL_ATTRS);
legacy_bit = FALSE;
use_es = TRUE;
api = GDK_GL_API_GLES;
GDK_DISPLAY_NOTE (display, OPENGL,
g_message ("eglCreateContext failed, switching to OpenGL ES"));
@@ -425,7 +449,7 @@ gdk_gl_context_real_realize (GdkGLContext *context,
}
/* If context creation failed without the legacy bit, let's try again with it */
if (ctx == NULL && eglBindAPI (EGL_OPENGL_API))
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;
@@ -440,7 +464,7 @@ gdk_gl_context_real_realize (GdkGLContext *context,
g_assert (i < N_EGL_ATTRS);
legacy_bit = TRUE;
use_es = FALSE;
api = GDK_GL_API_GL;
GDK_DISPLAY_NOTE (display, OPENGL,
g_message ("eglCreateContext failed, switching to legacy"));
@@ -456,7 +480,7 @@ gdk_gl_context_real_realize (GdkGLContext *context,
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("Unable to create a GL context"));
return FALSE;
return 0;
}
GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Created EGL context[%p]", ctx));
@@ -464,17 +488,16 @@ gdk_gl_context_real_realize (GdkGLContext *context,
priv->egl_context = ctx;
gdk_gl_context_set_is_legacy (context, legacy_bit);
gdk_gl_context_set_use_es (context, use_es);
gdk_profiler_end_mark (start_time, "realize GdkWaylandGLContext", NULL);
return TRUE;
return api;
}
#endif
g_set_error_literal (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
_("The current backend does not support OpenGL"));
return FALSE;
return 0;
}
#undef N_EGL_ATTRS
@@ -716,7 +739,7 @@ gdk_gl_context_class_init (GdkGLContextClass *klass)
* Deprecated: 4.4: Use [method@Gdk.GLContext.is_shared] to check if contexts
* can be shared.
*/
obj_pspecs[PROP_SHARED_CONTEXT] =
properties[PROP_SHARED_CONTEXT] =
g_param_spec_object ("shared-context",
P_("Shared context"),
P_("The GL context this context shares data with"),
@@ -726,11 +749,45 @@ gdk_gl_context_class_init (GdkGLContextClass *klass)
G_PARAM_STATIC_STRINGS |
G_PARAM_DEPRECATED);
/**
* GdkGLContext:allowed-apis: (attributes org.gtk.Property.get=gdk_gl_context_get_allowed_apis org.gtk.Property.gdk_gl_context_set_allowed_apis)
*
* The allowed APIs.
*
* Since: 4.6
*/
properties[PROP_ALLOWED_APIS] =
g_param_spec_flags ("allowed-apis",
P_("Allowed APIs"),
P_("The list of allowed APIs for this context"),
GDK_TYPE_GL_API,
DEFAULT_ALLOWED_APIS,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
G_PARAM_EXPLICIT_NOTIFY);
/**
* GdkGLContext:api: (attributes org.gtk.Property.get=gdk_gl_context_get_api)
*
* The API currently in use.
*
* Since: 4.6
*/
properties[PROP_API] =
g_param_spec_flags ("api",
P_("API"),
P_("The API currently in use"),
GDK_TYPE_GL_API,
0,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS |
G_PARAM_EXPLICIT_NOTIFY);
gobject_class->set_property = gdk_gl_context_set_property;
gobject_class->get_property = gdk_gl_context_get_property;
gobject_class->dispose = gdk_gl_context_dispose;
g_object_class_install_properties (gobject_class, LAST_PROP, obj_pspecs);
g_object_class_install_properties (gobject_class, LAST_PROP, properties);
}
static void
@@ -738,7 +795,7 @@ gdk_gl_context_init (GdkGLContext *self)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
priv->use_es = -1;
priv->allowed_apis = DEFAULT_ALLOWED_APIS;
}
/* Must have called gdk_display_prepare_gl() before */
@@ -845,6 +902,14 @@ gdk_gl_context_has_unpack_subimage (GdkGLContext *context)
return priv->has_unpack_subimage;
}
static gboolean
gdk_gl_context_is_realized (GdkGLContext *context)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
return priv->api != 0;
}
/**
* gdk_gl_context_set_debug_enabled:
* @context: a `GdkGLContext`
@@ -865,7 +930,7 @@ gdk_gl_context_set_debug_enabled (GdkGLContext *context,
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
g_return_if_fail (!priv->realized);
g_return_if_fail (gdk_gl_context_is_realized (context));
enabled = !!enabled;
@@ -914,7 +979,7 @@ gdk_gl_context_set_forward_compatible (GdkGLContext *context,
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
g_return_if_fail (!priv->realized);
g_return_if_fail (gdk_gl_context_is_realized (context));
compatible = !!compatible;
@@ -967,7 +1032,7 @@ gdk_gl_context_set_required_version (GdkGLContext *context,
#endif
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
g_return_if_fail (!priv->realized);
g_return_if_fail (gdk_gl_context_is_realized (context));
/* this will take care of the default */
if (major == 0 && minor == 0)
@@ -986,7 +1051,7 @@ gdk_gl_context_set_required_version (GdkGLContext *context,
/* Enforce a minimum context version number of 3.2 for desktop GL,
* and 2.0 for GLES
*/
if (priv->use_es > 0 || force_gles)
if (gdk_gl_context_get_use_es (context) || force_gles)
min_ver = 200;
else
min_ver = 302;
@@ -1034,7 +1099,7 @@ gdk_gl_context_get_required_version (GdkGLContext *context,
* enforce a context version number of 3.2 for desktop GL,
* and 2.0 for GLES
*/
if (priv->use_es > 0 || force_gles)
if (gdk_gl_context_get_use_es (context) || force_gles)
{
default_major = 2;
default_minor = 0;
@@ -1090,7 +1155,7 @@ gdk_gl_context_is_legacy (GdkGLContext *context)
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
g_return_val_if_fail (priv->realized, FALSE);
g_return_val_if_fail (gdk_gl_context_is_realized (context), FALSE);
return priv->is_legacy;
}
@@ -1130,18 +1195,116 @@ gboolean
gdk_gl_context_is_shared (GdkGLContext *self,
GdkGLContext *other)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
GdkGLContextPrivate *priv_other = gdk_gl_context_get_instance_private (other);
g_return_val_if_fail (GDK_IS_GL_CONTEXT (self), FALSE);
g_return_val_if_fail (GDK_IS_GL_CONTEXT (other), FALSE);
if (!priv->realized || !priv_other->realized)
if (!gdk_gl_context_is_realized (self) ||
!gdk_gl_context_is_realized (other))
return FALSE;
return GDK_GL_CONTEXT_GET_CLASS (self)->is_shared (self, other);
}
/**
* gdk_gl_context_set_allowed_apis: (attributes org.gtk.Method.set_property=allowed-apis)
* @self: a GL context
* @apis: the allowed APIs
*
* Sets the allowed APIs. When gdk_gl_context_realize() is called, only the
* allowed APIs will be tried. If you set this to 0, realizing will always fail.
*
* If you set it on a realized context, the property will not have any effect.
* It is only relevant during gdk_gl_context_realize().
*
* By default, all APIs are allowed.
*
* Since: 4.6
**/
void
gdk_gl_context_set_allowed_apis (GdkGLContext *self,
GdkGLAPI apis)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
g_return_if_fail (GDK_IS_GL_CONTEXT (self));
if (priv->allowed_apis == apis)
return;
priv->allowed_apis = apis;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ALLOWED_APIS]);
}
/**
* gdk_gl_context_get_allowed_apis: (attributes org.gtk.Method.get_property=allowed-apis)
* @self: a GL context
*
* Gets the allowed APIs set via gdk_gl_context_set_allowed_apis().
*
* Returns: the allowed APIs
*
* Since: 4.6
**/
GdkGLAPI
gdk_gl_context_get_allowed_apis (GdkGLContext *self)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
g_return_val_if_fail (GDK_IS_GL_CONTEXT (self), 0);
return priv->allowed_apis;
}
/**
* gdk_gl_context_get_api: (attributes org.gtk.Method.get_property=api)
* @self: a GL context
*
* Gets the API currently in use.
*
* If the renderer has not been realized yet, 0 is returned.
*
* Returns: the currently used API
*
* Since: 4.6
**/
GdkGLAPI
gdk_gl_context_get_api (GdkGLContext *self)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
g_return_val_if_fail (GDK_IS_GL_CONTEXT (self), 0);
return priv->api;
}
gboolean
gdk_gl_context_is_api_allowed (GdkGLContext *self,
GdkGLAPI api,
GError **error)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
if (GDK_DISPLAY_DEBUG_CHECK (gdk_gl_context_get_display (self), GL_GLES))
{
if (!(api & GDK_GL_API_GLES))
{
g_set_error_literal (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
_("Anything but OpenGL ES disabled via GDK_DEBUG"));
return FALSE;
}
}
if (priv->allowed_apis & api)
return TRUE;
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
_("Application does not support %s API"),
api == GDK_GL_API_GL ? "OpenGL" : "OpenGL ES");
return FALSE;
}
/**
* gdk_gl_context_set_use_es:
* @context: a `GdkGLContext`
@@ -1166,13 +1329,24 @@ void
gdk_gl_context_set_use_es (GdkGLContext *context,
int use_es)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
g_return_if_fail (!priv->realized);
g_return_if_fail (gdk_gl_context_is_realized (context));
if (priv->use_es != use_es)
priv->use_es = use_es;
switch (use_es)
{
case -1:
gdk_gl_context_set_allowed_apis (context, DEFAULT_ALLOWED_APIS);
break;
case 0:
gdk_gl_context_set_allowed_apis (context, GDK_GL_API_GL);
break;
case 1:
gdk_gl_context_set_allowed_apis (context, GDK_GL_API_GLES);
break;
default:
/* Just ignore the call */
break;
}
}
/**
@@ -1190,10 +1364,7 @@ gdk_gl_context_get_use_es (GdkGLContext *context)
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
if (!priv->realized)
return FALSE;
return priv->use_es > 0;
return priv->api == GDK_GL_API_GLES;
}
static void APIENTRY
@@ -1306,12 +1477,15 @@ gdk_gl_context_realize (GdkGLContext *context,
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
if (priv->realized)
if (priv->api)
return TRUE;
priv->realized = GDK_GL_CONTEXT_GET_CLASS (context)->realize (context, error);
priv->api = GDK_GL_CONTEXT_GET_CLASS (context)->realize (context, error);
return priv->realized;
if (priv->api)
g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_API]);
return priv->api;
}
static void
@@ -1323,7 +1497,7 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
GdkDisplay *display;
#endif
if (!priv->realized)
if (!gdk_gl_context_is_realized (context))
return;
if (priv->extensions_checked)
@@ -1331,9 +1505,6 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
priv->gl_version = epoxy_gl_version ();
if (priv->use_es < 0)
priv->use_es = !epoxy_is_desktop_gl ();
priv->has_debug_output = epoxy_has_gl_extension ("GL_ARB_debug_output") ||
epoxy_has_gl_extension ("GL_KHR_debug");
@@ -1354,7 +1525,7 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
glDebugMessageCallback (gl_debug_message_callback, NULL);
}
if (priv->use_es)
if (gdk_gl_context_get_use_es (context))
{
priv->has_unpack_subimage = epoxy_has_gl_extension ("GL_EXT_unpack_subimage");
priv->has_khr_debug = epoxy_has_gl_extension ("GL_KHR_debug");
@@ -1381,7 +1552,7 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
"* Extensions checked:\n"
" - GL_KHR_debug: %s\n"
" - GL_EXT_unpack_subimage: %s",
priv->use_es ? "OpenGL ES" : "OpenGL",
gdk_gl_context_get_use_es (context) ? "OpenGL ES" : "OpenGL",
priv->gl_version / 10, priv->gl_version % 10,
priv->is_legacy ? "legacy" : "core",
glGetString (GL_SHADING_LANGUAGE_VERSION),
@@ -1400,7 +1571,6 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
void
gdk_gl_context_make_current (GdkGLContext *context)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
MaskedContext *current, *masked_context;
gboolean surfaceless;
@@ -1414,7 +1584,7 @@ gdk_gl_context_make_current (GdkGLContext *context)
return;
/* we need to realize the GdkGLContext if it wasn't explicitly realized */
if (!priv->realized)
if (!gdk_gl_context_is_realized (context))
{
GError *error = NULL;
@@ -1510,7 +1680,7 @@ gdk_gl_context_get_version (GdkGLContext *context,
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
g_return_if_fail (priv->realized);
g_return_if_fail (gdk_gl_context_is_realized (context));
if (major != NULL)
*major = priv->gl_version / 10;

View File

@@ -30,6 +30,20 @@
G_BEGIN_DECLS
/**
* GdkGLAPI:
* @GDK_GL_API_GL: The OpenGL API
* @GDK_GL_API_GLES: The OpenGL ES API
*
* The list of the different APIs that GdkGLContext can potentially support.
*
* Since: 4.6
*/
typedef enum { /*< underscore_name=GDK_GL_API >*/
GDK_GL_API_GL = 1 << 0,
GDK_GL_API_GLES = 1 << 1
} GdkGLAPI;
#define GDK_TYPE_GL_CONTEXT (gdk_gl_context_get_type ())
#define GDK_GL_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_GL_CONTEXT, GdkGLContext))
#define GDK_IS_GL_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_GL_CONTEXT))
@@ -76,7 +90,14 @@ void gdk_gl_context_set_forward_compatible (GdkGLContext *
gboolean compatible);
GDK_AVAILABLE_IN_ALL
gboolean gdk_gl_context_get_forward_compatible (GdkGLContext *context);
GDK_AVAILABLE_IN_ALL
GDK_AVAILABLE_IN_4_6
void gdk_gl_context_set_allowed_apis (GdkGLContext *self,
GdkGLAPI apis);
GDK_AVAILABLE_IN_4_6
GdkGLAPI gdk_gl_context_get_allowed_apis (GdkGLContext *self);
GDK_AVAILABLE_IN_4_6
GdkGLAPI gdk_gl_context_get_api (GdkGLContext *self);
GDK_DEPRECATED_IN_4_6_FOR(gdk_gl_context_set_allowed_apis)
void gdk_gl_context_set_use_es (GdkGLContext *context,
int use_es);
GDK_AVAILABLE_IN_ALL

View File

@@ -62,7 +62,7 @@ struct _GdkGLContextClass
GdkGLBackend backend_type;
gboolean (* realize) (GdkGLContext *context,
GdkGLAPI (* realize) (GdkGLContext *context,
GError **error);
gboolean (* make_current) (GdkGLContext *context,
@@ -102,6 +102,9 @@ void gdk_gl_backend_use (GdkGLBackend
GdkGLContext * gdk_gl_context_new_for_surface (GdkSurface *surface);
gboolean gdk_gl_context_is_api_allowed (GdkGLContext *self,
GdkGLAPI api,
GError **error);
void gdk_gl_context_set_is_legacy (GdkGLContext *context,
gboolean is_legacy);

View File

@@ -184,7 +184,10 @@ gdk_macos_gl_context_real_realize (GdkGLContext *context,
g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
if (self->gl_context != nil)
return TRUE;
return GDK_GL_API_GL;
if (!gdk_gl_context_is_api_allowed (context, GDK_GL_API_GL, error))
return 0;
existing = [NSOpenGLContext currentContext];
@@ -197,7 +200,7 @@ gdk_macos_gl_context_real_realize (GdkGLContext *context,
if (shared != NULL)
{
if (!(shared_gl_context = get_ns_open_gl_context (GDK_MACOS_GL_CONTEXT (shared), error)))
return FALSE;
return 0;
}
GDK_DISPLAY_NOTE (display,
@@ -206,7 +209,7 @@ gdk_macos_gl_context_real_realize (GdkGLContext *context,
major, minor));
if (!(pixelFormat = create_pixel_format (major, minor, error)))
return FALSE;
return 0;
gl_context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
shareContext:shared_gl_context];
@@ -219,7 +222,7 @@ gdk_macos_gl_context_real_realize (GdkGLContext *context,
GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
"Failed to create NSOpenGLContext");
return FALSE;
return 0;
}
cgl_context = [gl_context CGLContextObj];
@@ -258,7 +261,7 @@ gdk_macos_gl_context_real_realize (GdkGLContext *context,
if (existing != NULL)
[existing makeCurrentContext];
return TRUE;
return GDK_GL_API_GL;
}
static gboolean

View File

@@ -543,7 +543,7 @@ set_wgl_pixformat_for_hdc (HDC hdc,
return TRUE;
}
static gboolean
static GdkGLAPI
gdk_win32_gl_context_wgl_realize (GdkGLContext *context,
GError **error)
{
@@ -564,6 +564,9 @@ gdk_win32_gl_context_wgl_realize (GdkGLContext *context,
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
GdkGLContext *share = gdk_display_get_gl_context (display);
if (!gdk_gl_context_is_api_allowed (context, GDK_GL_API_GL, error))
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);
@@ -589,7 +592,7 @@ gdk_win32_gl_context_wgl_realize (GdkGLContext *context,
GDK_GL_ERROR_UNSUPPORTED_FORMAT,
_("No available configurations for the given pixel format"));
return FALSE;
return 0;
}
/* if there isn't wglCreateContextAttribsARB() on WGL, use a legacy context */
@@ -622,7 +625,7 @@ gdk_win32_gl_context_wgl_realize (GdkGLContext *context,
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("Unable to create a GL context"));
return FALSE;
return 0;
}
GDK_NOTE (OPENGL,
@@ -632,13 +635,10 @@ gdk_win32_gl_context_wgl_realize (GdkGLContext *context,
context_wgl->wgl_context = hglrc;
/* No GLES, WGL does not support using EGL contexts */
gdk_gl_context_set_use_es (context, FALSE);
/* Ensure that any other context is created with a legacy bit set */
gdk_gl_context_set_is_legacy (context, legacy_bit);
return TRUE;
return GDK_GL_API_GL;
}
static gboolean

View File

@@ -509,7 +509,7 @@ on_surface_state_changed (GdkGLContext *context)
}
#endif
static gboolean
static GdkGLAPI
gdk_x11_gl_context_glx_realize (GdkGLContext *context,
GError **error)
{
@@ -519,8 +519,9 @@ gdk_x11_gl_context_glx_realize (GdkGLContext *context,
Display *dpy;
GdkSurface *surface;
GdkGLContext *share;
gboolean debug_bit, compat_bit, legacy_bit, es_bit;
gboolean debug_bit, compat_bit, legacy_bit;
int major, minor, flags;
GdkGLAPI api = 0;
display = gdk_gl_context_get_display (context);
dpy = gdk_x11_display_get_xdisplay (display);
@@ -536,9 +537,6 @@ gdk_x11_gl_context_glx_realize (GdkGLContext *context,
/* 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);
es_bit = (GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES) || (share != NULL && gdk_gl_context_get_use_es (share))) &&
(display_x11->has_glx_create_context && display_x11->has_glx_create_es2_context);
/* 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.
@@ -553,12 +551,13 @@ gdk_x11_gl_context_glx_realize (GdkGLContext *context,
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, es:%s)",
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",
es_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
@@ -567,58 +566,68 @@ gdk_x11_gl_context_glx_realize (GdkGLContext *context,
if (legacy_bit && !GDK_X11_DISPLAY (display)->has_glx_create_context)
{
GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Creating legacy GL context on request"));
context_glx->glx_context = create_legacy_context (display, display_x11->glx_config, share);
/* do it below */
}
else
{
int profile;
if (es_bit)
profile = GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
else
profile = legacy_bit ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
: GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
/* 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)
if (gdk_gl_context_is_api_allowed (context, GDK_GL_API_GL, NULL))
{
major = 3;
minor = 0;
int profile = legacy_bit ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
: GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
/* 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 GL3 context"));
context_glx->glx_context = create_gl3_context (display,
display_x11->glx_config,
share,
profile,
flags, major, minor);
api = GDK_GL_API_GL;
}
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);
/* Fall back to legacy in case the GL3 context creation failed */
if (context_glx->glx_context == NULL)
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 fallback legacy context"));
context_glx->glx_context = create_legacy_context (display, display_x11->glx_config, share);
legacy_bit = TRUE;
es_bit = FALSE;
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;
}
}
/* 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 (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 FALSE;
return 0;
}
/* Ensure that any other context is created with a legacy bit set */
gdk_gl_context_set_is_legacy (context, legacy_bit);
/* Ensure that any other context is created with an ES bit set */
gdk_gl_context_set_use_es (context, es_bit);
GDK_DISPLAY_NOTE (display, OPENGL,
g_message ("Realized GLX context[%p], %s, version: %d.%d",
context_glx->glx_context,
@@ -655,7 +664,7 @@ gdk_x11_gl_context_glx_realize (GdkGLContext *context,
}
#endif
return TRUE;
return api;
}
static void

View File

@@ -319,7 +319,7 @@ gtk_gl_area_real_create_context (GtkGLArea *area)
return NULL;
}
gdk_gl_context_set_use_es (context, priv->use_es);
gdk_gl_context_set_allowed_apis (context, priv->use_es ? GDK_GL_API_GLES : GDK_GL_API_GL);
gdk_gl_context_set_required_version (context,
priv->required_gl_version / 10,
priv->required_gl_version % 10);