mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-12 20:00:09 +00:00
x11: Use EGL for GL support
This makes the X11 backend similar to the Wayland one, when it comes to OpenGL. Fall back to GLX only if EGL support is not available.
This commit is contained in:
parent
03f76eccf5
commit
8924d614c0
@ -126,11 +126,20 @@ struct _GdkX11Display
|
||||
|
||||
int wm_moveresize_button;
|
||||
|
||||
#ifdef HAVE_XDAMAGE
|
||||
int damage_event_base;
|
||||
int damage_error_base;
|
||||
guint have_damage;
|
||||
#endif
|
||||
|
||||
/* GLX information */
|
||||
int glx_version;
|
||||
int glx_error_base;
|
||||
int glx_event_base;
|
||||
|
||||
/* EGL information */
|
||||
int egl_version;
|
||||
|
||||
/* Translation between X server time and system-local monotonic time */
|
||||
gint64 server_time_query_time;
|
||||
gint64 server_time_offset;
|
||||
@ -138,6 +147,7 @@ struct _GdkX11Display
|
||||
guint server_time_is_monotonic_time : 1;
|
||||
|
||||
guint have_glx : 1;
|
||||
guint have_egl : 1;
|
||||
|
||||
/* GLX extensions we check */
|
||||
guint has_glx_swap_interval : 1;
|
||||
@ -151,11 +161,11 @@ struct _GdkX11Display
|
||||
guint has_glx_create_es2_context : 1;
|
||||
guint has_async_glx_swap_buffers : 1;
|
||||
|
||||
#ifdef HAVE_XDAMAGE
|
||||
int damage_event_base;
|
||||
int damage_error_base;
|
||||
guint have_damage;
|
||||
#endif
|
||||
/* EGL extensions we check */
|
||||
guint has_egl_khr_create_context : 1;
|
||||
guint has_egl_buffer_age : 1;
|
||||
guint has_egl_swap_buffers_with_damage : 1;
|
||||
guint has_egl_surfaceless_context : 1;
|
||||
};
|
||||
|
||||
struct _GdkX11DisplayClass
|
||||
|
800
gdk/x11/gdkglcontext-egl.c
Normal file
800
gdk/x11/gdkglcontext-egl.c
Normal file
@ -0,0 +1,800 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
*
|
||||
* gdkglcontext-x11.c: X11 specific OpenGL wrappers
|
||||
*
|
||||
* Copyright © 2014 Emmanuele Bassi
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkglcontext-x11.h"
|
||||
#include "gdkdisplay-x11.h"
|
||||
#include "gdkprivate-x11.h"
|
||||
#include "gdkscreen-x11.h"
|
||||
|
||||
#include "gdkx11display.h"
|
||||
#include "gdkx11glcontext.h"
|
||||
#include "gdkx11screen.h"
|
||||
#include "gdkx11surface.h"
|
||||
#include "gdkvisual-x11.h"
|
||||
#include "gdkx11property.h"
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include "gdkinternals.h"
|
||||
|
||||
#include "gdkintl.h"
|
||||
|
||||
#include <cairo-xlib.h>
|
||||
|
||||
#include <epoxy/egl.h>
|
||||
|
||||
struct _GdkX11GLContextEGL
|
||||
{
|
||||
GdkX11GLContext parent_instance;
|
||||
|
||||
EGLDisplay egl_display;
|
||||
EGLConfig egl_config;
|
||||
EGLContext egl_context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
EGLDisplay egl_display;
|
||||
EGLConfig egl_config;
|
||||
EGLSurface egl_surface;
|
||||
|
||||
/* Only set by the dummy surface we attach to the display */
|
||||
Display *xdisplay;
|
||||
Window dummy_xwin;
|
||||
XVisualInfo *xvisinfo;
|
||||
} DrawableInfo;
|
||||
|
||||
typedef struct _GdkX11GLContextClass GdkX11GLContextEGLClass;
|
||||
|
||||
G_DEFINE_TYPE (GdkX11GLContextEGL, gdk_x11_gl_context_egl, GDK_TYPE_X11_GL_CONTEXT)
|
||||
|
||||
static void
|
||||
drawable_info_free (gpointer data)
|
||||
{
|
||||
DrawableInfo *info = data;
|
||||
|
||||
if (data == NULL)
|
||||
return;
|
||||
|
||||
if (info->egl_surface != NULL)
|
||||
{
|
||||
eglDestroySurface (info->egl_display, info->egl_surface);
|
||||
info->egl_surface = NULL;
|
||||
}
|
||||
|
||||
if (info->dummy_xwin != None)
|
||||
{
|
||||
XDestroyWindow (info->xdisplay, info->dummy_xwin);
|
||||
info->dummy_xwin = None;
|
||||
}
|
||||
|
||||
if (info->xvisinfo != NULL)
|
||||
{
|
||||
XFree (info->xvisinfo);
|
||||
info->xvisinfo = NULL;
|
||||
}
|
||||
|
||||
g_free (info);
|
||||
}
|
||||
|
||||
static EGLDisplay
|
||||
gdk_x11_display_get_egl_display (GdkDisplay *display)
|
||||
{
|
||||
EGLDisplay edpy = NULL;
|
||||
Display *dpy;
|
||||
|
||||
edpy = g_object_get_data (G_OBJECT (display), "-gdk-x11-egl-display");
|
||||
if (edpy != NULL)
|
||||
return edpy;
|
||||
|
||||
dpy = gdk_x11_display_get_xdisplay (display);
|
||||
|
||||
if (epoxy_has_egl_extension (NULL, "EGL_KHR_platform_base"))
|
||||
{
|
||||
PFNEGLGETPLATFORMDISPLAYPROC getPlatformDisplay =
|
||||
(void *) eglGetProcAddress ("eglGetPlatformDisplay");
|
||||
|
||||
if (getPlatformDisplay != NULL)
|
||||
edpy = getPlatformDisplay (EGL_PLATFORM_X11_KHR, dpy, NULL);
|
||||
|
||||
if (edpy != NULL)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (epoxy_has_egl_extension (NULL, "EGL_EXT_platform_base"))
|
||||
{
|
||||
PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplay =
|
||||
(void *) eglGetProcAddress ("eglGetPlatformDisplayEXT");
|
||||
|
||||
if (getPlatformDisplay)
|
||||
edpy = getPlatformDisplay (EGL_PLATFORM_X11_EXT, dpy, NULL);
|
||||
|
||||
if (edpy != NULL)
|
||||
goto out;
|
||||
}
|
||||
|
||||
edpy = eglGetDisplay ((EGLNativeDisplayType) dpy);
|
||||
|
||||
out:
|
||||
if (edpy != NULL)
|
||||
g_object_set_data (G_OBJECT (display), "-gdk-x11-egl-display", edpy);
|
||||
|
||||
return edpy;
|
||||
}
|
||||
|
||||
static XVisualInfo *
|
||||
get_visual_info_for_egl_config (GdkDisplay *display,
|
||||
EGLConfig egl_config)
|
||||
{
|
||||
XVisualInfo visinfo_template;
|
||||
int template_mask = 0;
|
||||
XVisualInfo *visinfo = NULL;
|
||||
int visinfos_count;
|
||||
EGLint visualid, red_size, green_size, blue_size, alpha_size;
|
||||
EGLDisplay egl_display = gdk_x11_display_get_egl_display (display);
|
||||
|
||||
eglGetConfigAttrib (egl_display, egl_config, EGL_NATIVE_VISUAL_ID, &visualid);
|
||||
|
||||
if (visualid != 0)
|
||||
{
|
||||
visinfo_template.visualid = visualid;
|
||||
template_mask |= VisualIDMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* some EGL drivers don't implement the EGL_NATIVE_VISUAL_ID
|
||||
* attribute, so attempt to find the closest match.
|
||||
*/
|
||||
eglGetConfigAttrib (egl_display, egl_config, EGL_RED_SIZE, &red_size);
|
||||
eglGetConfigAttrib (egl_display, egl_config, EGL_GREEN_SIZE, &green_size);
|
||||
eglGetConfigAttrib (egl_display, egl_config, EGL_BLUE_SIZE, &blue_size);
|
||||
eglGetConfigAttrib (egl_display, egl_config, EGL_ALPHA_SIZE, &alpha_size);
|
||||
|
||||
visinfo_template.depth = red_size + green_size + blue_size + alpha_size;
|
||||
template_mask |= VisualDepthMask;
|
||||
|
||||
visinfo_template.screen = DefaultScreen (gdk_x11_display_get_xdisplay (display));
|
||||
template_mask |= VisualScreenMask;
|
||||
}
|
||||
|
||||
visinfo = XGetVisualInfo (gdk_x11_display_get_xdisplay (display),
|
||||
template_mask,
|
||||
&visinfo_template,
|
||||
&visinfos_count);
|
||||
|
||||
if (visinfos_count < 1)
|
||||
return NULL;
|
||||
|
||||
return visinfo;
|
||||
}
|
||||
|
||||
static EGLSurface
|
||||
gdk_x11_display_get_egl_dummy_surface (GdkDisplay *display,
|
||||
EGLConfig egl_config)
|
||||
{
|
||||
DrawableInfo *info;
|
||||
XVisualInfo *xvisinfo;
|
||||
XSetWindowAttributes attrs;
|
||||
|
||||
info = g_object_get_data (G_OBJECT (display), "-gdk-x11-egl-dummy-surface");
|
||||
if (info != NULL)
|
||||
return info->egl_surface;
|
||||
|
||||
xvisinfo = get_visual_info_for_egl_config (display, egl_config);
|
||||
if (xvisinfo == NULL)
|
||||
return NULL;
|
||||
|
||||
info = g_new (DrawableInfo, 1);
|
||||
info->xdisplay = gdk_x11_display_get_xdisplay (display);
|
||||
info->xvisinfo = xvisinfo;
|
||||
info->egl_display = gdk_x11_display_get_egl_display (display);
|
||||
info->egl_config = egl_config;
|
||||
|
||||
attrs.override_redirect = True;
|
||||
attrs.colormap = XCreateColormap (info->xdisplay,
|
||||
DefaultRootWindow (info->xdisplay),
|
||||
xvisinfo->visual,
|
||||
AllocNone);
|
||||
attrs.border_pixel = 0;
|
||||
|
||||
info->dummy_xwin =
|
||||
XCreateWindow (info->xdisplay,
|
||||
DefaultRootWindow (info->xdisplay),
|
||||
-100, -100, 1, 1,
|
||||
0,
|
||||
xvisinfo->depth,
|
||||
CopyFromParent,
|
||||
xvisinfo->visual,
|
||||
CWOverrideRedirect | CWColormap | CWBorderPixel,
|
||||
&attrs);
|
||||
|
||||
info->egl_surface =
|
||||
eglCreateWindowSurface (info->egl_display,
|
||||
info->egl_config,
|
||||
(EGLNativeWindowType) info->dummy_xwin,
|
||||
NULL);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (display), "-gdk-x11-egl-dummy-surface",
|
||||
info,
|
||||
drawable_info_free);
|
||||
|
||||
return info->egl_surface;
|
||||
}
|
||||
|
||||
static EGLSurface
|
||||
gdk_x11_surface_get_egl_surface (GdkSurface *surface,
|
||||
EGLConfig config)
|
||||
{
|
||||
GdkDisplay *display = gdk_surface_get_display (surface);
|
||||
EGLDisplay egl_display = gdk_x11_display_get_egl_display (display);
|
||||
DrawableInfo *info;
|
||||
|
||||
info = g_object_get_data (G_OBJECT (surface), "-gdk-x11-egl-drawable");
|
||||
if (info != NULL)
|
||||
return info->egl_surface;
|
||||
|
||||
info = g_new0 (DrawableInfo, 1);
|
||||
info->egl_display = egl_display;
|
||||
info->egl_config = config;
|
||||
info->egl_surface =
|
||||
eglCreateWindowSurface (info->egl_display, config,
|
||||
(EGLNativeWindowType) gdk_x11_surface_get_xid (surface),
|
||||
NULL);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (surface), "-gdk-x11-egl-drawable",
|
||||
info,
|
||||
drawable_info_free);
|
||||
|
||||
return info->egl_surface;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_gl_context_egl_end_frame (GdkDrawContext *draw_context,
|
||||
cairo_region_t *painted)
|
||||
{
|
||||
GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
|
||||
GdkX11GLContextEGL *context_egl = GDK_X11_GL_CONTEXT_EGL (context);
|
||||
GdkSurface *surface = gdk_gl_context_get_surface (context);
|
||||
GdkDisplay *display = gdk_surface_get_display (surface);
|
||||
GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
|
||||
EGLDisplay egl_display = gdk_x11_display_get_egl_display (display);
|
||||
EGLSurface egl_surface;
|
||||
|
||||
GDK_DRAW_CONTEXT_CLASS (gdk_x11_gl_context_egl_parent_class)->end_frame (draw_context, painted);
|
||||
if (gdk_gl_context_get_shared_context (context) != NULL)
|
||||
return;
|
||||
|
||||
gdk_gl_context_make_current (context);
|
||||
|
||||
egl_surface = gdk_x11_surface_get_egl_surface (surface, context_egl->egl_config);
|
||||
|
||||
if (display_x11->has_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 (egl_display, egl_surface, rects, n_rects);
|
||||
g_free (heap_rects);
|
||||
}
|
||||
else
|
||||
eglSwapBuffers (egl_display, egl_surface);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
gdk_x11_gl_context_egl_get_damage (GdkGLContext *context)
|
||||
{
|
||||
GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
|
||||
GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
|
||||
|
||||
if (display_x11->has_egl_buffer_age)
|
||||
{
|
||||
GdkSurface *surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context));
|
||||
GdkGLContext *shared = gdk_gl_context_get_shared_context (context);
|
||||
GdkX11GLContextEGL *shared_egl;
|
||||
EGLSurface egl_surface;
|
||||
int buffer_age = 0;
|
||||
|
||||
shared = gdk_gl_context_get_shared_context (context);
|
||||
if (shared == NULL)
|
||||
shared = context;
|
||||
shared_egl = GDK_X11_GL_CONTEXT_EGL (shared);
|
||||
|
||||
egl_surface = gdk_x11_surface_get_egl_surface (surface, shared_egl->egl_config);
|
||||
gdk_gl_context_make_current (shared);
|
||||
|
||||
eglQuerySurface (gdk_x11_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)
|
||||
{
|
||||
GdkX11Display *display_x11;
|
||||
GdkDisplay *display;
|
||||
GdkX11GLContextEGL *context_egl;
|
||||
GdkGLContext *share, *shared_data_context;
|
||||
GdkSurface *surface;
|
||||
gboolean debug_bit, forward_bit, legacy_bit, use_es;
|
||||
int major, minor, i = 0;
|
||||
EGLint context_attrs[N_EGL_ATTRS];
|
||||
EGLDisplay egl_display;
|
||||
|
||||
surface = gdk_gl_context_get_surface (context);
|
||||
display = gdk_surface_get_display (surface);
|
||||
|
||||
context_egl = GDK_X11_GL_CONTEXT_EGL (context);
|
||||
display_x11 = GDK_X11_DISPLAY (display);
|
||||
share = gdk_gl_context_get_shared_context (context);
|
||||
shared_data_context = gdk_surface_get_shared_data_gl_context (surface);
|
||||
|
||||
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));
|
||||
|
||||
if (!use_es)
|
||||
{
|
||||
eglBindAPI (EGL_OPENGL_API);
|
||||
|
||||
if (display_x11->has_egl_khr_create_context)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
if (debug_bit)
|
||||
flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
|
||||
if (forward_bit)
|
||||
flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
|
||||
|
||||
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;
|
||||
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;
|
||||
context_attrs[i++] = flags;
|
||||
context_attrs[i++] = EGL_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
context_attrs[i++] = EGL_NONE;
|
||||
}
|
||||
}
|
||||
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_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"));
|
||||
|
||||
egl_display = gdk_x11_display_get_egl_display (display);
|
||||
|
||||
context_egl->egl_context =
|
||||
eglCreateContext (egl_display,
|
||||
context_egl->egl_config,
|
||||
share != NULL
|
||||
? GDK_X11_GL_CONTEXT_EGL (share)->egl_context
|
||||
: shared_data_context != NULL
|
||||
? GDK_X11_GL_CONTEXT_EGL (shared_data_context)->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,
|
||||
context_egl->egl_config,
|
||||
share != NULL
|
||||
? GDK_X11_GL_CONTEXT_EGL (share)->egl_context
|
||||
: shared_data_context != NULL
|
||||
? GDK_X11_GL_CONTEXT_EGL (shared_data_context)->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);
|
||||
EGLDisplay egl_display = gdk_x11_display_get_egl_display (display);
|
||||
|
||||
/* Unset the current context if we're disposing it */
|
||||
if (eglGetCurrentContext () == context_egl->egl_context)
|
||||
eglMakeCurrent (egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
|
||||
GDK_NOTE (OPENGL, g_message ("Destroying EGL context"));
|
||||
eglDestroyContext (egl_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->realize = gdk_x11_gl_context_egl_realize;
|
||||
context_class->get_damage = gdk_x11_gl_context_egl_get_damage;
|
||||
|
||||
draw_context_class->end_frame = gdk_x11_gl_context_egl_end_frame;
|
||||
|
||||
gobject_class->dispose = gdk_x11_gl_context_egl_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_gl_context_egl_init (GdkX11GLContextEGL *self)
|
||||
{
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_x11_screen_init_egl (GdkX11Screen *screen)
|
||||
{
|
||||
GdkDisplay *display = GDK_SCREEN_DISPLAY (screen);
|
||||
GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
|
||||
EGLDisplay edpy;
|
||||
Display *dpy;
|
||||
int major, minor;
|
||||
|
||||
if (display_x11->have_egl)
|
||||
return TRUE;
|
||||
|
||||
dpy = gdk_x11_display_get_xdisplay (display);
|
||||
|
||||
if (!epoxy_has_egl ())
|
||||
return FALSE;
|
||||
|
||||
edpy = gdk_x11_display_get_egl_display (display);
|
||||
if (edpy == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (!eglInitialize (edpy, &major, &minor))
|
||||
return FALSE;
|
||||
|
||||
display_x11->have_egl = TRUE;
|
||||
display_x11->egl_version = epoxy_egl_version (dpy);
|
||||
|
||||
display_x11->has_egl_khr_create_context =
|
||||
epoxy_has_egl_extension (edpy, "EGL_KHR_create_context");
|
||||
display_x11->has_egl_buffer_age =
|
||||
epoxy_has_egl_extension (edpy, "EGL_EXT_buffer_age");
|
||||
display_x11->has_egl_swap_buffers_with_damage =
|
||||
epoxy_has_egl_extension (edpy, "EGL_EXT_swap_buffers_with_damage");
|
||||
display_x11->has_egl_surfaceless_context =
|
||||
epoxy_has_egl_extension (edpy, "EGL_KHR_surfaceless_context");
|
||||
|
||||
GDK_DISPLAY_NOTE (display, OPENGL,
|
||||
g_message ("EGL found\n"
|
||||
" - Version: %s\n"
|
||||
" - Vendor: %s\n"
|
||||
" - Client API: %s\n"
|
||||
" - Checked extensions:\n"
|
||||
"\t* EGL_KHR_create_context: %s\n"
|
||||
"\t* EGL_EXT_buffer_age: %s\n"
|
||||
"\t* EGL_EXT_swap_buffers_with_damage: %s\n"
|
||||
"\t* EGL_KHR_surfaceless_context: %s\n",
|
||||
eglQueryString (edpy, EGL_VERSION),
|
||||
eglQueryString (edpy, EGL_VENDOR),
|
||||
eglQueryString (edpy, EGL_CLIENT_APIS),
|
||||
display_x11->has_egl_khr_create_context ? "yes" : "no",
|
||||
display_x11->has_egl_buffer_age ? "yes" : "no",
|
||||
display_x11->has_egl_swap_buffers_with_damage ? "yes" : "no",
|
||||
display_x11->has_egl_surfaceless_context ? "yes" : "no"));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define MAX_EGL_ATTRS 30
|
||||
|
||||
static gboolean
|
||||
find_eglconfig_for_display (GdkDisplay *display,
|
||||
EGLConfig *egl_config_out,
|
||||
GError **error)
|
||||
{
|
||||
EGLint attrs[MAX_EGL_ATTRS];
|
||||
EGLint count;
|
||||
EGLConfig egl_config;
|
||||
EGLDisplay egl_display;
|
||||
int i = 0;
|
||||
|
||||
attrs[i++] = EGL_SURFACE_TYPE;
|
||||
attrs[i++] = EGL_WINDOW_BIT;
|
||||
|
||||
attrs[i++] = EGL_COLOR_BUFFER_TYPE;
|
||||
attrs[i++] = EGL_RGB_BUFFER;
|
||||
|
||||
attrs[i++] = EGL_RED_SIZE;
|
||||
attrs[i++] = 8;
|
||||
attrs[i++] = EGL_GREEN_SIZE;
|
||||
attrs[i++] = 8;
|
||||
attrs[i++] = EGL_BLUE_SIZE;
|
||||
attrs[i++] = 8;
|
||||
attrs[i++] = EGL_ALPHA_SIZE;
|
||||
attrs[i++] = 8;
|
||||
|
||||
attrs[i++] = EGL_NONE;
|
||||
g_assert (i < MAX_EGL_ATTRS);
|
||||
|
||||
/* Pick first valid configuration that the driver returns us */
|
||||
egl_display = gdk_x11_display_get_egl_display (display);
|
||||
if (!eglChooseConfig (egl_display, attrs, &egl_config, 1, &count) || count < 1)
|
||||
{
|
||||
g_set_error_literal (error, GDK_GL_ERROR,
|
||||
GDK_GL_ERROR_UNSUPPORTED_FORMAT,
|
||||
_("No available configurations for the given pixel format"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_assert (egl_config_out);
|
||||
*egl_config_out = egl_config;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#undef MAX_EGL_ATTRS
|
||||
|
||||
GdkX11GLContext *
|
||||
gdk_x11_gl_context_egl_new (GdkSurface *surface,
|
||||
gboolean attached,
|
||||
GdkGLContext *share,
|
||||
GError **error)
|
||||
{
|
||||
GdkDisplay *display;
|
||||
GdkX11GLContextEGL *context;
|
||||
EGLConfig egl_config;
|
||||
|
||||
display = gdk_surface_get_display (surface);
|
||||
|
||||
if (!find_eglconfig_for_display (display, &egl_config, error))
|
||||
return NULL;
|
||||
|
||||
context = g_object_new (GDK_TYPE_X11_GL_CONTEXT_EGL,
|
||||
"surface", surface,
|
||||
"shared-context", share,
|
||||
NULL);
|
||||
|
||||
context->egl_config = egl_config;
|
||||
|
||||
return GDK_X11_GL_CONTEXT (context);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_x11_gl_context_egl_make_current (GdkDisplay *display,
|
||||
GdkGLContext *context)
|
||||
{
|
||||
GdkX11GLContextEGL *context_egl = GDK_X11_GL_CONTEXT_EGL (context);
|
||||
GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context);
|
||||
GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
|
||||
GdkSurface *surface;
|
||||
EGLDisplay egl_display;
|
||||
EGLSurface egl_surface;
|
||||
|
||||
egl_display = gdk_x11_display_get_egl_display (display);
|
||||
|
||||
if (context == NULL)
|
||||
{
|
||||
eglMakeCurrent (egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (context_egl->egl_context == NULL)
|
||||
{
|
||||
g_critical ("No EGL context associated to the GdkGLContext; you must "
|
||||
"call gdk_gl_context_realize() first.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
surface = gdk_gl_context_get_surface (context);
|
||||
|
||||
if (context_x11->is_attached || gdk_draw_context_is_in_frame (GDK_DRAW_CONTEXT (context)))
|
||||
egl_surface = gdk_x11_surface_get_egl_surface (surface, context_egl->egl_config);
|
||||
else
|
||||
{
|
||||
if (display_x11->has_egl_surfaceless_context)
|
||||
egl_surface = EGL_NO_SURFACE;
|
||||
else
|
||||
egl_surface = gdk_x11_display_get_egl_dummy_surface (display, context_egl->egl_config);
|
||||
}
|
||||
|
||||
GDK_DISPLAY_NOTE (display, OPENGL,
|
||||
g_message ("Making EGL context %p current to surface %p",
|
||||
context_egl->egl_context, egl_surface));
|
||||
|
||||
if (!eglMakeCurrent (egl_display, egl_surface, egl_surface, context_egl->egl_context))
|
||||
{
|
||||
GDK_DISPLAY_NOTE (display, OPENGL,
|
||||
g_message ("Making EGL context current failed"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (context_x11->is_attached)
|
||||
{
|
||||
gboolean do_frame_sync = FALSE;
|
||||
|
||||
/* 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
|
||||
* to the vblank. */
|
||||
do_frame_sync = ! gdk_display_is_composited (display);
|
||||
|
||||
if (do_frame_sync != context_x11->do_frame_sync)
|
||||
{
|
||||
context_x11->do_frame_sync = do_frame_sync;
|
||||
|
||||
if (do_frame_sync)
|
||||
eglSwapInterval (egl_display, 1);
|
||||
else
|
||||
eglSwapInterval (egl_display, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_x11_display_get_egl_version:
|
||||
* @display: (type GdkX11Display): a #GdkDisplay
|
||||
* @major: (out): return location for the EGL major version
|
||||
* @minor: (out): return location for the EGL minor version
|
||||
*
|
||||
* Retrieves the version of the EGL implementation.
|
||||
*
|
||||
* Returns: %TRUE if EGL is available
|
||||
*
|
||||
* Since: 4.4
|
||||
*/
|
||||
gboolean
|
||||
gdk_x11_display_get_egl_version (GdkDisplay *display,
|
||||
int *major,
|
||||
int *minor)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
|
||||
|
||||
if (!GDK_IS_X11_DISPLAY (display))
|
||||
return FALSE;
|
||||
|
||||
GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
|
||||
|
||||
if (display_x11->have_glx)
|
||||
return FALSE;
|
||||
|
||||
if (!gdk_x11_screen_init_egl (display_x11->screen))
|
||||
return FALSE;
|
||||
|
||||
if (major != NULL)
|
||||
*major = display_x11->egl_version / 10;
|
||||
if (minor != NULL)
|
||||
*minor = display_x11->egl_version % 10;
|
||||
|
||||
return TRUE;
|
||||
}
|
@ -866,7 +866,7 @@ save_cached_gl_visuals (GdkDisplay *display, int system, int rgba)
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_x11_screen_update_visuals_for_gl (GdkX11Screen *x11_screen)
|
||||
gdk_x11_screen_update_visuals_for_glx (GdkX11Screen *x11_screen)
|
||||
{
|
||||
GdkDisplay *display;
|
||||
GdkX11Display *display_x11;
|
||||
|
@ -238,6 +238,10 @@ gdk_x11_screen_init_gl (GdkX11Screen *screen)
|
||||
if (GDK_DISPLAY_DEBUG_CHECK (display, GL_DISABLE))
|
||||
return FALSE;
|
||||
|
||||
/* We favour EGL */
|
||||
if (gdk_x11_screen_init_egl (screen))
|
||||
return TRUE;
|
||||
|
||||
if (gdk_x11_screen_init_glx (screen))
|
||||
return TRUE;
|
||||
|
||||
@ -250,8 +254,8 @@ gdk_x11_surface_create_gl_context (GdkSurface *surface,
|
||||
GdkGLContext *share,
|
||||
GError **error)
|
||||
{
|
||||
GdkX11GLContext *context = NULL;
|
||||
GdkX11Display *display_x11;
|
||||
GdkX11GLContext *context;
|
||||
GdkDisplay *display;
|
||||
|
||||
display = gdk_surface_get_display (surface);
|
||||
@ -265,7 +269,9 @@ gdk_x11_surface_create_gl_context (GdkSurface *surface,
|
||||
}
|
||||
|
||||
display_x11 = GDK_X11_DISPLAY (display);
|
||||
if (display_x11->have_glx)
|
||||
if (display_x11->have_egl)
|
||||
context = gdk_x11_gl_context_egl_new (surface, attached, share, error);
|
||||
else if (display_x11->have_glx)
|
||||
context = gdk_x11_gl_context_glx_new (surface, attached, share, error);
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
@ -284,8 +290,12 @@ gdk_x11_display_make_gl_context_current (GdkDisplay *display,
|
||||
{
|
||||
GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
|
||||
|
||||
if (display_x11->have_glx)
|
||||
if (display_x11->have_egl)
|
||||
return gdk_x11_gl_context_egl_make_current (display, context);
|
||||
else if (display_x11->have_glx)
|
||||
return gdk_x11_gl_context_glx_make_current (display, context);
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -65,14 +65,7 @@ struct _GdkX11GLContextClass
|
||||
void (* bind_for_frame_fence) (GdkX11GLContext *self);
|
||||
};
|
||||
|
||||
#define GDK_TYPE_X11_GL_CONTEXT_GLX (gdk_x11_gl_context_glx_get_type())
|
||||
#define GDK_X11_GL_CONTEXT_GLX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_X11_GL_CONTEXT_GLX, GdkX11GLContextGLX))
|
||||
#define GDK_IS_X11_GL_CONTEXT_GLX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_X11_GL_CONTEXT_GLX))
|
||||
|
||||
typedef struct _GdkX11GLContextGLX GdkX11GLContextGLX;
|
||||
|
||||
gboolean gdk_x11_screen_init_gl (GdkX11Screen *screen);
|
||||
gboolean gdk_x11_screen_init_glx (GdkX11Screen *screen);
|
||||
|
||||
GdkGLContext * gdk_x11_surface_create_gl_context (GdkSurface *window,
|
||||
gboolean attached,
|
||||
@ -81,6 +74,16 @@ GdkGLContext * gdk_x11_surface_create_gl_context (GdkSurface *window,
|
||||
gboolean gdk_x11_display_make_gl_context_current (GdkDisplay *display,
|
||||
GdkGLContext *context);
|
||||
|
||||
/* GLX */
|
||||
#define GDK_TYPE_X11_GL_CONTEXT_GLX (gdk_x11_gl_context_glx_get_type())
|
||||
#define GDK_X11_GL_CONTEXT_GLX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_X11_GL_CONTEXT_GLX, GdkX11GLContextGLX))
|
||||
#define GDK_IS_X11_GL_CONTEXT_GLX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_X11_GL_CONTEXT_GLX))
|
||||
|
||||
typedef struct _GdkX11GLContextGLX GdkX11GLContextGLX;
|
||||
|
||||
gboolean gdk_x11_screen_init_glx (GdkX11Screen *screen);
|
||||
void gdk_x11_screen_update_visuals_for_glx (GdkX11Screen *screen);
|
||||
|
||||
GType gdk_x11_gl_context_glx_get_type (void) G_GNUC_CONST;
|
||||
GdkX11GLContext * gdk_x11_gl_context_glx_new (GdkSurface *surface,
|
||||
gboolean attached,
|
||||
@ -90,6 +93,22 @@ gboolean gdk_x11_gl_context_glx_make_current (GdkDisplay *
|
||||
GdkGLContext *context);
|
||||
|
||||
|
||||
/* EGL */
|
||||
#define GDK_TYPE_X11_GL_CONTEXT_EGL (gdk_x11_gl_context_egl_get_type())
|
||||
#define GDK_X11_GL_CONTEXT_EGL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_X11_GL_CONTEXT_EGL, GdkX11GLContextEGL))
|
||||
#define GDK_IS_X11_GL_CONTEXT_EGL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_X11_GL_CONTEXT_EGL))
|
||||
|
||||
typedef struct _GdkX11GLContextEGL GdkX11GLContextEGL;
|
||||
|
||||
gboolean gdk_x11_screen_init_egl (GdkX11Screen *screen);
|
||||
GType gdk_x11_gl_context_egl_get_type (void) G_GNUC_CONST;
|
||||
GdkX11GLContext * gdk_x11_gl_context_egl_new (GdkSurface *surface,
|
||||
gboolean attached,
|
||||
GdkGLContext *share,
|
||||
GError **error);
|
||||
gboolean gdk_x11_gl_context_egl_make_current (GdkDisplay *display,
|
||||
GdkGLContext *context);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_X11_GL_CONTEXT__ */
|
||||
|
@ -97,7 +97,6 @@ GdkX11Screen *_gdk_x11_screen_new (GdkDisplay *display,
|
||||
int screen_number,
|
||||
gboolean setup_display);
|
||||
|
||||
void _gdk_x11_screen_update_visuals_for_gl (GdkX11Screen *screen);
|
||||
void _gdk_x11_screen_window_manager_changed (GdkX11Screen *screen);
|
||||
void _gdk_x11_screen_size_changed (GdkX11Screen *screen,
|
||||
const XEvent *event);
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "gdkprivate-x11.h"
|
||||
#include "gdkscreen-x11.h"
|
||||
#include "gdkvisual-x11.h"
|
||||
#include "gdkglcontext-x11.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
@ -249,9 +250,10 @@ _gdk_x11_screen_init_visuals (GdkX11Screen *x11_screen,
|
||||
x11_screen->nvisuals = nvisuals;
|
||||
|
||||
/* If GL is available we want to pick better default/rgba visuals,
|
||||
as we care about glx details such as alpha/depth/stencil depth,
|
||||
stereo and double buffering */
|
||||
_gdk_x11_screen_update_visuals_for_gl (x11_screen);
|
||||
* as we care about GLX details such as alpha/depth/stencil depth,
|
||||
* stereo and double buffering
|
||||
*/
|
||||
gdk_x11_screen_update_visuals_for_glx (x11_screen);
|
||||
|
||||
if (setup_display)
|
||||
{
|
||||
|
@ -43,6 +43,10 @@ GDK_AVAILABLE_IN_ALL
|
||||
gboolean gdk_x11_display_get_glx_version (GdkDisplay *display,
|
||||
int *major,
|
||||
int *minor);
|
||||
GDK_AVAILABLE_IN_4_4
|
||||
gboolean gdk_x11_display_get_egl_version (GdkDisplay *display,
|
||||
int *major,
|
||||
int *minor);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -8,6 +8,7 @@ gdk_x11_public_sources = files([
|
||||
'gdkdevicemanager-x11.c',
|
||||
'gdkdevicemanager-xi2.c',
|
||||
'gdkdisplay-x11.c',
|
||||
'gdkglcontext-egl.c',
|
||||
'gdkglcontext-glx.c',
|
||||
'gdkglcontext-x11.c',
|
||||
'gdkkeys-x11.c',
|
||||
|
Loading…
Reference in New Issue
Block a user