egl: Unify contexts

Unify the X11 and Wayland EGL contexts.

This is a bit ugly to implement, because I don't want to create an
interface and I can't make them inherit from the same object, because
one needs to inherit from X11GLContext and the other from
WaylandGLContext.

So we have to put the code in GdkGLContext and make sure non-EGL
contexts can't accidentally run it. This is rather easy because we can
just check for priv->egl_context != NULL.
This commit is contained in:
Benjamin Otte 2021-10-06 00:34:10 +02:00
parent 03cc603093
commit 2ff1ea555f
5 changed files with 327 additions and 597 deletions

View File

@ -80,6 +80,7 @@
#include "gdkdisplayprivate.h"
#include "gdkintl.h"
#include "gdkmemorytextureprivate.h"
#include "gdkprofilerprivate.h"
#include "gdk-private.h"
@ -88,6 +89,9 @@
#endif
#include <epoxy/gl.h>
#ifdef HAVE_EGL
#include <epoxy/egl.h>
#endif
typedef struct {
int major;
@ -107,6 +111,10 @@ typedef struct {
int use_es;
int max_debug_label_length;
#ifdef HAVE_EGL
EGLContext egl_context;
#endif
} GdkGLContextPrivate;
enum {
@ -161,6 +169,24 @@ static void
gdk_gl_context_dispose (GObject *gobject)
{
GdkGLContext *context = GDK_GL_CONTEXT (gobject);
#ifdef HAVE_EGL
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
if (priv->egl_context != NULL)
{
GdkSurface *surface = gdk_gl_context_get_surface (context);
GdkDisplay *display = gdk_surface_get_display (surface);
EGLDisplay *egl_display = gdk_display_get_egl_display (display);
if (eglGetCurrentContext () == priv->egl_context)
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Destroying EGL context"));
eglDestroyContext (egl_display, priv->egl_context);
priv->egl_context = NULL;
}
#endif
gdk_gl_context_clear_old_updated_area (context);
@ -320,20 +346,219 @@ gdk_gl_context_upload_texture (GdkGLContext *context,
g_free (copy);
}
#define N_EGL_ATTRS 16
static gboolean
gdk_gl_context_real_realize (GdkGLContext *self,
gdk_gl_context_real_realize (GdkGLContext *context,
GError **error)
{
#if 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);
if (egl_display)
{
EGLConfig egl_config = gdk_display_get_egl_config (display);
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, use_es;
int i = 0;
G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
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_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));
flags = 0;
if (debug_bit)
flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
if (forward_bit)
flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
if (!use_es)
{
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;
}
else
{
eglBindAPI (EGL_OPENGL_ES_API);
context_attribs[i++] = EGL_CONTEXT_CLIENT_VERSION;
if (major == 3)
context_attribs[i++] = 3;
else
context_attribs[i++] = 2;
}
/* 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",
use_es ? "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)
{
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);
eglBindAPI (EGL_OPENGL_ES_API);
legacy_bit = FALSE;
use_es = TRUE;
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)
{
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);
eglBindAPI (EGL_OPENGL_API);
legacy_bit = TRUE;
use_es = FALSE;
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 FALSE;
}
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_use_es (context, use_es);
gdk_profiler_end_mark (start_time, "realize GdkWaylandGLContext", NULL);
return TRUE;
}
#endif
g_set_error_literal (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
"The current backend does not support OpenGL");
return FALSE;
}
#undef N_EGL_ATTRS
static cairo_region_t *
gdk_gl_context_real_get_damage (GdkGLContext *context)
{
GdkSurface *surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context));
#ifdef HAVE_EGL
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
if (priv->egl_context && display->have_egl_buffer_age)
{
EGLSurface egl_surface;
int buffer_age = 0;
egl_surface = gdk_surface_get_egl_surface (surface);
gdk_gl_context_make_current (context);
eglQuerySurface (gdk_display_get_egl_display (display), egl_surface,
EGL_BUFFER_AGE_EXT, &buffer_age);
switch (buffer_age)
{
case 1:
return cairo_region_create ();
break;
case 2:
if (context->old_updated_area[0])
return cairo_region_copy (context->old_updated_area[0]);
break;
case 3:
if (context->old_updated_area[0] &&
context->old_updated_area[1])
{
cairo_region_t *damage = cairo_region_copy (context->old_updated_area[0]);
cairo_region_union (damage, context->old_updated_area[1]);
return damage;
}
break;
default:
;
}
}
#endif
return cairo_region_create_rectangle (&(GdkRectangle) {
0, 0,
@ -354,6 +579,51 @@ gdk_gl_context_real_is_shared (GdkGLContext *self,
return TRUE;
}
static gboolean
gdk_gl_context_real_clear_current (GdkGLContext *context)
{
GdkDisplay *display = gdk_gl_context_get_display (context);
#ifdef HAVE_EGL
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
if (priv->egl_context == NULL)
return FALSE;
return eglMakeCurrent (gdk_display_get_egl_display (display),
EGL_NO_SURFACE,
EGL_NO_SURFACE,
EGL_NO_CONTEXT);
#else
return FALSE;
#endif
}
static gboolean
gdk_gl_context_real_make_current (GdkGLContext *context,
gboolean surfaceless)
{
#ifdef HAVE_EGL
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
GdkDisplay *display = gdk_gl_context_get_display (context);
EGLSurface egl_surface;
if (priv->egl_context == NULL)
return FALSE;
if (!surfaceless)
egl_surface = gdk_surface_get_egl_surface (gdk_gl_context_get_surface (context));
else
egl_surface = EGL_NO_SURFACE;
return eglMakeCurrent (gdk_display_get_egl_display (display),
egl_surface,
egl_surface,
priv->egl_context);
#else
return FALSE;
#endif
}
static void
gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context,
cairo_region_t *region)
@ -392,6 +662,52 @@ static void
gdk_gl_context_real_end_frame (GdkDrawContext *draw_context,
cairo_region_t *painted)
{
#ifdef HAVE_EGL
GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
GdkSurface *surface = gdk_gl_context_get_surface (context);
GdkDisplay *display = gdk_surface_get_display (surface);
EGLSurface egl_surface;
if (priv->egl_context == NULL)
return;
gdk_gl_context_make_current (context);
egl_surface = gdk_surface_get_egl_surface (surface);
gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "EGL", "swap buffers");
if (display->have_egl_swap_buffers_with_damage)
{
EGLint stack_rects[4 * 4]; /* 4 rects */
EGLint *heap_rects = NULL;
int i, j, n_rects = cairo_region_num_rectangles (painted);
int surface_height = gdk_surface_get_height (surface);
int scale = gdk_surface_get_scale_factor (surface);
EGLint *rects;
if (n_rects < G_N_ELEMENTS (stack_rects) / 4)
rects = (EGLint *)&stack_rects;
else
heap_rects = rects = g_new (EGLint, n_rects * 4);
for (i = 0, j = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (painted, i, &rect);
rects[j++] = rect.x * scale;
rects[j++] = (surface_height - rect.height - rect.y) * scale;
rects[j++] = rect.width * scale;
rects[j++] = rect.height * scale;
}
eglSwapBuffersWithDamageEXT (gdk_display_get_egl_display (display), egl_surface, rects, n_rects);
g_free (heap_rects);
}
else
eglSwapBuffers (gdk_display_get_egl_display (display), egl_surface);
#endif
}
static void
@ -411,6 +727,8 @@ gdk_gl_context_class_init (GdkGLContextClass *klass)
klass->realize = gdk_gl_context_real_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;
klass->clear_current = gdk_gl_context_real_clear_current;
draw_context_class->begin_frame = gdk_gl_context_real_begin_frame;
draw_context_class->end_frame = gdk_gl_context_real_end_frame;
@ -1357,3 +1675,4 @@ gdk_gl_backend_use (GdkGLBackend backend_type)
g_assert (the_gl_backend_type == backend_type);
}

View File

@ -133,7 +133,6 @@ gboolean gdk_gl_context_has_debug (GdkGLContext
gboolean gdk_gl_context_use_es_bgra (GdkGLContext *context);
G_END_DECLS
#endif /* __GDK_GL_CONTEXT_PRIVATE_H__ */

View File

@ -45,239 +45,6 @@
G_DEFINE_TYPE (GdkWaylandGLContext, gdk_wayland_gl_context, GDK_TYPE_GL_CONTEXT)
static void gdk_wayland_gl_context_dispose (GObject *gobject);
#define N_EGL_ATTRS 16
static gboolean
gdk_wayland_gl_context_realize (GdkGLContext *context,
GError **error)
{
GdkWaylandGLContext *context_wayland = GDK_WAYLAND_GL_CONTEXT (context);
GdkDisplay *display = gdk_gl_context_get_display (context);
GdkGLContext *share = gdk_display_get_gl_context (display);
EGLDisplay egl_display = gdk_display_get_egl_display (display);
EGLConfig egl_config = gdk_display_get_egl_config (display);
EGLContext ctx;
EGLint context_attribs[N_EGL_ATTRS];
int major, minor, flags;
gboolean debug_bit, forward_bit, legacy_bit, use_es;
int i = 0;
G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
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_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));
flags = 0;
if (debug_bit)
flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
if (forward_bit)
flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
if (!use_es)
{
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;
}
else
{
eglBindAPI (EGL_OPENGL_ES_API);
context_attribs[i++] = EGL_CONTEXT_CLIENT_VERSION;
if (major == 3)
context_attribs[i++] = 3;
else
context_attribs[i++] = 2;
}
/* 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",
use_es ? "yes" : "no"));
ctx = eglCreateContext (egl_display,
egl_config,
share != NULL ? GDK_WAYLAND_GL_CONTEXT (share)->egl_context
: EGL_NO_CONTEXT,
context_attribs);
/* If context creation failed without the ES bit, let's try again with it */
if (ctx == NULL)
{
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);
eglBindAPI (EGL_OPENGL_ES_API);
legacy_bit = FALSE;
use_es = TRUE;
GDK_DISPLAY_NOTE (display, OPENGL,
g_message ("eglCreateContext failed, switching to OpenGL ES"));
ctx = eglCreateContext (egl_display,
egl_config,
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)
{
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);
eglBindAPI (EGL_OPENGL_API);
legacy_bit = TRUE;
use_es = FALSE;
GDK_DISPLAY_NOTE (display, OPENGL,
g_message ("eglCreateContext failed, switching to legacy"));
ctx = eglCreateContext (egl_display,
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,
GDK_GL_ERROR_NOT_AVAILABLE,
_("Unable to create a GL context"));
return FALSE;
}
GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Created EGL context[%p]", ctx));
context_wayland->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;
}
static cairo_region_t *
gdk_wayland_gl_context_get_damage (GdkGLContext *context)
{
GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
EGLSurface egl_surface;
GdkSurface *surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context));
int buffer_age = 0;
if (display->have_egl_buffer_age)
{
egl_surface = gdk_surface_get_egl_surface (surface);
gdk_gl_context_make_current (context);
eglQuerySurface (gdk_display_get_egl_display (display), egl_surface,
EGL_BUFFER_AGE_EXT, &buffer_age);
switch (buffer_age)
{
case 1:
return cairo_region_create ();
break;
case 2:
if (context->old_updated_area[0])
return cairo_region_copy (context->old_updated_area[0]);
break;
case 3:
if (context->old_updated_area[0] &&
context->old_updated_area[1])
{
cairo_region_t *damage = cairo_region_copy (context->old_updated_area[0]);
cairo_region_union (damage, context->old_updated_area[1]);
return damage;
}
break;
default:
;
}
}
return GDK_GL_CONTEXT_CLASS (gdk_wayland_gl_context_parent_class)->get_damage (context);
}
static gboolean
gdk_wayland_gl_context_clear_current (GdkGLContext *context)
{
GdkDisplay *display = gdk_gl_context_get_display (context);
return eglMakeCurrent (gdk_display_get_egl_display (display),
EGL_NO_SURFACE,
EGL_NO_SURFACE,
EGL_NO_CONTEXT);
}
static gboolean
gdk_wayland_gl_context_make_current (GdkGLContext *context,
gboolean surfaceless)
{
GdkWaylandGLContext *context_wayland = GDK_WAYLAND_GL_CONTEXT (context);
GdkDisplay *display = gdk_gl_context_get_display (context);
EGLSurface egl_surface;
if (!surfaceless)
egl_surface = gdk_surface_get_egl_surface (gdk_gl_context_get_surface (context));
else
egl_surface = EGL_NO_SURFACE;
return eglMakeCurrent (gdk_display_get_egl_display (display),
egl_surface,
egl_surface,
context_wayland->egl_context);
}
static void
gdk_wayland_gl_context_begin_frame (GdkDrawContext *draw_context,
cairo_region_t *region)
@ -293,49 +60,12 @@ static void
gdk_wayland_gl_context_end_frame (GdkDrawContext *draw_context,
cairo_region_t *painted)
{
GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
GdkSurface *surface = gdk_gl_context_get_surface (context);
GdkDisplay *display = gdk_surface_get_display (surface);
EGLSurface egl_surface;
GdkSurface *surface = gdk_draw_context_get_surface (draw_context);
GDK_DRAW_CONTEXT_CLASS (gdk_wayland_gl_context_parent_class)->end_frame (draw_context, painted);
gdk_gl_context_make_current (context);
egl_surface = gdk_surface_get_egl_surface (surface);
gdk_wayland_surface_sync (surface);
gdk_wayland_surface_request_frame (surface);
gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "wayland", "swap buffers");
if (display->have_egl_swap_buffers_with_damage)
{
EGLint stack_rects[4 * 4]; /* 4 rects */
EGLint *heap_rects = NULL;
int i, j, n_rects = cairo_region_num_rectangles (painted);
int surface_height = gdk_surface_get_height (surface);
int scale = gdk_surface_get_scale_factor (surface);
EGLint *rects;
if (n_rects < G_N_ELEMENTS (stack_rects) / 4)
rects = (EGLint *)&stack_rects;
else
heap_rects = rects = g_new (EGLint, n_rects * 4);
for (i = 0, j = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (painted, i, &rect);
rects[j++] = rect.x * scale;
rects[j++] = (surface_height - rect.height - rect.y) * scale;
rects[j++] = rect.width * scale;
rects[j++] = rect.height * scale;
}
eglSwapBuffersWithDamageEXT (gdk_display_get_egl_display (display), egl_surface, rects, n_rects);
g_free (heap_rects);
}
else
eglSwapBuffers (gdk_display_get_egl_display (display), egl_surface);
GDK_DRAW_CONTEXT_CLASS (gdk_wayland_gl_context_parent_class)->end_frame (draw_context, painted);
gdk_wayland_surface_notify_committed (surface);
}
@ -343,20 +73,12 @@ gdk_wayland_gl_context_end_frame (GdkDrawContext *draw_context,
static void
gdk_wayland_gl_context_class_init (GdkWaylandGLContextClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
gobject_class->dispose = gdk_wayland_gl_context_dispose;
draw_context_class->begin_frame = gdk_wayland_gl_context_begin_frame;
draw_context_class->end_frame = gdk_wayland_gl_context_end_frame;
context_class->realize = gdk_wayland_gl_context_realize;
context_class->make_current = gdk_wayland_gl_context_make_current;
context_class->clear_current = gdk_wayland_gl_context_clear_current;
context_class->get_damage = gdk_wayland_gl_context_get_damage;
context_class->backend_type = GDK_GL_EGL;
}
@ -401,27 +123,3 @@ gdk_wayland_display_init_gl (GdkDisplay *display,
NULL);
}
static void
gdk_wayland_gl_context_dispose (GObject *gobject)
{
GdkWaylandGLContext *context_wayland = GDK_WAYLAND_GL_CONTEXT (gobject);
if (context_wayland->egl_context != NULL)
{
GdkGLContext *context = GDK_GL_CONTEXT (gobject);
GdkSurface *surface = gdk_gl_context_get_surface (context);
GdkDisplay *display = gdk_surface_get_display (surface);
EGLDisplay *egl_display = gdk_display_get_egl_display (display);
if (eglGetCurrentContext () == context_wayland->egl_context)
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Destroying EGL context"));
eglDestroyContext (egl_display, context_wayland->egl_context);
context_wayland->egl_context = NULL;
}
G_OBJECT_CLASS (gdk_wayland_gl_context_parent_class)->dispose (gobject);
}

View File

@ -33,8 +33,6 @@ G_BEGIN_DECLS
struct _GdkWaylandGLContext
{
GdkGLContext parent_instance;
EGLContext egl_context;
};
struct _GdkWaylandGLContextClass

View File

@ -32,8 +32,6 @@ struct _GdkX11GLContextEGL
{
GdkX11GLContext parent_instance;
EGLContext egl_context;
guint do_frame_sync : 1;
};
@ -70,66 +68,6 @@ gdk_x11_gl_context_egl_begin_frame (GdkDrawContext *draw_context,
glDrawBuffers (1, (GLenum[1]) { GL_BACK });
}
static void
gdk_x11_gl_context_egl_end_frame (GdkDrawContext *draw_context,
cairo_region_t *painted)
{
GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
GdkSurface *surface = gdk_gl_context_get_surface (context);
GdkDisplay *display = gdk_surface_get_display (surface);
EGLSurface egl_surface;
GDK_DRAW_CONTEXT_CLASS (gdk_x11_gl_context_egl_parent_class)->end_frame (draw_context, painted);
gdk_gl_context_make_current (context);
egl_surface = gdk_surface_get_egl_surface (surface);
gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "x11", "swap buffers");
if (display->have_egl_swap_buffers_with_damage)
{
int i, j, n_rects = cairo_region_num_rectangles (painted);
int surface_height = gdk_surface_get_height (surface);
int scale = gdk_surface_get_scale_factor (surface);
EGLint stack_rects[4 * 4]; /* 4 rects */
EGLint *heap_rects = NULL;
EGLint *rects;
if (n_rects < G_N_ELEMENTS (stack_rects) / 4)
rects = (EGLint *) &stack_rects;
else
rects = heap_rects = g_new (EGLint, n_rects * 4);
for (i = 0, j = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (painted, i, &rect);
rects[j++] = rect.x * scale;
rects[j++] = (surface_height - rect.height - rect.y) * scale;
rects[j++] = rect.width * scale;
rects[j++] = rect.height * scale;
}
eglSwapBuffersWithDamageEXT (gdk_display_get_egl_display (display), egl_surface, rects, n_rects);
g_free (heap_rects);
}
else
eglSwapBuffers (gdk_display_get_egl_display (display), egl_surface);
}
static gboolean
gdk_x11_gl_context_egl_clear_current (GdkGLContext *context)
{
GdkDisplay *display = gdk_gl_context_get_display (context);
return eglMakeCurrent (gdk_display_get_egl_display (display),
EGL_NO_SURFACE,
EGL_NO_SURFACE,
EGL_NO_CONTEXT);
}
static gboolean
gdk_x11_gl_context_egl_make_current (GdkGLContext *context,
gboolean surfaceless)
@ -137,31 +75,14 @@ gdk_x11_gl_context_egl_make_current (GdkGLContext *context,
GdkX11GLContextEGL *self = GDK_X11_GL_CONTEXT_EGL (context);
GdkDisplay *display = gdk_gl_context_get_display (context);
EGLDisplay egl_display = gdk_display_get_egl_display (display);
GdkSurface *surface;
EGLSurface egl_surface;
gboolean do_frame_sync = FALSE;
if (surfaceless)
{
return eglMakeCurrent (egl_display,
EGL_NO_SURFACE,
EGL_NO_SURFACE,
self->egl_context);
}
surface = gdk_gl_context_get_surface (context);
egl_surface = gdk_surface_get_egl_surface (surface);
GDK_DISPLAY_NOTE (display, OPENGL,
g_message ("Making EGL context %p current to surface %p",
self->egl_context, egl_surface));
if (!eglMakeCurrent (gdk_display_get_egl_display (display),
egl_surface,
egl_surface,
self->egl_context))
if (!GDK_GL_CONTEXT_CLASS (gdk_x11_gl_context_egl_parent_class)->make_current (context, surfaceless))
return FALSE;
if (surfaceless)
return TRUE;
/* If the WM is compositing there is no particular need to delay
* the swap when drawing on the offscreen, rendering to the screen
* happens later anyway, and its up to the compositor to sync that
@ -181,222 +102,17 @@ gdk_x11_gl_context_egl_make_current (GdkGLContext *context,
return TRUE;
}
static cairo_region_t *
gdk_x11_gl_context_egl_get_damage (GdkGLContext *context)
{
GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
if (display->have_egl_buffer_age)
{
GdkSurface *surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context));
EGLSurface egl_surface;
int buffer_age = 0;
egl_surface = gdk_surface_get_egl_surface (surface);
gdk_gl_context_make_current (context);
eglQuerySurface (gdk_display_get_egl_display (display),
egl_surface,
EGL_BUFFER_AGE_EXT,
&buffer_age);
switch (buffer_age)
{
case 1:
return cairo_region_create ();
case 2:
if (context->old_updated_area[0])
return cairo_region_copy (context->old_updated_area[0]);
break;
case 3:
if (context->old_updated_area[0] && context->old_updated_area[1])
{
cairo_region_t *damage = cairo_region_copy (context->old_updated_area[0]);
cairo_region_union (damage, context->old_updated_area[1]);
return damage;
}
break;
default:
break;
}
}
return GDK_GL_CONTEXT_CLASS (gdk_x11_gl_context_egl_parent_class)->get_damage (context);
}
#define N_EGL_ATTRS 16
static gboolean
gdk_x11_gl_context_egl_realize (GdkGLContext *context,
GError **error)
{
GdkDisplay *display;
GdkX11GLContextEGL *context_egl;
GdkGLContext *share;
EGLDisplay egl_display;
EGLConfig egl_config;
gboolean debug_bit, forward_bit, legacy_bit, use_es;
int major, minor, flags, i = 0;
EGLint context_attrs[N_EGL_ATTRS];
display = gdk_gl_context_get_display (context);
context_egl = GDK_X11_GL_CONTEXT_EGL (context);
share = gdk_display_get_gl_context (display);
egl_display = gdk_display_get_egl_display (display),
egl_config = gdk_display_get_egl_config (display),
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_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));
flags = 0;
if (debug_bit)
flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
if (forward_bit)
flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
if (!use_es)
{
eglBindAPI (EGL_OPENGL_API);
/* We want a core profile, unless in legacy mode */
context_attrs[i++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
context_attrs[i++] = legacy_bit
? EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR
: EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
/* Specify the version */
context_attrs[i++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
context_attrs[i++] = legacy_bit ? 3 : major;
context_attrs[i++] = EGL_CONTEXT_MINOR_VERSION_KHR;
context_attrs[i++] = legacy_bit ? 0 : minor;
context_attrs[i++] = EGL_CONTEXT_FLAGS_KHR;
}
else
{
eglBindAPI (EGL_OPENGL_ES_API);
context_attrs[i++] = EGL_CONTEXT_CLIENT_VERSION;
if (major == 3)
context_attrs[i++] = 3;
else
context_attrs[i++] = 2;
}
context_attrs[i++] = EGL_CONTEXT_FLAGS_KHR;
context_attrs[i++] = flags;
context_attrs[i++] = EGL_NONE;
g_assert (i < N_EGL_ATTRS);
GDK_DISPLAY_NOTE (display, OPENGL,
g_message ("Creating EGL context version %d.%d (shared:%s, debug:%s, forward:%s, legacy:%s, es:%s)",
major, minor,
share != NULL ? "yes" : "no",
debug_bit ? "yes" : "no",
forward_bit ? "yes" : "no",
legacy_bit ? "yes" : "no",
use_es ? "yes" : "no"));
context_egl->egl_context =
eglCreateContext (egl_display,
egl_config,
share != NULL
? GDK_X11_GL_CONTEXT_EGL (share)->egl_context
: EGL_NO_CONTEXT,
context_attrs);
/* If we're not asking for a GLES context, and we don't have the legacy bit set
* already, try again with a legacy context
*/
if (context_egl->egl_context == NULL && !use_es && !legacy_bit)
{
context_attrs[1] = EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR;
context_attrs[3] = 3;
context_attrs[5] = 0;
legacy_bit = TRUE;
use_es = FALSE;
GDK_NOTE (OPENGL,
g_message ("Context creation failed; trying legacy EGL context"));
context_egl->egl_context =
eglCreateContext (egl_display,
egl_config,
share != NULL
? GDK_X11_GL_CONTEXT_EGL (share)->egl_context
: EGL_NO_CONTEXT,
context_attrs);
}
if (context_egl->egl_context == NULL)
{
g_set_error_literal (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
_("Unable to create a GL context"));
return FALSE;
}
gdk_gl_context_set_is_legacy (context, legacy_bit);
gdk_gl_context_set_use_es (context, use_es);
GDK_NOTE (OPENGL,
g_message ("Realized EGL context[%p]",
context_egl->egl_context));
return TRUE;
}
#undef N_EGL_ATTRS
static void
gdk_x11_gl_context_egl_dispose (GObject *gobject)
{
GdkX11GLContextEGL *context_egl = GDK_X11_GL_CONTEXT_EGL (gobject);
if (context_egl->egl_context != NULL)
{
GdkGLContext *context = GDK_GL_CONTEXT (gobject);
GdkDisplay *display = gdk_gl_context_get_display (context);
/* Unset the current context if we're disposing it */
if (eglGetCurrentContext () == context_egl->egl_context)
eglMakeCurrent (gdk_display_get_egl_display (display), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
GDK_NOTE (OPENGL, g_message ("Destroying EGL context"));
eglDestroyContext (gdk_display_get_egl_display (display), context_egl->egl_context);
context_egl->egl_context = NULL;
}
G_OBJECT_CLASS (gdk_x11_gl_context_egl_parent_class)->dispose (gobject);
}
static void
gdk_x11_gl_context_egl_class_init (GdkX11GLContextEGLClass *klass)
{
GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
context_class->backend_type = GDK_GL_EGL;
context_class->realize = gdk_x11_gl_context_egl_realize;
context_class->make_current = gdk_x11_gl_context_egl_make_current;
context_class->clear_current = gdk_x11_gl_context_egl_clear_current;
context_class->get_damage = gdk_x11_gl_context_egl_get_damage;
draw_context_class->begin_frame = gdk_x11_gl_context_egl_begin_frame;
draw_context_class->end_frame = gdk_x11_gl_context_egl_end_frame;
gobject_class->dispose = gdk_x11_gl_context_egl_dispose;
}
static void