summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@gmail.com>2016-01-11 11:57:41 +0100
committerMarc-André Lureau <marcandre.lureau@gmail.com>2016-03-14 13:48:48 +0100
commit6d8ca210d89e4dc7bed90534e91e1c3650e00d2a (patch)
tree935b1a3d67f046588116560175d1e3b0818897ac
parent2cb74f4ac1fc5c3601cbc780f7eefa6e867ba4d2 (diff)
downloadspice-gtk-6d8ca210d89e4dc7bed90534e91e1c3650e00d2a.tar.gz
spice-gtk-6d8ca210d89e4dc7bed90534e91e1c3650e00d2a.tar.xz
spice-gtk-6d8ca210d89e4dc7bed90534e91e1c3650e00d2a.zip
gtk: add GtkGLArea
GtkGLArea is the proper modern way to have opengl in an gtk+ application. Unfortunately, it may use various backends and interfaces to initialize it, but dmabuf image sharing requires egl atm. This patch keeps using our egl setup on X11, while it uses gtkglarea on known gdk backend based on egl, such as the wayland one. This brings wayland support for local gl to spice-gtk. Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com> Acked-by: Fabiano Fidêncio <fidencio@redhat.com>
-rw-r--r--src/spice-widget-egl.c9
-rw-r--r--src/spice-widget-priv.h1
-rw-r--r--src/spice-widget.c79
3 files changed, 81 insertions, 8 deletions
diff --git a/src/spice-widget-egl.c b/src/spice-widget-egl.c
index 1748189..1b3cd07 100644
--- a/src/spice-widget-egl.c
+++ b/src/spice-widget-egl.c
@@ -29,6 +29,7 @@
#include <libdrm/drm_fourcc.h>
#include <gdk/gdkx.h>
+#include <gdk/gdkwayland.h>
#define VERTS_ARRAY_SIZE (sizeof(GLfloat) * 4 * 4)
#define TEX_ARRAY_SIZE (sizeof(GLfloat) * 4 * 2)
@@ -200,6 +201,14 @@ gboolean spice_egl_init(SpiceDisplay *display, GError **err)
EGLNativeDisplayType dpy = 0;
GdkDisplay *gdk_dpy = gdk_display_get_default();
+#ifdef GDK_WINDOWING_WAYLAND
+ if (GDK_IS_WAYLAND_DISPLAY(gdk_dpy)) {
+ d->egl.ctx = eglGetCurrentContext();
+ dpy = (EGLNativeDisplayType)gdk_wayland_display_get_wl_display(gdk_dpy);
+ d->egl.display = eglGetDisplay(dpy);
+ return spice_egl_init_shaders(display, err);
+ }
+#endif
#ifdef GDK_WINDOWING_X11
if (GDK_IS_X11_DISPLAY(gdk_dpy)) {
dpy = (EGLNativeDisplayType)gdk_x11_display_get_xdisplay(gdk_dpy);
diff --git a/src/spice-widget-priv.h b/src/spice-widget-priv.h
index cf055d3..0d1c3ae 100644
--- a/src/spice-widget-priv.h
+++ b/src/spice-widget-priv.h
@@ -137,6 +137,7 @@ struct _SpiceDisplayPrivate {
guint tex_pointer_id;
guint prog;
EGLImageKHR image;
+ gboolean call_draw_done;
SpiceGlScanout scanout;
} egl;
};
diff --git a/src/spice-widget.c b/src/spice-widget.c
index 286eeca..891f2c8 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -539,12 +539,48 @@ static void grab_notify(SpiceDisplay *display, gboolean was_grabbed)
release_keys(display);
}
+static gboolean
+gl_area_render(GtkGLArea *area, GdkGLContext *context, gpointer user_data)
+{
+ SpiceDisplay *display = SPICE_DISPLAY(user_data);
+ SpiceDisplayPrivate *d = display->priv;
+
+ spice_egl_update_display(display);
+ glFlush();
+ if (d->egl.call_draw_done) {
+ spice_display_gl_draw_done(SPICE_DISPLAY_CHANNEL(d->display));
+ d->egl.call_draw_done = FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+gl_area_realize(GtkGLArea *area, gpointer user_data)
+{
+ SpiceDisplay *display = SPICE_DISPLAY(user_data);
+ GError *err = NULL;
+
+ gtk_gl_area_make_current(area);
+ if (gtk_gl_area_get_error(area) != NULL)
+ return;
+
+ if (!spice_egl_init(display, &err)) {
+ g_critical("egl init failed: %s", err->message);
+ g_clear_error(&err);
+ }
+}
+
static void
drawing_area_realize(GtkWidget *area, gpointer user_data)
{
+#ifdef GDK_WINDOWING_X11
SpiceDisplay *display = SPICE_DISPLAY(user_data);
GError *err = NULL;
+ if (!GDK_IS_X11_DISPLAY(gdk_display_get_default()))
+ return;
+
if (!spice_egl_init(display, &err)) {
g_critical("egl init failed: %s", err->message);
g_clear_error(&err);
@@ -554,6 +590,7 @@ drawing_area_realize(GtkWidget *area, gpointer user_data)
g_critical("egl realize failed: %s", err->message);
g_clear_error(&err);
}
+#endif
}
static void spice_display_init(SpiceDisplay *display)
@@ -574,6 +611,16 @@ static void spice_display_init(SpiceDisplay *display)
gtk_widget_set_double_buffered(area, true);
gtk_stack_set_visible_child(GTK_STACK(widget), area);
+ area = gtk_gl_area_new();
+ gtk_gl_area_set_required_version(GTK_GL_AREA(area), 3, 2);
+ gtk_gl_area_set_auto_render(GTK_GL_AREA(area), false);
+ g_object_connect(area,
+ "signal::render", gl_area_render, display,
+ "signal::realize", gl_area_realize, display,
+ NULL);
+ gtk_stack_add_named(GTK_STACK(widget), area, "gl-area");
+ gtk_widget_show_all(widget);
+
g_signal_connect(display, "grab-broken-event", G_CALLBACK(grab_broken), NULL);
g_signal_connect(display, "grab-notify", G_CALLBACK(grab_notify), NULL);
@@ -1152,11 +1199,20 @@ static void set_egl_enabled(SpiceDisplay *display, bool enabled)
if (d->egl.enabled == enabled)
return;
- /* even though the function is marked as deprecated, it's the
- * only way I found to prevent glitches when the window is
- * resized. */
- area = gtk_stack_get_child_by_name(GTK_STACK(display), "draw-area");
- gtk_widget_set_double_buffered(GTK_WIDGET(area), !enabled);
+#ifdef GDK_WINDOWING_X11
+ if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
+ /* even though the function is marked as deprecated, it's the
+ * only way I found to prevent glitches when the window is
+ * resized. */
+ area = gtk_stack_get_child_by_name(GTK_STACK(display), "draw-area");
+ gtk_widget_set_double_buffered(GTK_WIDGET(area), !enabled);
+ } else
+#endif
+ {
+ area = gtk_stack_get_child_by_name(GTK_STACK(display), "gl-area");
+ gtk_stack_set_visible_child_name(GTK_STACK(display),
+ enabled ? "gl-area" : "draw-area");
+ }
if (enabled) {
spice_egl_resize_display(display, d->ww, d->wh);
@@ -1171,7 +1227,8 @@ static gboolean draw_event(GtkWidget *widget, cairo_t *cr, gpointer data)
SpiceDisplayPrivate *d = display->priv;
g_return_val_if_fail(d != NULL, false);
- if (d->egl.enabled) {
+ if (d->egl.enabled &&
+ g_str_equal(gtk_stack_get_visible_child_name(GTK_STACK(display)), "draw-area")) {
spice_egl_update_display(display);
return false;
}
@@ -2437,12 +2494,18 @@ static void gl_draw(SpiceDisplay *display,
guint32 x, guint32 y, guint32 w, guint32 h)
{
SpiceDisplayPrivate *d = display->priv;
+ GtkWidget *gl = gtk_stack_get_child_by_name(GTK_STACK(display), "gl-area");
SPICE_DEBUG("%s", __FUNCTION__);
set_egl_enabled(display, true);
- spice_egl_update_display(display);
- spice_display_gl_draw_done(SPICE_DISPLAY_CHANNEL(d->display));
+ if (gtk_stack_get_visible_child(GTK_STACK(display)) == gl) {
+ gtk_gl_area_queue_render(GTK_GL_AREA(gl));
+ d->egl.call_draw_done = TRUE;
+ } else {
+ spice_egl_update_display(display);
+ spice_display_gl_draw_done(SPICE_DISPLAY_CHANNEL(d->display));
+ }
}
static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data)