From: Paolo Bonzini <pbonzini@redhat.com>
To: Gerd Hoffmann <kraxel@redhat.com>, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PULL 4/5] gtk: add opengl support, using egl
Date: Fri, 05 Jun 2015 12:20:50 +0200 [thread overview]
Message-ID: <55717802.9000707@redhat.com> (raw)
In-Reply-To: <1432894036-28513-5-git-send-email-kraxel@redhat.com>
On 29/05/2015 12:07, Gerd Hoffmann wrote:
> This adds opengl rendering support to the gtk ui, using egl.
> It's off by default for now, use 'qemu -display gtk,gl=on'
> to play with this.
>
> Note that gtk got native opengl support with release 3.16.
> There most likely will be a separate implementation for 3.16+,
> using the native gtk opengl support. This patch covers older
> versions (and for the time being 3.16 too, hopefully without
> rendering quirks).
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This unfortunately breaks "-device help" if you do not have an X11
connection. gtk_init exits the program.
Paolo
> ---
> include/ui/console.h | 2 +-
> include/ui/gtk.h | 23 +++++++++
> ui/Makefile.objs | 3 ++
> ui/gtk-egl.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++
> ui/gtk.c | 90 ++++++++++++++++++++++++++------
> vl.c | 11 +++-
> 6 files changed, 253 insertions(+), 17 deletions(-)
> create mode 100644 ui/gtk-egl.c
>
> diff --git a/include/ui/console.h b/include/ui/console.h
> index 383dec2..6f7550e 100644
> --- a/include/ui/console.h
> +++ b/include/ui/console.h
> @@ -393,7 +393,7 @@ void curses_display_init(DisplayState *ds, int full_screen);
> int index_from_key(const char *key);
>
> /* gtk.c */
> -void early_gtk_display_init(void);
> +void early_gtk_display_init(int opengl);
> void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover);
>
> #endif
> diff --git a/include/ui/gtk.h b/include/ui/gtk.h
> index b750845..ee6dffd 100644
> --- a/include/ui/gtk.h
> +++ b/include/ui/gtk.h
> @@ -22,6 +22,10 @@
> #include <X11/XKBlib.h>
> #endif
>
> +#if defined(CONFIG_OPENGL)
> +#include "ui/egl-helpers.h"
> +#endif
> +
> /* Compatibility define to let us build on both Gtk2 and Gtk3 */
> #if GTK_CHECK_VERSION(3, 0, 0)
> static inline void gdk_drawable_get_size(GdkWindow *w, gint *ww, gint *wh)
> @@ -41,6 +45,12 @@ typedef struct VirtualGfxConsole {
> cairo_surface_t *surface;
> double scale_x;
> double scale_y;
> +#if defined(CONFIG_OPENGL)
> + ConsoleGLState *gls;
> + EGLContext ectx;
> + EGLSurface esurface;
> + int glupdates;
> +#endif
> } VirtualGfxConsole;
>
> #if defined(CONFIG_VTE)
> @@ -73,4 +83,17 @@ typedef struct VirtualConsole {
> };
> } VirtualConsole;
>
> +/* ui/gtk.c */
> +void gd_update_windowsize(VirtualConsole *vc);
> +
> +/* ui/gtk-egl.c */
> +void gd_egl_init(VirtualConsole *vc);
> +void gd_egl_draw(VirtualConsole *vc);
> +void gd_egl_update(DisplayChangeListener *dcl,
> + int x, int y, int w, int h);
> +void gd_egl_refresh(DisplayChangeListener *dcl);
> +void gd_egl_switch(DisplayChangeListener *dcl,
> + DisplaySurface *surface);
> +void gtk_egl_init(void);
> +
> #endif /* UI_GTK_H */
> diff --git a/ui/Makefile.objs b/ui/Makefile.objs
> index 5c46870..023914c 100644
> --- a/ui/Makefile.objs
> +++ b/ui/Makefile.objs
> @@ -31,13 +31,16 @@ ifeq ($(CONFIG_OPENGL),y)
> common-obj-y += shader.o
> common-obj-y += console-gl.o
> common-obj-y += egl-helpers.o
> +common-obj-$(CONFIG_GTK) += gtk-egl.o
> endif
>
> gtk.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS)
> +gtk-egl.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)
>
> +gtk-egl.o-libs += $(OPENGL_LIBS)
> shader.o-libs += $(OPENGL_LIBS)
> console-gl.o-libs += $(OPENGL_LIBS)
> egl-helpers.o-libs += $(OPENGL_LIBS)
> diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
> new file mode 100644
> index 0000000..15b41f2
> --- /dev/null
> +++ b/ui/gtk-egl.c
> @@ -0,0 +1,141 @@
> +/*
> + * GTK UI -- egl opengl code.
> + *
> + * Note that gtk 3.16+ (released 2015-03-23) has a GtkGLArea widget,
> + * which is GtkDrawingArea like widget with opengl rendering support.
> + *
> + * This code handles opengl support on older gtk versions, using egl
> + * to get a opengl context for the X11 window.
> + *
> + * 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"
> +
> +/** DisplayState Callbacks (opengl version) **/
> +
> +void gd_egl_init(VirtualConsole *vc)
> +{
> + GdkWindow *gdk_window = gtk_widget_get_window(vc->gfx.drawing_area);
> + if (!gdk_window) {
> + return;
> + }
> +
> +#if GTK_CHECK_VERSION(3, 0, 0)
> + Window x11_window = gdk_x11_window_get_xid(gdk_window);
> +#else
> + Window x11_window = gdk_x11_drawable_get_xid(gdk_window);
> +#endif
> + if (!x11_window) {
> + return;
> + }
> +
> + vc->gfx.ectx = qemu_egl_init_ctx();
> + vc->gfx.esurface = qemu_egl_init_surface_x11(vc->gfx.ectx, x11_window);
> +
> + assert(vc->gfx.esurface);
> +}
> +
> +void gd_egl_draw(VirtualConsole *vc)
> +{
> + GdkWindow *window;
> + int ww, wh;
> +
> + if (!vc->gfx.gls || !vc->gfx.ds) {
> + return;
> + }
> +
> + eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
> + vc->gfx.esurface, vc->gfx.ectx);
> +
> + window = gtk_widget_get_window(vc->gfx.drawing_area);
> + gdk_drawable_get_size(window, &ww, &wh);
> + surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh);
> + surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds);
> +
> + eglSwapBuffers(qemu_egl_display, vc->gfx.esurface);
> +}
> +
> +void gd_egl_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;
> + }
> +
> + eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
> + vc->gfx.esurface, vc->gfx.ectx);
> + surface_gl_update_texture(vc->gfx.gls, vc->gfx.ds, x, y, w, h);
> + vc->gfx.glupdates++;
> +}
> +
> +void gd_egl_refresh(DisplayChangeListener *dcl)
> +{
> + VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> +
> + if (!vc->gfx.esurface) {
> + gd_egl_init(vc);
> + if (!vc->gfx.esurface) {
> + return;
> + }
> + 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;
> + gd_egl_draw(vc);
> + }
> +}
> +
> +void gd_egl_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;
> + }
> +
> + surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds);
> + vc->gfx.ds = surface;
> + if (vc->gfx.gls) {
> + surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds);
> + }
> +
> + if (resized) {
> + gd_update_windowsize(vc);
> + }
> +}
> +
> +void gtk_egl_init(void)
> +{
> + GdkDisplay *gdk_display = gdk_display_get_default();
> + Display *x11_display = gdk_x11_display_get_xdisplay(gdk_display);
> +
> + if (qemu_egl_init_dpy(x11_display, false, false) < 0) {
> + return;
> + }
> +
> + display_opengl = 1;
> +}
> diff --git a/ui/gtk.c b/ui/gtk.c
> index c58028f..2477e37 100644
> --- a/ui/gtk.c
> +++ b/ui/gtk.c
> @@ -339,7 +339,7 @@ static void gd_update_geometry_hints(VirtualConsole *vc)
> gtk_window_set_geometry_hints(geo_window, geo_widget, &geo, mask);
> }
>
> -static void gd_update_windowsize(VirtualConsole *vc)
> +void gd_update_windowsize(VirtualConsole *vc)
> {
> GtkDisplayState *s = vc->s;
>
> @@ -581,6 +581,33 @@ static void gd_switch(DisplayChangeListener *dcl,
> }
> }
>
> +static const DisplayChangeListenerOps dcl_ops = {
> + .dpy_name = "gtk",
> + .dpy_gfx_update = gd_update,
> + .dpy_gfx_switch = gd_switch,
> + .dpy_gfx_check_format = qemu_pixman_check_format,
> + .dpy_refresh = gd_refresh,
> + .dpy_mouse_set = gd_mouse_set,
> + .dpy_cursor_define = gd_cursor_define,
> +};
> +
> +
> +#if defined(CONFIG_OPENGL)
> +
> +/** DisplayState Callbacks (opengl version) **/
> +
> +static const DisplayChangeListenerOps dcl_egl_ops = {
> + .dpy_name = "gtk-egl",
> + .dpy_gfx_update = gd_egl_update,
> + .dpy_gfx_switch = gd_egl_switch,
> + .dpy_gfx_check_format = console_gl_check_format,
> + .dpy_refresh = gd_egl_refresh,
> + .dpy_mouse_set = gd_mouse_set,
> + .dpy_cursor_define = gd_cursor_define,
> +};
> +
> +#endif
> +
> /** QEMU Events **/
>
> static void gd_change_runstate(void *opaque, int running, RunState state)
> @@ -637,6 +664,13 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
> int ww, wh;
> int fbw, fbh;
>
> +#if defined(CONFIG_OPENGL)
> + if (vc->gfx.gls) {
> + gd_egl_draw(vc);
> + return TRUE;
> + }
> +#endif
> +
> if (!gtk_widget_get_realized(widget)) {
> return FALSE;
> }
> @@ -1676,16 +1710,6 @@ static GtkWidget *gd_create_menu_machine(GtkDisplayState *s)
> return machine_menu;
> }
>
> -static const DisplayChangeListenerOps dcl_ops = {
> - .dpy_name = "gtk",
> - .dpy_gfx_update = gd_update,
> - .dpy_gfx_switch = gd_switch,
> - .dpy_gfx_check_format = qemu_pixman_check_format,
> - .dpy_refresh = gd_refresh,
> - .dpy_mouse_set = gd_mouse_set,
> - .dpy_cursor_define = gd_cursor_define,
> -};
> -
> static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
> QemuConsole *con, int idx,
> GSList *group, GtkWidget *view_menu)
> @@ -1713,7 +1737,29 @@ 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));
>
> - vc->gfx.dcl.ops = &dcl_ops;
> +#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);
>
> @@ -1876,8 +1922,6 @@ void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
> GtkDisplayState *s = g_malloc0(sizeof(*s));
> char *filename;
>
> - gtk_init(NULL, NULL);
> -
> s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
> #if GTK_CHECK_VERSION(3, 2, 0)
> s->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
> @@ -1954,8 +1998,24 @@ void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
> gd_set_keycode_type(s);
> }
>
> -void early_gtk_display_init(void)
> +void early_gtk_display_init(int opengl)
> {
> + gtk_init(NULL, NULL);
> +
> + switch (opengl) {
> + case -1: /* default */
> + case 0: /* off */
> + break;
> + case 1: /* on */
> +#if defined(CONFIG_OPENGL)
> + gtk_egl_init();
> +#endif
> + break;
> + default:
> + g_assert_not_reached();
> + break;
> + }
> +
> #if defined(CONFIG_VTE)
> register_vc_handler(gd_vc_handler);
> #endif
> diff --git a/vl.c b/vl.c
> index 15bccc4..26b1e7e 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -2047,6 +2047,15 @@ static DisplayType select_display(const char *p)
> } else {
> goto invalid_gtk_args;
> }
> + } else if (strstart(opts, ",gl=", &nextopt)) {
> + opts = nextopt;
> + if (strstart(opts, "on", &nextopt)) {
> + request_opengl = 1;
> + } else if (strstart(opts, "off", &nextopt)) {
> + request_opengl = 0;
> + } else {
> + goto invalid_gtk_args;
> + }
> } else {
> invalid_gtk_args:
> fprintf(stderr, "Invalid GTK option string: %s\n", p);
> @@ -4012,7 +4021,7 @@ int main(int argc, char **argv, char **envp)
>
> #if defined(CONFIG_GTK)
> if (display_type == DT_GTK) {
> - early_gtk_display_init();
> + early_gtk_display_init(request_opengl);
> }
> #endif
> #if defined(CONFIG_SDL)
>
next prev parent reply other threads:[~2015-06-05 10:21 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-05-29 10:07 [Qemu-devel] [PULL 0/5] gtk: add opengl rendering support Gerd Hoffmann
2015-05-29 10:07 ` [Qemu-devel] [PULL 1/5] ui: use libexpoxy Gerd Hoffmann
2015-05-29 10:07 ` [Qemu-devel] [PULL 2/5] ui: shader.h protect against double inclusion Gerd Hoffmann
2015-05-29 10:07 ` [Qemu-devel] [PULL 3/5] ui: add egl-helpers Gerd Hoffmann
2015-05-29 10:07 ` [Qemu-devel] [PULL 4/5] gtk: add opengl support, using egl Gerd Hoffmann
2015-06-05 10:20 ` Paolo Bonzini [this message]
2015-06-05 11:01 ` Gerd Hoffmann
2015-06-05 11:09 ` Gerd Hoffmann
2015-06-05 12:50 ` Gerd Hoffmann
2015-06-08 12:57 ` Markus Armbruster
2015-05-29 10:07 ` [Qemu-devel] [PULL 5/5] gtk: Replace gdk_cursor_new() Gerd Hoffmann
2015-05-29 14:31 ` [Qemu-devel] [PULL 0/5] gtk: add opengl rendering support Peter Maydell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=55717802.9000707@redhat.com \
--to=pbonzini@redhat.com \
--cc=kraxel@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.