Compare commits

...

8 Commits

Author SHA1 Message Date
Emmanuele Bassi
116c96127b wayland: Allow falling back to compatibility EGL contexts
If the shared context is in legacy mode, or if the creation of a core
profile context failed, we fall back to an EGL context in compatibility
mode.

Since we're relying on a fairly new EGL implementation for Wayland, we
don't fall back to the older EGL API, and instead we always require the
EGL_KHR_create_context extension.

https://bugzilla.gnome.org/show_bug.cgi?id=756142
2015-10-07 15:57:18 +01:00
Emmanuele Bassi
3e6693ca1d docs: Improve description of gdk_gl_context_is_legacy()
Explain why this function is available, and why you may need it.

https://bugzilla.gnome.org/show_bug.cgi?id=756142
2015-10-07 15:57:18 +01:00
Emmanuele Bassi
3353e76409 Allow testglarea to work with legacy GL contexts
Use the 1.30 GLSL shading language for the fragment and vertex shaders.

https://bugzilla.gnome.org/show_bug.cgi?id=756142
2015-10-07 15:57:18 +01:00
Emmanuele Bassi
51fc7930f0 Control legacy GL context via environment variable
For testing purposes, we may want to force the creation of legacy GL
contexts via an environment variable.

https://bugzilla.gnome.org/show_bug.cgi?id=756142
2015-10-07 15:57:18 +01:00
Emmanuele Bassi
c547fd0223 x11: Create legacy GLX contexts
If GLX has support for the GLX_ARB_create_context_profile extension,
then we use the GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; if it does
not, we fall back to the old glXCreateNewContext() API.

We use the shared GdkGLContext to decide whether the GLX context should
use the legacy bit or not.

https://bugzilla.gnome.org/show_bug.cgi?id=756142
2015-10-07 15:57:18 +01:00
Emmanuele Bassi
87bde51d81 gl: Use older GLSL shaders with legacy contexts
If we're using modern GLSL, then we should stop using deprecated
modifiers, like 'varying' and 'attribute', as well as deprecated global
variables, like 'gl_FragColor'.

On the other hand, with legacy contexts we should be using older GLSL
shaders, to maximize compatibility.

https://bugzilla.gnome.org/show_bug.cgi?id=756142
2015-10-07 15:45:12 +01:00
Emmanuele Bassi
193ea5e14a gl: Store the legacy bit in the GL program data
We need to know if we're using a legacy GL context in various places.

https://bugzilla.gnome.org/show_bug.cgi?id=756142
2015-10-07 15:45:06 +01:00
Emmanuele Bassi
20b0b16d58 gdk: Allow querying if a GL context is in legacy mode
We want to have the ability to fall back to legacy GL contexts when
creating them. In order to do so, we need to store the legacy bit on the
GdkGLContext, as well as being able to query it.

Setting the legacy bit from outside GDK is not possible; we cannot
create GL contexts in 3.2 core profile *and* compatibility modes at the
same time, and if we allowed users to select the legacy mode themselves,
it would break the creation of the GdkWindow's paint GL context.

What we do allow is falling back to legacy GL context if the platform
does not support 3.2 core profiles — for instance, on older GPUs or
inside virtualized environments.

We are also going to use the legacy bit internally, to choose which GL
API we can use when drawing GL content.

https://bugzilla.gnome.org/show_bug.cgi?id=756142
2015-10-07 15:44:56 +01:00
9 changed files with 273 additions and 34 deletions

View File

@@ -144,6 +144,7 @@ static const GDebugKey gdk_gl_keys[] = {
{"software-draw-gl", GDK_GL_SOFTWARE_DRAW_GL},
{"software-draw-surface", GDK_GL_SOFTWARE_DRAW_SURFACE},
{"texture-rectangle", GDK_GL_TEXTURE_RECTANGLE},
{"legacy", GDK_GL_LEGACY},
};
#ifdef G_ENABLE_DEBUG

View File

@@ -147,9 +147,27 @@ bind_vao (GdkGLContextPaintData *paint_data)
static void
use_texture_2d_program (GdkGLContextPaintData *paint_data)
{
static const char *vertex_shader_code =
static const char *vertex_shader_code_150 =
"#version 150\n"
"uniform sampler2D map;"
"in vec2 position;\n"
"in vec2 uv;\n"
"out vec2 vUv;\n"
"void main() {\n"
" gl_Position = vec4(position, 0, 1);\n"
" vUv = uv;\n"
"}\n";
static const char *fragment_shader_code_150 =
"#version 150\n"
"in vec2 vUv;\n"
"out vec4 vertexColor;\n"
"uniform sampler2D map;\n"
"void main() {\n"
" vertexColor = texture2D (map, vUv);\n"
"}\n";
static const char *vertex_shader_code_130 =
"#version 130\n"
"uniform sampler2D map;"
"attribute vec2 position;\n"
"attribute vec2 uv;\n"
"varying vec2 vUv;\n"
@@ -157,14 +175,21 @@ use_texture_2d_program (GdkGLContextPaintData *paint_data)
" gl_Position = vec4(position, 0, 1);\n"
" vUv = uv;\n"
"}\n";
static const char *fragment_shader_code =
"#version 150\n"
static const char *fragment_shader_code_130 =
"#version 130\n"
"varying vec2 vUv;\n"
"uniform sampler2D map;\n"
"void main() {\n"
" gl_FragColor = texture2D (map, vUv);\n"
"}\n";
const char *vertex_shader_code = paint_data->is_legacy
? vertex_shader_code_130
: vertex_shader_code_150;
const char *fragment_shader_code = paint_data->is_legacy
? fragment_shader_code_130
: fragment_shader_code_150;
if (paint_data->texture_2d_quad_program.program == 0)
make_program (&paint_data->texture_2d_quad_program, vertex_shader_code, fragment_shader_code);
@@ -178,9 +203,9 @@ use_texture_2d_program (GdkGLContextPaintData *paint_data)
static void
use_texture_rect_program (GdkGLContextPaintData *paint_data)
{
static const char *vertex_shader_code =
static const char *vertex_shader_code_150 =
"#version 150\n"
"uniform sampler2DRect map;"
"uniform sampler2DRect map;\n"
"attribute vec2 position;\n"
"attribute vec2 uv;\n"
"varying vec2 vUv;\n"
@@ -188,13 +213,37 @@ use_texture_rect_program (GdkGLContextPaintData *paint_data)
" gl_Position = vec4(position, 0, 1);\n"
" vUv = uv;\n"
"}\n";
static const char *fragment_shader_code =
static const char *fragment_shader_code_150 =
"#version 150\n"
"varying vec2 vUv;\n"
"uniform sampler2DRect map;\n"
"void main() {\n"
" gl_FragColor = texture2DRect (map, vUv);\n"
"}\n";
static const char *vertex_shader_code_130 =
"#version 130\n"
"uniform sampler2DRect map;\n"
"attribute vec2 position;\n"
"attribute vec2 uv;\n"
"varying vec2 vUv;\n"
"void main() {\n"
" gl_Position = vec4(position, 0, 1);\n"
" vUv = uv;\n"
"}\n";
static const char *fragment_shader_code_130 =
"#version 130\n"
"varying vec2 vUv;\n"
"uniform sampler2DRect map;\n"
"void main() {\n"
" gl_FragColor = texture2DRect (map, vUv);\n"
"}\n";
const char *vertex_shader_code = paint_data->is_legacy
? vertex_shader_code_130
: vertex_shader_code_150;
const char *fragment_shader_code = paint_data->is_legacy
? fragment_shader_code_130
: fragment_shader_code_150;
if (paint_data->texture_rect_quad_program.program == 0)
make_program (&paint_data->texture_rect_quad_program, vertex_shader_code, fragment_shader_code);

View File

@@ -103,6 +103,7 @@ typedef struct {
guint extensions_checked : 1;
guint debug_enabled : 1;
guint forward_compatible : 1;
guint is_legacy : 1;
GdkGLContextPaintData *paint_data;
} GdkGLContextPrivate;
@@ -344,7 +345,10 @@ gdk_gl_context_get_paint_data (GdkGLContext *context)
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
if (priv->paint_data == NULL)
priv->paint_data = g_new0 (GdkGLContextPaintData, 1);
{
priv->paint_data = g_new0 (GdkGLContextPaintData, 1);
priv->paint_data->is_legacy = priv->is_legacy;
}
return priv->paint_data;
}
@@ -554,6 +558,51 @@ gdk_gl_context_get_required_version (GdkGLContext *context,
*minor = min;
}
/**
* gdk_gl_context_is_legacy:
* @context: a #GdkGLContext
*
* Whether the #GdkGLContext is in legacy mode or not.
*
* The #GdkGLContext must be realized before calling this function.
*
* When realizing a GL context, GDK will try to use the OpenGL 3.2 core
* profile; this profile removes all the OpenGL API that was deprecated
* prior to the 3.2 version of the specification. If the realization is
* successful, this function will return %FALSE.
*
* If the underlying OpenGL implementation does not support core profiles,
* GDK will fall back to a pre-3.2 compatibility profile, and this function
* will return %TRUE.
*
* You can use the value returned by this function to decide which kind
* of OpenGL API to use, or whether to do extension discovery, or what
* kind of shader programs to load.
*
* Returns: %TRUE if the GL context is in legacy mode
*
* Since: 3.20
*/
gboolean
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);
return priv->is_legacy;
}
void
gdk_gl_context_set_is_legacy (GdkGLContext *context,
gboolean is_legacy)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
priv->is_legacy = !!is_legacy;
}
/**
* gdk_gl_context_realize:
* @context: a #GdkGLContext

View File

@@ -52,6 +52,8 @@ GDK_AVAILABLE_IN_3_16
void gdk_gl_context_get_version (GdkGLContext *context,
int *major,
int *minor);
GDK_AVAILABLE_IN_3_20
gboolean gdk_gl_context_is_legacy (GdkGLContext *context);
GDK_AVAILABLE_IN_3_16
void gdk_gl_context_set_required_version (GdkGLContext *context,

View File

@@ -67,8 +67,13 @@ typedef struct {
GdkGLContextProgram texture_rect_quad_program;
GdkGLContextProgram *current_program;
guint is_legacy : 1;
} GdkGLContextPaintData;
void gdk_gl_context_set_is_legacy (GdkGLContext *context,
gboolean is_legacy);
void gdk_gl_context_upload_texture (GdkGLContext *context,
cairo_surface_t *image_surface,
int width,

View File

@@ -99,7 +99,8 @@ typedef enum {
GDK_GL_ALWAYS = 1 << 1,
GDK_GL_SOFTWARE_DRAW_GL = 1 << 2,
GDK_GL_SOFTWARE_DRAW_SURFACE = 1 << 3,
GDK_GL_TEXTURE_RECTANGLE = 1 << 4
GDK_GL_TEXTURE_RECTANGLE = 1 << 4,
GDK_GL_LEGACY = 1 << 5
} GdkGLFlags;
extern GList *_gdk_default_filters;

View File

@@ -114,12 +114,14 @@ gdk_wayland_gl_context_realize (GdkGLContext *context,
EGLContext ctx;
EGLint context_attribs[N_EGL_ATTRS];
int major, minor, flags;
gboolean debug_bit, forward_bit;
gboolean debug_bit, forward_bit, legacy_bit;
int i = 0;
gdk_gl_context_get_required_version (context, &major, &minor);
debug_bit = gdk_gl_context_get_debug_enabled (context);
forward_bit = gdk_gl_context_get_forward_compatible (context);
legacy_bit = (_gdk_gl_flags & GDK_GL_LEGACY) != 0 ||
(share != NULL && gdk_gl_context_is_legacy (share));
flags = 0;
@@ -128,15 +130,17 @@ gdk_wayland_gl_context_realize (GdkGLContext *context,
if (forward_bit)
flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
/* We want a core profile */
/* We want a core profile, unless in legacy mode */
context_attribs[i++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
context_attribs[i++] = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_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++] = major;
context_attribs[i++] = legacy_bit ? 3 : major;
context_attribs[i++] = EGL_CONTEXT_MINOR_VERSION_KHR;
context_attribs[i++] = minor;
context_attribs[i++] = legacy_bit ? 0 : minor;
/* Specify the flags */
context_attribs[i++] = EGL_CONTEXT_FLAGS_KHR;
@@ -150,6 +154,25 @@ gdk_wayland_gl_context_realize (GdkGLContext *context,
share != NULL ? GDK_WAYLAND_GL_CONTEXT (share)->egl_context
: EGL_NO_CONTEXT,
context_attribs);
/* If context creation failed without the legacy bit, let's try again with it */
if (ctx == NULL && !legacy_bit)
{
/* Ensure that re-ordering does not break the offsets */
g_assert (context_attribs[0] == EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR);
context_attribs[1] = EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR;
context_attribs[3] = 3;
context_attribs[5] = 0;
legacy_bit = TRUE;
ctx = eglCreateContext (display_wayland->egl_display,
context_wayland->egl_config,
share != NULL ? GDK_WAYLAND_GL_CONTEXT (share)->egl_context
: EGL_NO_CONTEXT,
context_attribs);
}
if (ctx == NULL)
{
g_set_error_literal (error, GDK_GL_ERROR,
@@ -162,6 +185,8 @@ gdk_wayland_gl_context_realize (GdkGLContext *context,
context_wayland->egl_context = ctx;
gdk_gl_context_set_is_legacy (context, legacy_bit);
return TRUE;
}

View File

@@ -554,12 +554,13 @@ 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, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
GLX_CONTEXT_PROFILE_MASK_ARB, profile,
GLX_CONTEXT_MAJOR_VERSION_ARB, major,
GLX_CONTEXT_MINOR_VERSION_ARB, minor,
GLX_CONTEXT_FLAGS_ARB, flags,
@@ -586,6 +587,31 @@ create_gl3_context (GdkDisplay *display,
return res;
}
static GLXContext
create_legacy_context (GdkDisplay *display,
GLXFBConfig config,
GdkGLContext *share)
{
GdkX11GLContext *share_x11 = NULL;
GLXContext res;
if (share != NULL)
share_x11 = GDK_X11_GL_CONTEXT (share);
gdk_x11_display_error_trap_push (display);
res = glXCreateNewContext (gdk_x11_display_get_xdisplay (display),
config,
GLX_RGBA_TYPE,
share_x11 != NULL ? share_x11->glx_context : NULL,
TRUE);
if (gdk_x11_display_error_trap_pop (display))
return NULL;
return res;
}
static gboolean
gdk_x11_gl_context_realize (GdkGLContext *context,
GError **error)
@@ -598,7 +624,7 @@ gdk_x11_gl_context_realize (GdkGLContext *context,
DrawableInfo *info;
GdkGLContext *share;
GdkWindow *window;
gboolean debug_bit, compat_bit;
gboolean debug_bit, compat_bit, legacy_bit;
int major, minor, flags;
window = gdk_gl_context_get_window (context);
@@ -611,6 +637,17 @@ gdk_x11_gl_context_realize (GdkGLContext *context,
debug_bit = gdk_gl_context_get_debug_enabled (context);
compat_bit = gdk_gl_context_get_forward_compatible (context);
/* If there is no glXCreateContextAttribsARB() then we default to legacy */
legacy_bit = !GDK_X11_DISPLAY (display)->has_glx_create_context ||
(_gdk_gl_flags & GDK_GL_LEGACY) != 0;
/* 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;
flags = 0;
if (debug_bit)
flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
@@ -618,15 +655,51 @@ gdk_x11_gl_context_realize (GdkGLContext *context,
flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
GDK_NOTE (OPENGL,
g_print ("Creating core GLX context (version:%d.%d, debug:%s, forward:%s)\n",
g_print ("Creating core GLX context (version:%d.%d, debug:%s, forward:%s, legacy:%s)\n",
major, minor,
debug_bit ? "yes" : "no",
compat_bit ? "yes" : "no"));
compat_bit ? "yes" : "no",
legacy_bit ? "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_NOTE (OPENGL, g_print ("Creating legacy GL context on request\n"));
context_x11->glx_context = create_legacy_context (display, context_x11->glx_config, share);
}
else
{
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_NOTE (OPENGL, g_print ("Creating GL3 context\n"));
context_x11->glx_context = create_gl3_context (display,
context_x11->glx_config,
share,
profile, flags, major, minor);
/* Fall back to legacy in case the GL3 context creation failed */
if (context_x11->glx_context == NULL)
{
GDK_NOTE (OPENGL, g_print ("Creating fallback legacy context\n"));
context_x11->glx_context = create_legacy_context (display, context_x11->glx_config, share);
legacy_bit = TRUE;
}
}
context_x11->glx_context = create_gl3_context (display,
context_x11->glx_config,
share,
flags, major, minor);
if (context_x11->glx_context == NULL)
{
g_set_error_literal (error, GDK_GL_ERROR,
@@ -635,6 +708,9 @@ gdk_x11_gl_context_realize (GdkGLContext *context,
return FALSE;
}
/* Ensure that any other context is created with a legacy bit set */
gdk_gl_context_set_is_legacy (context, legacy_bit);
xvisinfo = find_xvisinfo_for_fbconfig (display, context_x11->glx_config);
info = get_glx_drawable_info (window->impl_window);
@@ -1179,15 +1255,6 @@ gdk_x11_window_create_gl_context (GdkWindow *window,
return NULL;
}
if (!GDK_X11_DISPLAY (display)->has_glx_create_context)
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_UNSUPPORTED_PROFILE,
_("The GLX_ARB_create_context_profile extension "
"needed to create core profiles is not available"));
return NULL;
}
visual = gdk_window_get_visual (window);
if (!find_fbconfig_for_visual (display, visual, &config, error))
return NULL;

View File

@@ -80,7 +80,7 @@ create_shader (int type, const char *src)
return shader;
}
static const char *vertex_shader_code =
static const char *vertex_shader_code_330 =
"#version 330\n" \
"\n" \
"layout(location = 0) in vec4 position;\n" \
@@ -89,7 +89,16 @@ static const char *vertex_shader_code =
" gl_Position = mvp * position;\n" \
"}";
static const char *fragment_shader_code =
static const char *vertex_shader_code_legacy =
"#version 130\n" \
"\n" \
"attribute vec4 position;\n" \
"uniform mat4 mvp;\n" \
"void main() {\n" \
" gl_Position = mvp * position;\n" \
"}";
static const char *fragment_shader_code_330 =
"#version 330\n" \
"\n" \
"out vec4 outputColor;\n" \
@@ -98,8 +107,18 @@ static const char *fragment_shader_code =
" outputColor = mix(vec4(1.0f, 0.85f, 0.35f, 1.0f), vec4(0.2f, 0.2f, 0.2f, 1.0f), lerpVal);\n" \
"}";
static const char *fragment_shader_code_legacy =
"#version 130\n" \
"\n" \
"void main() {\n" \
" float lerpVal = gl_FragCoord.y / 400.0f;\n" \
" gl_FragColor = mix(vec4(1.0f, 0.85f, 0.35f, 1.0f), vec4(0.2f, 0.2, 0.2f, 1.0f), lerpVal);\n" \
"}";
static void
init_shaders (GLuint *program_out,
init_shaders (const char *vertex_shader_code,
const char *fragment_shader_code,
GLuint *program_out,
GLuint *mvp_out)
{
GLuint vertex, fragment;
@@ -215,10 +234,28 @@ static GLuint mvp_location;
static void
realize (GtkWidget *widget)
{
const char *fragment, *vertex;
GdkGLContext *context;
gtk_gl_area_make_current (GTK_GL_AREA (widget));
if (gtk_gl_area_get_error (GTK_GL_AREA (widget)) != NULL)
return;
context = gtk_gl_area_get_context (GTK_GL_AREA (widget));
if (!gdk_gl_context_is_legacy (context))
{
vertex = vertex_shader_code_330;
fragment = fragment_shader_code_330;
}
else
{
vertex = vertex_shader_code_legacy;
fragment = fragment_shader_code_legacy;
}
init_buffers (&position_buffer, NULL);
init_shaders (&program, &mvp_location);
init_shaders (vertex, fragment, &program, &mvp_location);
}
static void
@@ -226,6 +263,9 @@ unrealize (GtkWidget *widget)
{
gtk_gl_area_make_current (GTK_GL_AREA (widget));
if (gtk_gl_area_get_error (GTK_GL_AREA (widget)) != NULL)
return;
glDeleteBuffers (1, &position_buffer);
glDeleteProgram (program);
}