gl: Make all user GdkGLContexts not attached to any window

We make user facing gl contexts not attached to a surface if possible,
or attached to dummy surfaces. This means nothing can accidentally
read/write to the toplevel back buffer.
This commit is contained in:
Alexander Larsson
2014-10-09 16:09:05 +02:00
committed by Matthias Clasen
parent 62a26eb3c8
commit 236d08c3c5
10 changed files with 162 additions and 59 deletions

View File

@ -27,15 +27,15 @@
* OpenGL drawing context. * OpenGL drawing context.
* *
* #GdkGLContexts are created for a #GdkWindow using gdk_window_create_gl_context(), and * #GdkGLContexts are created for a #GdkWindow using gdk_window_create_gl_context(), and
* the context will be tied to the native window backing that window, matching the * the context will match the GdkVisual of the window.
* GdkVisual of the window.
* *
* A #GdkGLContexts normal framebuffer draws directly on to the back buffer of the native * A #GdkGLContexts is not tied to any particulare normal
* window backing the #GdkWindow, so its not allowed to draw directly to that, as the * framebuffer. For instance, it cannot draw to the #GdkWindow back
* gdk repaint system is in full control of that. Instead you can create render buffers * buffer. The gdk repaint system is in full control of the painting
* or textures and use gdk_cairo_draw_from_gl() in the draw function of your widget * to that. Instead you can create render buffers or textures and use
* to draw them. Then Gdk will handle the integration of your rendering with that of * gdk_cairo_draw_from_gl() in the draw function of your widget to
* other widgets. * draw them. Then Gdk will handle the integration of your rendering
* with that of other widgets.
* *
* Support for #GdkGLContext is platform specific, context creation can fail, returning * Support for #GdkGLContext is platform specific, context creation can fail, returning
* a %NULL context. * a %NULL context.

View File

@ -2725,6 +2725,7 @@ gdk_window_get_paint_gl_context (GdkWindow *window, GError **error)
if (window->impl_window->gl_paint_context == NULL) if (window->impl_window->gl_paint_context == NULL)
window->impl_window->gl_paint_context = window->impl_window->gl_paint_context =
GDK_WINDOW_IMPL_GET_CLASS (window->impl)->create_gl_context (window, GDK_WINDOW_IMPL_GET_CLASS (window->impl)->create_gl_context (window,
TRUE,
GDK_GL_PROFILE_DEFAULT, GDK_GL_PROFILE_DEFAULT,
NULL, NULL,
error); error);
@ -2738,8 +2739,9 @@ gdk_window_get_paint_gl_context (GdkWindow *window, GError **error)
* @profile: the GL profile the context should target * @profile: the GL profile the context should target
* @error: return location for an error * @error: return location for an error
* *
* Creates a new #GdkGLContext for the given window, matching the * Creates a new #GdkGLContext matching the
* framebuffer format to the visual of the #GdkWindow. * framebuffer format to the visual of the #GdkWindow. The context
* is disconnected from any particular window or surface.
* *
* If the creation of the #GdkGLContext failed, @error will be set. * If the creation of the #GdkGLContext failed, @error will be set.
* *
@ -2763,6 +2765,7 @@ gdk_window_create_gl_context (GdkWindow *window,
return NULL; return NULL;
return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->create_gl_context (window, return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->create_gl_context (window,
FALSE,
profile, profile,
paint_context, paint_context,
error); error);

View File

@ -290,6 +290,7 @@ struct _GdkWindowImplClass
gboolean (* show_window_menu) (GdkWindow *window, gboolean (* show_window_menu) (GdkWindow *window,
GdkEvent *event); GdkEvent *event);
GdkGLContext *(*create_gl_context) (GdkWindow *window, GdkGLContext *(*create_gl_context) (GdkWindow *window,
gboolean attached,
GdkGLProfile profile, GdkGLProfile profile,
GdkGLContext *share, GdkGLContext *share,
GError **error); GError **error);

View File

@ -89,6 +89,7 @@ struct _GdkWaylandDisplay
guint have_egl_khr_create_context : 1; guint have_egl_khr_create_context : 1;
guint have_egl_buffer_age : 1; guint have_egl_buffer_age : 1;
guint have_egl_swap_buffers_with_damage : 1; guint have_egl_swap_buffers_with_damage : 1;
guint have_egl_surfaceless_context : 1;
}; };
struct _GdkWaylandDisplayClass struct _GdkWaylandDisplayClass

View File

@ -76,7 +76,8 @@ gdk_wayland_window_invalidate_for_new_frame (GdkWindow *window,
egl_surface = gdk_wayland_window_get_egl_surface (window->impl_window, egl_surface = gdk_wayland_window_get_egl_surface (window->impl_window,
context_wayland->egl_config); context_wayland->egl_config);
if (display_wayland->have_egl_buffer_age) if (display_wayland->have_egl_buffer_age &&
gdk_gl_context_make_current (window->gl_paint_context))
eglQuerySurface (display_wayland->egl_display, egl_surface, eglQuerySurface (display_wayland->egl_display, egl_surface,
EGL_BUFFER_AGE_EXT, &buffer_age); EGL_BUFFER_AGE_EXT, &buffer_age);
@ -203,6 +204,9 @@ gdk_wayland_display_init_gl (GdkDisplay *display)
display_wayland->have_egl_swap_buffers_with_damage = display_wayland->have_egl_swap_buffers_with_damage =
epoxy_has_egl_extension (dpy, "EGL_EXT_swap_buffers_with_damage"); epoxy_has_egl_extension (dpy, "EGL_EXT_swap_buffers_with_damage");
display_wayland->have_egl_surfaceless_context =
epoxy_has_egl_extension (dpy, "EGL_KHR_surfaceless_context");
GDK_NOTE (OPENGL, GDK_NOTE (OPENGL,
g_print ("EGL API version %d.%d found\n" g_print ("EGL API version %d.%d found\n"
" - Vendor: %s\n" " - Vendor: %s\n"
@ -297,6 +301,7 @@ find_eglconfig_for_window (GdkWindow *window,
GdkGLContext * GdkGLContext *
gdk_wayland_window_create_gl_context (GdkWindow *window, gdk_wayland_window_create_gl_context (GdkWindow *window,
gboolean attached,
GdkGLProfile profile, GdkGLProfile profile,
GdkGLContext *share, GdkGLContext *share,
GError **error) GError **error)
@ -359,6 +364,7 @@ gdk_wayland_window_create_gl_context (GdkWindow *window,
context->egl_config = config; context->egl_config = config;
context->egl_context = ctx; context->egl_context = ctx;
context->is_attached = attached;
return GDK_GL_CONTEXT (context); return GDK_GL_CONTEXT (context);
} }
@ -404,7 +410,16 @@ gdk_wayland_display_make_gl_context_current (GdkDisplay *display,
context_wayland = GDK_WAYLAND_GL_CONTEXT (context); context_wayland = GDK_WAYLAND_GL_CONTEXT (context);
window = gdk_gl_context_get_window (context); window = gdk_gl_context_get_window (context);
egl_surface = gdk_wayland_window_get_egl_surface (window->impl_window, context_wayland->egl_config); if (context_wayland->is_attached)
egl_surface = gdk_wayland_window_get_egl_surface (window->impl_window, context_wayland->egl_config);
else
{
if (display_wayland->have_egl_surfaceless_context)
egl_surface = EGL_NO_SURFACE;
else
egl_surface = gdk_wayland_window_get_dummy_egl_surface (window->impl_window,
context_wayland->egl_config);
}
if (!eglMakeCurrent(display_wayland->egl_display, egl_surface, if (!eglMakeCurrent(display_wayland->egl_display, egl_surface,
egl_surface, context_wayland->egl_context)) egl_surface, context_wayland->egl_context))

View File

@ -39,6 +39,7 @@ struct _GdkWaylandGLContext
EGLContext egl_context; EGLContext egl_context;
EGLConfig egl_config; EGLConfig egl_config;
gboolean is_attached;
}; };
struct _GdkWaylandGLContextClass struct _GdkWaylandGLContextClass
@ -48,6 +49,7 @@ struct _GdkWaylandGLContextClass
gboolean gdk_wayland_display_init_gl (GdkDisplay *display); gboolean gdk_wayland_display_init_gl (GdkDisplay *display);
GdkGLContext * gdk_wayland_window_create_gl_context (GdkWindow *window, GdkGLContext * gdk_wayland_window_create_gl_context (GdkWindow *window,
gboolean attach,
GdkGLProfile profile, GdkGLProfile profile,
GdkGLContext *share, GdkGLContext *share,
GError **error); GError **error);

View File

@ -239,5 +239,7 @@ void gdk_wayland_selection_unset_data_source (GdkAtom selection);
EGLSurface gdk_wayland_window_get_egl_surface (GdkWindow *window, EGLSurface gdk_wayland_window_get_egl_surface (GdkWindow *window,
EGLConfig config); EGLConfig config);
EGLSurface gdk_wayland_window_get_dummy_egl_surface (GdkWindow *window,
EGLConfig config);
#endif /* __GDK_PRIVATE_WAYLAND_H__ */ #endif /* __GDK_PRIVATE_WAYLAND_H__ */

View File

@ -101,6 +101,9 @@ struct _GdkWindowImplWayland
struct wl_egl_window *egl_window; struct wl_egl_window *egl_window;
EGLSurface egl_surface; EGLSurface egl_surface;
struct wl_egl_window *dummy_egl_window;
EGLSurface dummy_egl_surface;
unsigned int mapped : 1; unsigned int mapped : 1;
unsigned int use_custom_surface : 1; unsigned int use_custom_surface : 1;
unsigned int pending_commit : 1; unsigned int pending_commit : 1;
@ -1171,6 +1174,18 @@ gdk_wayland_window_hide_surface (GdkWindow *window)
if (impl->surface) if (impl->surface)
{ {
if (impl->dummy_egl_surface)
{
eglDestroySurface(display_wayland->egl_display, impl->dummy_egl_surface);
impl->dummy_egl_surface = NULL;
}
if (impl->dummy_egl_window)
{
wl_egl_window_destroy (impl->dummy_egl_window);
impl->dummy_egl_window = NULL;
}
if (impl->egl_surface) if (impl->egl_surface)
{ {
eglDestroySurface(display_wayland->egl_display, impl->egl_surface); eglDestroySurface(display_wayland->egl_display, impl->egl_surface);
@ -2238,6 +2253,32 @@ gdk_wayland_window_get_egl_surface (GdkWindow *window,
return impl->egl_surface; return impl->egl_surface;
} }
EGLSurface
gdk_wayland_window_get_dummy_egl_surface (GdkWindow *window,
EGLConfig config)
{
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
GdkWindowImplWayland *impl;
struct wl_egl_window *egl_window;
g_return_val_if_fail (GDK_IS_WAYLAND_WINDOW (window), NULL);
impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
if (impl->dummy_egl_surface == NULL)
{
impl->dummy_egl_window =
wl_egl_window_create (impl->surface, 1, 1);
impl->dummy_egl_surface =
eglCreateWindowSurface (display_wayland->egl_display,
config, impl->dummy_egl_window, NULL);
}
return impl->dummy_egl_surface;
}
/** /**
* gdk_wayland_window_set_use_custom_surface: * gdk_wayland_window_set_use_custom_surface:
* @window: (type GdkWaylandWindow): a #GdkWindow * @window: (type GdkWaylandWindow): a #GdkWindow

View File

@ -41,10 +41,12 @@
G_DEFINE_TYPE (GdkX11GLContext, gdk_x11_gl_context, GDK_TYPE_GL_CONTEXT) G_DEFINE_TYPE (GdkX11GLContext, gdk_x11_gl_context, GDK_TYPE_GL_CONTEXT)
typedef struct { typedef struct {
GLXDrawable drawable;
GdkDisplay *display; GdkDisplay *display;
GdkWindow *window;
GLXDrawable glx_drawable;
Window dummy_xwin;
GLXWindow dummy_glx;
guint32 last_frame_counter; guint32 last_frame_counter;
} DrawableInfo; } DrawableInfo;
@ -53,11 +55,20 @@ static void
drawable_info_free (gpointer data_) drawable_info_free (gpointer data_)
{ {
DrawableInfo *data = data_; DrawableInfo *data = data_;
Display *dpy;
gdk_x11_display_error_trap_push (data->display); gdk_x11_display_error_trap_push (data->display);
if (data->drawable) dpy = gdk_x11_display_get_xdisplay (data->display);
glXDestroyWindow (gdk_x11_display_get_xdisplay (data->display), data->drawable);
if (data->glx_drawable)
glXDestroyWindow (dpy, data->glx_drawable);
if (data->dummy_glx)
glXDestroyWindow (dpy, data->dummy_glx);
if (data->dummy_xwin)
XDestroyWindow (dpy, data->dummy_xwin);
gdk_x11_display_error_trap_pop_ignored (data->display); gdk_x11_display_error_trap_pop_ignored (data->display);
@ -144,9 +155,10 @@ gdk_x11_window_invalidate_for_new_frame (GdkWindow *window,
buffer_age = 0; buffer_age = 0;
if (display_x11->has_glx_buffer_age) if (display_x11->has_glx_buffer_age &&
gdk_gl_context_make_current (window->gl_paint_context))
glXQueryDrawable(dpy, context_x11->drawable, glXQueryDrawable(dpy, context_x11->drawable,
GLX_BACK_BUFFER_AGE_EXT, &buffer_age); GLX_BACK_BUFFER_AGE_EXT, &buffer_age);
invalidate_all = FALSE; invalidate_all = FALSE;
if (buffer_age == 0 || buffer_age >= 4) if (buffer_age == 0 || buffer_age >= 4)
@ -500,14 +512,13 @@ gdk_x11_display_init_gl (GdkDisplay *display)
#define MAX_GLX_ATTRS 30 #define MAX_GLX_ATTRS 30
static gboolean static gboolean
find_fbconfig_for_window (GdkWindow *window, find_fbconfig_for_visual (GdkDisplay *display,
GdkVisual *visual,
GLXFBConfig *fb_config_out, GLXFBConfig *fb_config_out,
XVisualInfo **visinfo_out, XVisualInfo **visinfo_out,
GError **error) GError **error)
{ {
static int attrs[MAX_GLX_ATTRS]; static int attrs[MAX_GLX_ATTRS];
GdkVisual *visual = gdk_window_get_visual (window);
GdkDisplay *display = gdk_window_get_display (window);
Display *dpy = gdk_x11_display_get_xdisplay (display); Display *dpy = gdk_x11_display_get_xdisplay (display);
GLXFBConfig *configs; GLXFBConfig *configs;
int n_configs, i; int n_configs, i;
@ -650,12 +661,14 @@ create_gl_context (GdkDisplay *display,
GdkGLContext * GdkGLContext *
gdk_x11_window_create_gl_context (GdkWindow *window, gdk_x11_window_create_gl_context (GdkWindow *window,
GdkGLProfile profile, gboolean attached,
GdkGLContext *share, GdkGLProfile profile,
GError **error) GdkGLContext *share,
GError **error)
{ {
GdkDisplay *display = gdk_window_get_display (window); GdkDisplay *display;
GdkX11GLContext *context; GdkX11GLContext *context;
GdkVisual *visual;
GdkVisual *gdk_visual; GdkVisual *gdk_visual;
GLXFBConfig config; GLXFBConfig config;
GLXContext glx_context; GLXContext glx_context;
@ -665,6 +678,8 @@ gdk_x11_window_create_gl_context (GdkWindow *window,
Display *dpy; Display *dpy;
DrawableInfo *info; DrawableInfo *info;
display = gdk_window_get_display (window);
if (!gdk_x11_display_init_gl (display)) if (!gdk_x11_display_init_gl (display))
{ {
g_set_error_literal (error, GDK_GL_ERROR, g_set_error_literal (error, GDK_GL_ERROR,
@ -684,7 +699,9 @@ gdk_x11_window_create_gl_context (GdkWindow *window,
return NULL; return NULL;
} }
if (!find_fbconfig_for_window (window, &config, &xvisinfo, error)) visual = gdk_window_get_visual (window);
if (!find_fbconfig_for_visual (display, visual, &config, &xvisinfo, error))
return NULL; return NULL;
dpy = gdk_x11_display_get_xdisplay (display); dpy = gdk_x11_display_get_xdisplay (display);
@ -712,31 +729,53 @@ gdk_x11_window_create_gl_context (GdkWindow *window,
is_direct = glXIsDirect (dpy, glx_context); is_direct = glXIsDirect (dpy, glx_context);
gdk_x11_display_error_trap_push (display); info = get_glx_drawable_info (window->impl_window);
if (info == NULL)
if (GDK_X11_DISPLAY (display)->glx_version >= 13)
{ {
info = get_glx_drawable_info (window->impl_window); XSetWindowAttributes attrs;
unsigned long mask;
if (info == NULL) gdk_x11_display_error_trap_push (display);
{
info = g_slice_new (DrawableInfo);
info->window = window->impl_window;
info->display = display;
info->drawable = glXCreateWindow (dpy,
config,
gdk_x11_window_get_xid (window->impl_window),
NULL);
info->last_frame_counter = 0;
set_glx_drawable_info (window->impl_window, info); info = g_slice_new0 (DrawableInfo);
} info->display = display;
info->last_frame_counter = 0;
drawable = info->drawable; attrs.override_redirect = True;
} attrs.colormap = XCreateColormap (dpy, DefaultRootWindow (dpy), xvisinfo->visual, AllocNone);
else attrs.border_pixel = 0;
{ mask = CWOverrideRedirect | CWColormap | CWBorderPixel;
drawable = gdk_x11_window_get_xid (window); info->dummy_xwin = XCreateWindow (dpy, DefaultRootWindow (dpy),
-100, -100, 1, 1,
0,
xvisinfo->depth,
CopyFromParent,
xvisinfo->visual,
mask,
&attrs);
XMapWindow(dpy, info->dummy_xwin);
if (GDK_X11_DISPLAY (display)->glx_version >= 13)
{
info->glx_drawable = glXCreateWindow (dpy, config,
gdk_x11_window_get_xid (window->impl_window),
NULL);
info->dummy_glx = glXCreateWindow (dpy, config, info->dummy_xwin, NULL);
}
if (gdk_x11_display_error_trap_pop (display))
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("Unable to create a GL context"));
drawable_info_free (info);
glXDestroyContext (dpy, glx_context);
return NULL;
}
set_glx_drawable_info (window->impl_window, info);
} }
gdk_visual = gdk_x11_screen_lookup_visual (gdk_display_get_default_screen (display), gdk_visual = gdk_x11_screen_lookup_visual (gdk_display_get_default_screen (display),
@ -744,16 +783,10 @@ gdk_x11_window_create_gl_context (GdkWindow *window,
XFree (xvisinfo); XFree (xvisinfo);
if (gdk_x11_display_error_trap_pop (display)) if (attached)
{ drawable = info->glx_drawable ? info->glx_drawable : gdk_x11_window_get_xid (window->impl_window);
g_set_error_literal (error, GDK_GL_ERROR, else
GDK_GL_ERROR_NOT_AVAILABLE, drawable = info->dummy_glx ? info->dummy_glx : info->dummy_xwin;
_("Unable to create a GL context"));
glXDestroyContext (dpy, glx_context);
return NULL;
}
GDK_NOTE (OPENGL, GDK_NOTE (OPENGL,
g_print ("Created GLX context[%p], %s\n", g_print ("Created GLX context[%p], %s\n",
@ -765,9 +798,11 @@ gdk_x11_window_create_gl_context (GdkWindow *window,
"visual", gdk_visual, "visual", gdk_visual,
NULL); NULL);
context->profile = profile;
context->glx_config = config; context->glx_config = config;
context->glx_context = glx_context; context->glx_context = glx_context;
context->drawable = drawable; context->drawable = drawable;
context->is_attached = attached;
context->is_direct = is_direct; context->is_direct = is_direct;
return GDK_GL_CONTEXT (context); return GDK_GL_CONTEXT (context);
@ -832,7 +867,7 @@ gdk_x11_display_make_gl_context_current (GdkDisplay *display,
glXMakeContextCurrent (dpy, context_x11->drawable, context_x11->drawable, glXMakeContextCurrent (dpy, context_x11->drawable, context_x11->drawable,
context_x11->glx_context); context_x11->glx_context);
if (GDK_X11_DISPLAY (display)->has_glx_swap_interval) if (context_x11->is_attached && GDK_X11_DISPLAY (display)->has_glx_swap_interval)
{ {
if (context_x11->do_frame_sync) if (context_x11->do_frame_sync)
glXSwapIntervalSGI (1); glXSwapIntervalSGI (1);

View File

@ -40,10 +40,12 @@ struct _GdkX11GLContext
{ {
GdkGLContext parent_instance; GdkGLContext parent_instance;
GdkGLProfile profile;
GLXContext glx_context; GLXContext glx_context;
GLXFBConfig glx_config; GLXFBConfig glx_config;
GLXDrawable drawable; GLXDrawable drawable;
guint is_attached : 1;
guint is_direct : 1; guint is_direct : 1;
guint do_frame_sync : 1; guint do_frame_sync : 1;
@ -56,6 +58,7 @@ struct _GdkX11GLContextClass
gboolean gdk_x11_display_init_gl (GdkDisplay *display); gboolean gdk_x11_display_init_gl (GdkDisplay *display);
GdkGLContext * gdk_x11_window_create_gl_context (GdkWindow *window, GdkGLContext * gdk_x11_window_create_gl_context (GdkWindow *window,
gboolean attached,
GdkGLProfile profile, GdkGLProfile profile,
GdkGLContext *share, GdkGLContext *share,
GError **error); GError **error);