[gtk+] gl: Make all user GdkGLContexts not attached to any window
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] gl: Make all user GdkGLContexts not attached to any window
- Date: Mon, 13 Oct 2014 14:45:54 +0000 (UTC)
commit 236d08c3c59a33e1ec4004af0aa4f6095402809a
Author: Alexander Larsson <alexl redhat com>
Date: Thu Oct 9 16:09:05 2014 +0200
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.
gdk/gdkglcontext.c | 18 +++---
gdk/gdkwindow.c | 7 ++-
gdk/gdkwindowimpl.h | 1 +
gdk/wayland/gdkdisplay-wayland.h | 1 +
gdk/wayland/gdkglcontext-wayland.c | 19 +++++-
gdk/wayland/gdkglcontext-wayland.h | 2 +
gdk/wayland/gdkprivate-wayland.h | 2 +
gdk/wayland/gdkwindow-wayland.c | 41 +++++++++++
gdk/x11/gdkglcontext-x11.c | 131 +++++++++++++++++++++++-------------
gdk/x11/gdkglcontext-x11.h | 3 +
10 files changed, 164 insertions(+), 61 deletions(-)
---
diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c
index 58eaa0a..9a5f457 100644
--- a/gdk/gdkglcontext.c
+++ b/gdk/gdkglcontext.c
@@ -27,15 +27,15 @@
* OpenGL drawing context.
*
* #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
- * GdkVisual of the window.
- *
- * A #GdkGLContexts normal framebuffer draws directly on to the back buffer of the native
- * window backing the #GdkWindow, so its not allowed to draw directly to that, as the
- * gdk repaint system is in full control of that. Instead you can create render buffers
- * or textures and use gdk_cairo_draw_from_gl() in the draw function of your widget
- * to draw them. Then Gdk will handle the integration of your rendering with that of
- * other widgets.
+ * the context will match the GdkVisual of the window.
+ *
+ * A #GdkGLContexts is not tied to any particulare normal
+ * framebuffer. For instance, it cannot draw to the #GdkWindow back
+ * buffer. The gdk repaint system is in full control of the painting
+ * to that. Instead you can create render buffers or textures and use
+ * gdk_cairo_draw_from_gl() in the draw function of your widget to
+ * 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
* a %NULL context.
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index a737254..21eddf0 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -2725,6 +2725,7 @@ gdk_window_get_paint_gl_context (GdkWindow *window, GError **error)
if (window->impl_window->gl_paint_context == NULL)
window->impl_window->gl_paint_context =
GDK_WINDOW_IMPL_GET_CLASS (window->impl)->create_gl_context (window,
+ TRUE,
GDK_GL_PROFILE_DEFAULT,
NULL,
error);
@@ -2738,8 +2739,9 @@ gdk_window_get_paint_gl_context (GdkWindow *window, GError **error)
* @profile: the GL profile the context should target
* @error: return location for an error
*
- * Creates a new #GdkGLContext for the given window, matching the
- * framebuffer format to the visual of the #GdkWindow.
+ * Creates a new #GdkGLContext matching the
+ * 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.
*
@@ -2763,6 +2765,7 @@ gdk_window_create_gl_context (GdkWindow *window,
return NULL;
return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->create_gl_context (window,
+ FALSE,
profile,
paint_context,
error);
diff --git a/gdk/gdkwindowimpl.h b/gdk/gdkwindowimpl.h
index f6e9a63..2c1bc1e 100644
--- a/gdk/gdkwindowimpl.h
+++ b/gdk/gdkwindowimpl.h
@@ -290,6 +290,7 @@ struct _GdkWindowImplClass
gboolean (* show_window_menu) (GdkWindow *window,
GdkEvent *event);
GdkGLContext *(*create_gl_context) (GdkWindow *window,
+ gboolean attached,
GdkGLProfile profile,
GdkGLContext *share,
GError **error);
diff --git a/gdk/wayland/gdkdisplay-wayland.h b/gdk/wayland/gdkdisplay-wayland.h
index daa8baf..3bad519 100644
--- a/gdk/wayland/gdkdisplay-wayland.h
+++ b/gdk/wayland/gdkdisplay-wayland.h
@@ -89,6 +89,7 @@ struct _GdkWaylandDisplay
guint have_egl_khr_create_context : 1;
guint have_egl_buffer_age : 1;
guint have_egl_swap_buffers_with_damage : 1;
+ guint have_egl_surfaceless_context : 1;
};
struct _GdkWaylandDisplayClass
diff --git a/gdk/wayland/gdkglcontext-wayland.c b/gdk/wayland/gdkglcontext-wayland.c
index 5ddcdcd..b6f1e99 100644
--- a/gdk/wayland/gdkglcontext-wayland.c
+++ b/gdk/wayland/gdkglcontext-wayland.c
@@ -76,7 +76,8 @@ gdk_wayland_window_invalidate_for_new_frame (GdkWindow *window,
egl_surface = gdk_wayland_window_get_egl_surface (window->impl_window,
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,
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 =
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,
g_print ("EGL API version %d.%d found\n"
" - Vendor: %s\n"
@@ -297,6 +301,7 @@ find_eglconfig_for_window (GdkWindow *window,
GdkGLContext *
gdk_wayland_window_create_gl_context (GdkWindow *window,
+ gboolean attached,
GdkGLProfile profile,
GdkGLContext *share,
GError **error)
@@ -359,6 +364,7 @@ gdk_wayland_window_create_gl_context (GdkWindow *window,
context->egl_config = config;
context->egl_context = ctx;
+ context->is_attached = attached;
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);
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,
egl_surface, context_wayland->egl_context))
diff --git a/gdk/wayland/gdkglcontext-wayland.h b/gdk/wayland/gdkglcontext-wayland.h
index 475a28b..3d4fe37 100644
--- a/gdk/wayland/gdkglcontext-wayland.h
+++ b/gdk/wayland/gdkglcontext-wayland.h
@@ -39,6 +39,7 @@ struct _GdkWaylandGLContext
EGLContext egl_context;
EGLConfig egl_config;
+ gboolean is_attached;
};
struct _GdkWaylandGLContextClass
@@ -48,6 +49,7 @@ struct _GdkWaylandGLContextClass
gboolean gdk_wayland_display_init_gl (GdkDisplay *display);
GdkGLContext * gdk_wayland_window_create_gl_context (GdkWindow *window,
+ gboolean attach,
GdkGLProfile profile,
GdkGLContext *share,
GError **error);
diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h
index b72b359..4f6f15b 100644
--- a/gdk/wayland/gdkprivate-wayland.h
+++ b/gdk/wayland/gdkprivate-wayland.h
@@ -239,5 +239,7 @@ void gdk_wayland_selection_unset_data_source (GdkAtom selection);
EGLSurface gdk_wayland_window_get_egl_surface (GdkWindow *window,
EGLConfig config);
+EGLSurface gdk_wayland_window_get_dummy_egl_surface (GdkWindow *window,
+ EGLConfig config);
#endif /* __GDK_PRIVATE_WAYLAND_H__ */
diff --git a/gdk/wayland/gdkwindow-wayland.c b/gdk/wayland/gdkwindow-wayland.c
index 90d75ef..828cd57 100644
--- a/gdk/wayland/gdkwindow-wayland.c
+++ b/gdk/wayland/gdkwindow-wayland.c
@@ -101,6 +101,9 @@ struct _GdkWindowImplWayland
struct wl_egl_window *egl_window;
EGLSurface egl_surface;
+ struct wl_egl_window *dummy_egl_window;
+ EGLSurface dummy_egl_surface;
+
unsigned int mapped : 1;
unsigned int use_custom_surface : 1;
unsigned int pending_commit : 1;
@@ -1171,6 +1174,18 @@ gdk_wayland_window_hide_surface (GdkWindow *window)
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)
{
eglDestroySurface(display_wayland->egl_display, impl->egl_surface);
@@ -2238,6 +2253,32 @@ gdk_wayland_window_get_egl_surface (GdkWindow *window,
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:
* @window: (type GdkWaylandWindow): a #GdkWindow
diff --git a/gdk/x11/gdkglcontext-x11.c b/gdk/x11/gdkglcontext-x11.c
index 70ff6a3..b4e4e57 100644
--- a/gdk/x11/gdkglcontext-x11.c
+++ b/gdk/x11/gdkglcontext-x11.c
@@ -41,10 +41,12 @@
G_DEFINE_TYPE (GdkX11GLContext, gdk_x11_gl_context, GDK_TYPE_GL_CONTEXT)
typedef struct {
- GLXDrawable drawable;
-
GdkDisplay *display;
- GdkWindow *window;
+
+ GLXDrawable glx_drawable;
+
+ Window dummy_xwin;
+ GLXWindow dummy_glx;
guint32 last_frame_counter;
} DrawableInfo;
@@ -53,11 +55,20 @@ static void
drawable_info_free (gpointer data_)
{
DrawableInfo *data = data_;
+ Display *dpy;
gdk_x11_display_error_trap_push (data->display);
- if (data->drawable)
- glXDestroyWindow (gdk_x11_display_get_xdisplay (data->display), data->drawable);
+ dpy = gdk_x11_display_get_xdisplay (data->display);
+
+ 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);
@@ -144,9 +155,10 @@ gdk_x11_window_invalidate_for_new_frame (GdkWindow *window,
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,
- GLX_BACK_BUFFER_AGE_EXT, &buffer_age);
+ GLX_BACK_BUFFER_AGE_EXT, &buffer_age);
invalidate_all = FALSE;
if (buffer_age == 0 || buffer_age >= 4)
@@ -500,14 +512,13 @@ gdk_x11_display_init_gl (GdkDisplay *display)
#define MAX_GLX_ATTRS 30
static gboolean
-find_fbconfig_for_window (GdkWindow *window,
+find_fbconfig_for_visual (GdkDisplay *display,
+ GdkVisual *visual,
GLXFBConfig *fb_config_out,
XVisualInfo **visinfo_out,
GError **error)
{
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);
GLXFBConfig *configs;
int n_configs, i;
@@ -650,12 +661,14 @@ create_gl_context (GdkDisplay *display,
GdkGLContext *
gdk_x11_window_create_gl_context (GdkWindow *window,
- GdkGLProfile profile,
- GdkGLContext *share,
- GError **error)
+ gboolean attached,
+ GdkGLProfile profile,
+ GdkGLContext *share,
+ GError **error)
{
- GdkDisplay *display = gdk_window_get_display (window);
+ GdkDisplay *display;
GdkX11GLContext *context;
+ GdkVisual *visual;
GdkVisual *gdk_visual;
GLXFBConfig config;
GLXContext glx_context;
@@ -665,6 +678,8 @@ gdk_x11_window_create_gl_context (GdkWindow *window,
Display *dpy;
DrawableInfo *info;
+ display = gdk_window_get_display (window);
+
if (!gdk_x11_display_init_gl (display))
{
g_set_error_literal (error, GDK_GL_ERROR,
@@ -684,7 +699,9 @@ gdk_x11_window_create_gl_context (GdkWindow *window,
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;
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);
- gdk_x11_display_error_trap_push (display);
-
- if (GDK_X11_DISPLAY (display)->glx_version >= 13)
+ info = get_glx_drawable_info (window->impl_window);
+ if (info == NULL)
{
- info = get_glx_drawable_info (window->impl_window);
+ XSetWindowAttributes attrs;
+ unsigned long mask;
- if (info == NULL)
- {
- 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);
- }
+ gdk_x11_display_error_trap_push (display);
+
+ info = g_slice_new0 (DrawableInfo);
+ info->display = display;
+ info->last_frame_counter = 0;
+
+ attrs.override_redirect = True;
+ attrs.colormap = XCreateColormap (dpy, DefaultRootWindow (dpy), xvisinfo->visual, AllocNone);
+ attrs.border_pixel = 0;
+ mask = CWOverrideRedirect | CWColormap | CWBorderPixel;
+ 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);
+ }
- drawable = info->drawable;
- }
- else
- {
- drawable = gdk_x11_window_get_xid (window);
+ 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),
@@ -744,16 +783,10 @@ gdk_x11_window_create_gl_context (GdkWindow *window,
XFree (xvisinfo);
- 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"));
-
- glXDestroyContext (dpy, glx_context);
-
- return NULL;
- }
+ if (attached)
+ drawable = info->glx_drawable ? info->glx_drawable : gdk_x11_window_get_xid (window->impl_window);
+ else
+ drawable = info->dummy_glx ? info->dummy_glx : info->dummy_xwin;
GDK_NOTE (OPENGL,
g_print ("Created GLX context[%p], %s\n",
@@ -765,9 +798,11 @@ gdk_x11_window_create_gl_context (GdkWindow *window,
"visual", gdk_visual,
NULL);
+ context->profile = profile;
context->glx_config = config;
context->glx_context = glx_context;
context->drawable = drawable;
+ context->is_attached = attached;
context->is_direct = is_direct;
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,
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)
glXSwapIntervalSGI (1);
diff --git a/gdk/x11/gdkglcontext-x11.h b/gdk/x11/gdkglcontext-x11.h
index 9f7566c..091783e 100644
--- a/gdk/x11/gdkglcontext-x11.h
+++ b/gdk/x11/gdkglcontext-x11.h
@@ -40,10 +40,12 @@ struct _GdkX11GLContext
{
GdkGLContext parent_instance;
+ GdkGLProfile profile;
GLXContext glx_context;
GLXFBConfig glx_config;
GLXDrawable drawable;
+ guint is_attached : 1;
guint is_direct : 1;
guint do_frame_sync : 1;
@@ -56,6 +58,7 @@ struct _GdkX11GLContextClass
gboolean gdk_x11_display_init_gl (GdkDisplay *display);
GdkGLContext * gdk_x11_window_create_gl_context (GdkWindow *window,
+ gboolean attached,
GdkGLProfile profile,
GdkGLContext *share,
GError **error);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]