[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 9/9] gtk/opengl: add opengl context and scanout supp
From: |
Gerd Hoffmann |
Subject: |
[Qemu-devel] [PATCH 9/9] gtk/opengl: add opengl context and scanout support (GtkGLArea) |
Date: |
Wed, 9 Sep 2015 13:20:54 +0200 |
This allows virtio-gpu to render in 3d mode.
Uses native opengl support which is present
in gtk versions 3.16 and newer.
Signed-off-by: Gerd Hoffmann <address@hidden>
---
configure | 8 ++
include/ui/gtk.h | 23 ++++++
ui/Makefile.objs | 5 ++
ui/gtk-gl-area.c | 219 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
ui/gtk.c | 111 +++++++++++++++++++++-------
5 files changed, 341 insertions(+), 25 deletions(-)
create mode 100644 ui/gtk-gl-area.c
diff --git a/configure b/configure
index 2d922d1..f7692d2 100755
--- a/configure
+++ b/configure
@@ -329,6 +329,7 @@ glusterfs_zerofill="no"
archipelago="no"
gtk=""
gtkabi=""
+gtk_gl="no"
gnutls=""
gnutls_hash=""
vte=""
@@ -3182,6 +3183,9 @@ if test "$opengl" != "no" ; then
opengl_cflags="$($pkg_config --cflags $opengl_pkgs) $x11_cflags"
opengl_libs="$($pkg_config --libs $opengl_pkgs) $x11_libs"
opengl=yes
+ if test "$gtk" = "yes" && $pkg_config --exists "$gtkpackage >= 3.16"; then
+ gtk_gl="yes"
+ fi
else
if test "$opengl" = "yes" ; then
feature_not_found "opengl" "Please install opengl (mesa) devel pkgs:
$opengl_pkgs"
@@ -4541,6 +4545,7 @@ fi
echo "pixman $pixman"
echo "SDL support $sdl"
echo "GTK support $gtk"
+echo "GTK GL support $gtk_gl"
echo "GNUTLS support $gnutls"
echo "GNUTLS hash $gnutls_hash"
echo "GNUTLS gcrypt $gnutls_gcrypt"
@@ -4902,6 +4907,9 @@ if test "$gtk" = "yes" ; then
echo "CONFIG_GTK=y" >> $config_host_mak
echo "CONFIG_GTKABI=$gtkabi" >> $config_host_mak
echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
+ if test "$gtk_gl" = "yes" ; then
+ echo "CONFIG_GTK_GL=y" >> $config_host_mak
+ fi
fi
if test "$gnutls" = "yes" ; then
echo "CONFIG_GNUTLS=y" >> $config_host_mak
diff --git a/include/ui/gtk.h b/include/ui/gtk.h
index 1e04c0c..76aabd0 100644
--- a/include/ui/gtk.h
+++ b/include/ui/gtk.h
@@ -112,4 +112,27 @@ void gtk_egl_init(void);
int gd_egl_make_current(DisplayChangeListener *dcl,
qemu_gl_context ctx);
+/* ui/gtk-gl-area.c */
+void gd_gl_area_init(VirtualConsole *vc);
+void gd_gl_area_draw(VirtualConsole *vc);
+void gd_gl_area_update(DisplayChangeListener *dcl,
+ int x, int y, int w, int h);
+void gd_gl_area_refresh(DisplayChangeListener *dcl);
+void gd_gl_area_switch(DisplayChangeListener *dcl,
+ DisplaySurface *surface);
+qemu_gl_context gd_gl_area_create_context(DisplayChangeListener *dcl,
+ struct qemu_gl_params *params);
+void gd_gl_area_destroy_context(DisplayChangeListener *dcl,
+ qemu_gl_context ctx);
+void gd_gl_area_scanout(DisplayChangeListener *dcl,
+ uint32_t backing_id, bool backing_y_0_top,
+ uint32_t x, uint32_t y,
+ uint32_t w, uint32_t h);
+void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
+ uint32_t x, uint32_t y, uint32_t w, uint32_t h);
+void gtk_gl_area_init(void);
+qemu_gl_context gd_gl_area_get_current_context(DisplayChangeListener *dcl);
+int gd_gl_area_make_current(DisplayChangeListener *dcl,
+ qemu_gl_context ctx);
+
#endif /* UI_GTK_H */
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index 9bc64a0..bc79bdb 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -32,11 +32,16 @@ common-obj-y += shader.o
common-obj-y += console-gl.o
common-obj-y += egl-helpers.o
common-obj-y += egl-context.o
+ifeq ($(CONFIG_GTK_GL),y)
+common-obj-$(CONFIG_GTK) += gtk-gl-area.o
+else
common-obj-$(CONFIG_GTK) += gtk-egl.o
endif
+endif
gtk.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS)
gtk-egl.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) $(OPENGL_CFLAGS)
+gtk-gl-area.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) $(OPENGL_CFLAGS)
shader.o-cflags += $(OPENGL_CFLAGS)
console-gl.o-cflags += $(OPENGL_CFLAGS)
egl-helpers.o-cflags += $(OPENGL_CFLAGS)
diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c
new file mode 100644
index 0000000..8973c36
--- /dev/null
+++ b/ui/gtk-gl-area.c
@@ -0,0 +1,219 @@
+/*
+ * GTK UI -- glarea opengl code.
+ *
+ * Requires 3.16+ (GtkGLArea widget).
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+
+#include "trace.h"
+
+#include "ui/console.h"
+#include "ui/gtk.h"
+#include "ui/egl-helpers.h"
+
+#include "sysemu/sysemu.h"
+
+static void gtk_gl_area_set_scanout_mode(VirtualConsole *vc, bool scanout)
+{
+ if (vc->gfx.scanout_mode == scanout) {
+ return;
+ }
+
+ vc->gfx.scanout_mode = scanout;
+ if (!vc->gfx.scanout_mode) {
+ if (vc->gfx.fbo_id) {
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
+ GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, 0, 0);
+ glDeleteFramebuffers(1, &vc->gfx.fbo_id);
+ vc->gfx.fbo_id = 0;
+ }
+ if (vc->gfx.surface) {
+ surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds);
+ surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds);
+ }
+ }
+}
+
+/** DisplayState Callbacks (opengl version) **/
+
+void gd_gl_area_draw(VirtualConsole *vc)
+{
+ int ww, wh, y1, y2;
+
+ if (!vc->gfx.gls) {
+ return;
+ }
+
+ gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
+ ww = gtk_widget_get_allocated_width(vc->gfx.drawing_area);
+ wh = gtk_widget_get_allocated_height(vc->gfx.drawing_area);
+
+ if (vc->gfx.scanout_mode) {
+ if (!vc->gfx.fbo_id) {
+ return;
+ }
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, vc->gfx.fbo_id);
+ /* GtkGLArea sets GL_DRAW_FRAMEBUFFER for us */
+
+ glViewport(0, 0, ww, wh);
+ y1 = vc->gfx.y0_top ? 0 : vc->gfx.h;
+ y2 = vc->gfx.y0_top ? vc->gfx.h : 0;
+ glBlitFramebuffer(0, y1, vc->gfx.w, y2,
+ 0, 0, ww, wh,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ } else {
+ if (!vc->gfx.ds) {
+ return;
+ }
+ gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
+
+ surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh);
+ surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds);
+ }
+}
+
+void gd_gl_area_update(DisplayChangeListener *dcl,
+ int x, int y, int w, int h)
+{
+ VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+
+ if (!vc->gfx.gls || !vc->gfx.ds) {
+ return;
+ }
+
+ gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
+ surface_gl_update_texture(vc->gfx.gls, vc->gfx.ds, x, y, w, h);
+ vc->gfx.glupdates++;
+}
+
+void gd_gl_area_refresh(DisplayChangeListener *dcl)
+{
+ VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+
+ if (!vc->gfx.gls) {
+ gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
+ vc->gfx.gls = console_gl_init_context();
+ if (vc->gfx.ds) {
+ surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds);
+ }
+ }
+
+ graphic_hw_update(dcl->con);
+
+ if (vc->gfx.glupdates) {
+ vc->gfx.glupdates = 0;
+ gtk_gl_area_set_scanout_mode(vc, false);
+ gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area));
+ }
+}
+
+void gd_gl_area_switch(DisplayChangeListener *dcl,
+ DisplaySurface *surface)
+{
+ VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+ bool resized = true;
+
+ trace_gd_switch(vc->label, surface_width(surface),
surface_height(surface));
+
+ if (vc->gfx.ds &&
+ surface_width(vc->gfx.ds) == surface_width(surface) &&
+ surface_height(vc->gfx.ds) == surface_height(surface)) {
+ resized = false;
+ }
+
+ if (vc->gfx.gls) {
+ gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
+ surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds);
+ surface_gl_create_texture(vc->gfx.gls, surface);
+ }
+ vc->gfx.ds = surface;
+
+ if (resized) {
+ gd_update_windowsize(vc);
+ }
+}
+
+qemu_gl_context gd_gl_area_create_context(DisplayChangeListener *dcl,
+ struct qemu_gl_params *params)
+{
+ VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+ GdkWindow *window;
+ GdkGLContext *ctx;
+ GError *err = NULL;
+
+ gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
+ window = gtk_widget_get_window(vc->gfx.drawing_area);
+ ctx = gdk_window_create_gl_context(window, &err);
+ gdk_gl_context_set_required_version(ctx,
+ params->major_ver,
+ params->minor_ver);
+ gdk_gl_context_realize(ctx, &err);
+ return ctx;
+}
+
+void gd_gl_area_destroy_context(DisplayChangeListener *dcl, qemu_gl_context
ctx)
+{
+ /* FIXME */
+}
+
+void gd_gl_area_scanout(DisplayChangeListener *dcl,
+ uint32_t backing_id, bool backing_y_0_top,
+ uint32_t x, uint32_t y,
+ uint32_t w, uint32_t h)
+{
+ VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+
+ vc->gfx.x = x;
+ vc->gfx.y = y;
+ vc->gfx.w = w;
+ vc->gfx.h = h;
+ vc->gfx.tex_id = backing_id;
+ vc->gfx.y0_top = backing_y_0_top;
+
+ gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
+
+ if (vc->gfx.tex_id == 0 || vc->gfx.w == 0 || vc->gfx.h == 0) {
+ gtk_gl_area_set_scanout_mode(vc, false);
+ return;
+ }
+
+ gtk_gl_area_set_scanout_mode(vc, true);
+ if (!vc->gfx.fbo_id) {
+ glGenFramebuffers(1, &vc->gfx.fbo_id);
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, vc->gfx.fbo_id);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, vc->gfx.tex_id, 0);
+}
+
+void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
+ uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+{
+ VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+
+ gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area));
+}
+
+void gtk_gl_area_init(void)
+{
+ display_opengl = 1;
+}
+
+qemu_gl_context gd_gl_area_get_current_context(DisplayChangeListener *dcl)
+{
+ return gdk_gl_context_get_current();
+}
+
+int gd_gl_area_make_current(DisplayChangeListener *dcl,
+ qemu_gl_context ctx)
+{
+ gdk_gl_context_make_current(ctx);
+ return 0;
+}
diff --git a/ui/gtk.c b/ui/gtk.c
index 6faf5a5..5cbb389 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -356,6 +356,12 @@ static void gd_update_full_redraw(VirtualConsole *vc)
GtkWidget *area = vc->gfx.drawing_area;
int ww, wh;
gdk_drawable_get_size(gtk_widget_get_window(area), &ww, &wh);
+#if defined(CONFIG_GTK_GL)
+ if (vc->gfx.gls) {
+ gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area));
+ return;
+ }
+#endif
gtk_widget_queue_draw_area(area, 0, 0, ww, wh);
}
@@ -596,6 +602,27 @@ static const DisplayChangeListenerOps dcl_ops = {
/** DisplayState Callbacks (opengl version) **/
+#if defined(CONFIG_GTK_GL)
+
+static const DisplayChangeListenerOps dcl_gl_area_ops = {
+ .dpy_name = "gtk-egl",
+ .dpy_gfx_update = gd_gl_area_update,
+ .dpy_gfx_switch = gd_gl_area_switch,
+ .dpy_gfx_check_format = console_gl_check_format,
+ .dpy_refresh = gd_gl_area_refresh,
+ .dpy_mouse_set = gd_mouse_set,
+ .dpy_cursor_define = gd_cursor_define,
+
+ .dpy_gl_ctx_create = gd_gl_area_create_context,
+ .dpy_gl_ctx_destroy = gd_gl_area_destroy_context,
+ .dpy_gl_ctx_make_current = gd_gl_area_make_current,
+ .dpy_gl_ctx_get_current = gd_gl_area_get_current_context,
+ .dpy_gl_scanout = gd_gl_area_scanout,
+ .dpy_gl_update = gd_gl_area_scanout_flush,
+};
+
+#else
+
static const DisplayChangeListenerOps dcl_egl_ops = {
.dpy_name = "gtk-egl",
.dpy_gfx_update = gd_egl_update,
@@ -613,7 +640,8 @@ static const DisplayChangeListenerOps dcl_egl_ops = {
.dpy_gl_update = gd_egl_scanout_flush,
};
-#endif
+#endif /* CONFIG_GTK_GL */
+#endif /* CONFIG_OPENGL */
/** QEMU Events **/
@@ -663,6 +691,19 @@ static gboolean gd_window_close(GtkWidget *widget,
GdkEvent *event,
return TRUE;
}
+#if defined(CONFIG_GTK_GL)
+static gboolean gd_render_event(GtkGLArea *area, GdkGLContext *context,
+ void *opaque)
+{
+ VirtualConsole *vc = opaque;
+
+ if (vc->gfx.gls) {
+ gd_gl_area_draw(vc);
+ }
+ return TRUE;
+}
+#endif
+
static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
{
VirtualConsole *vc = opaque;
@@ -673,8 +714,13 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t
*cr, void *opaque)
#if defined(CONFIG_OPENGL)
if (vc->gfx.gls) {
+#if defined(CONFIG_GTK_GL)
+ /* invoke render callback please */
+ return FALSE;
+#else
gd_egl_draw(vc);
return TRUE;
+#endif
}
#endif
@@ -1618,6 +1664,10 @@ static void gd_connect_vc_gfx_signals(VirtualConsole *vc)
#if GTK_CHECK_VERSION(3, 0, 0)
g_signal_connect(vc->gfx.drawing_area, "draw",
G_CALLBACK(gd_draw_event), vc);
+#if defined(CONFIG_GTK_GL)
+ g_signal_connect(vc->gfx.drawing_area, "render",
+ G_CALLBACK(gd_render_event), vc);
+#endif
#else
g_signal_connect(vc->gfx.drawing_area, "expose-event",
G_CALLBACK(gd_expose_event), vc);
@@ -1726,7 +1776,37 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s,
VirtualConsole *vc,
vc->gfx.scale_x = 1.0;
vc->gfx.scale_y = 1.0;
- vc->gfx.drawing_area = gtk_drawing_area_new();
+#if defined(CONFIG_OPENGL)
+ if (display_opengl) {
+#if defined(CONFIG_GTK_GL)
+ vc->gfx.drawing_area = gtk_gl_area_new();
+ vc->gfx.dcl.ops = &dcl_gl_area_ops;
+#else
+ vc->gfx.drawing_area = gtk_drawing_area_new();
+ /*
+ * gtk_widget_set_double_buffered() was deprecated in 3.14.
+ * It is required for opengl rendering on X11 though. A
+ * proper replacement (native opengl support) is only
+ * available in 3.16+. Silence the warning if possible.
+ */
+#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+ gtk_widget_set_double_buffered(vc->gfx.drawing_area, FALSE);
+#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
+#pragma GCC diagnostic pop
+#endif
+ vc->gfx.dcl.ops = &dcl_egl_ops;
+#endif /* CONFIG_GTK_GL */
+ } else
+#endif
+ {
+ vc->gfx.drawing_area = gtk_drawing_area_new();
+ vc->gfx.dcl.ops = &dcl_ops;
+ }
+
+
gtk_widget_add_events(vc->gfx.drawing_area,
GDK_POINTER_MOTION_MASK |
GDK_BUTTON_PRESS_MASK |
@@ -1744,29 +1824,6 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s,
VirtualConsole *vc,
gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook),
vc->tab_item, gtk_label_new(vc->label));
-#if defined(CONFIG_OPENGL)
- if (display_opengl) {
- /*
- * gtk_widget_set_double_buffered() was deprecated in 3.14.
- * It is required for opengl rendering on X11 though. A
- * proper replacement (native opengl support) is only
- * available in 3.16+. Silence the warning if possible.
- */
-#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
- gtk_widget_set_double_buffered(vc->gfx.drawing_area, FALSE);
-#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
-#pragma GCC diagnostic pop
-#endif
- vc->gfx.dcl.ops = &dcl_egl_ops;
- } else
-#endif
- {
- vc->gfx.dcl.ops = &dcl_ops;
- }
-
vc->gfx.dcl.con = con;
register_displaychangelistener(&vc->gfx.dcl);
@@ -2029,8 +2086,12 @@ void early_gtk_display_init(int opengl)
break;
case 1: /* on */
#if defined(CONFIG_OPENGL)
+#if defined(CONFIG_GTK_GL)
+ gtk_gl_area_init();
+#else
gtk_egl_init();
#endif
+#endif
break;
default:
g_assert_not_reached();
--
1.8.3.1
- Re: [Qemu-devel] [PATCH 1/9] shaders: initialize vertexes once, (continued)
[Qemu-devel] [PATCH 2/9] sdl2: quick & dirty flicker workaround, Gerd Hoffmann, 2015/09/09
[Qemu-devel] [PATCH 3/9] ui/console: add opengl context and scanout support interfaces., Gerd Hoffmann, 2015/09/09
[Qemu-devel] [PATCH 9/9] gtk/opengl: add opengl context and scanout support (GtkGLArea),
Gerd Hoffmann <=
[Qemu-devel] [PATCH 8/9] gtk/opengl: add opengl context and scanout support (egl), Gerd Hoffmann, 2015/09/09
[Qemu-devel] [PATCH 5/9] virtio-gpu: add 3d mode and virgl rendering support., Gerd Hoffmann, 2015/09/09
Re: [Qemu-devel] [PATCH 0/9] add virgl rendering support., Marc-André Lureau, 2015/09/11