mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice-gtk
synced 2026-02-03 20:30:35 +00:00
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>
This commit is contained in:
parent
2cb74f4ac1
commit
6d8ca210d8
@ -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);
|
||||
|
||||
@ -137,6 +137,7 @@ struct _SpiceDisplayPrivate {
|
||||
guint tex_pointer_id;
|
||||
guint prog;
|
||||
EGLImageKHR image;
|
||||
gboolean call_draw_done;
|
||||
SpiceGlScanout scanout;
|
||||
} egl;
|
||||
};
|
||||
|
||||
@ -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
|
||||
drawing_area_realize(GtkWidget *area, gpointer user_data)
|
||||
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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user