From 0e39c4aa7ecc5699bc391fcb1dceed88d077e99d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 9 Mar 2018 14:59:45 +0100 Subject: [PATCH 01/14] build: try improve handling of clang warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch disables the pragma diagnostic -Wunused-but-set-variable for clang in util/coroutine-ucontext.c. This in turn allows us to remove it from the configure check, so the CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE will succeed for clang. With that in place clang builds (linux) will use -Werror by default, which breaks the build due to warning about unaligned struct members. Just turning off this warning isn't a good idea as it indicates portability problems. So make it a warning again, using -Wno-error=address-of-packed-member. That way it doesn't break the build but still shows up in the logs. Now clang builds qemu without errors. Well, almost. There are some left in the rdma code. Leaving that to the rdma people. All others can use --disable-rdma to workarounds this. Cc: Peter Maydell Signed-off-by: Gerd Hoffmann Message-Id: <20180309135945.20436-1-kraxel@redhat.com> Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé --- configure | 2 +- util/coroutine-ucontext.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure b/configure index f74e1f3b7c..356abee025 100755 --- a/configure +++ b/configure @@ -1692,6 +1692,7 @@ gcc_flags="-Wno-missing-include-dirs -Wempty-body -Wnested-externs $gcc_flags" gcc_flags="-Wendif-labels -Wno-shift-negative-value $gcc_flags" gcc_flags="-Wno-initializer-overrides -Wexpansion-to-defined $gcc_flags" gcc_flags="-Wno-string-plus-int $gcc_flags" +gcc_flags="-Wno-error=address-of-packed-member $gcc_flags" # Note that we do not add -Werror to gcc_flags here, because that would # enable it for all configure tests. If a configure test failed due # to -Werror this would just silently disable some features, @@ -4860,7 +4861,6 @@ fi pragma_disable_unused_but_set=no cat > $TMPC << EOF #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wstrict-prototypes" #pragma GCC diagnostic pop diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c index 926d3402e3..090ba21a13 100644 --- a/util/coroutine-ucontext.c +++ b/util/coroutine-ucontext.c @@ -170,7 +170,7 @@ Coroutine *qemu_coroutine_new(void) } #ifdef CONFIG_VALGRIND_H -#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE +#if defined(CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE) && !defined(__clang__) /* Work around an unused variable in the valgrind.h macro... */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-but-set-variable" @@ -179,7 +179,7 @@ static inline void valgrind_stack_deregister(CoroutineUContext *co) { VALGRIND_STACK_DEREGISTER(co->valgrind_stack_id); } -#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE +#if defined(CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE) && !defined(__clang__) #pragma GCC diagnostic pop #endif #endif From 722cd7496474cebb2218f21e038592fad8603365 Mon Sep 17 00:00:00 2001 From: Bruce Rogers Date: Wed, 7 Mar 2018 08:55:17 -0700 Subject: [PATCH 02/14] make: switch language file build to be gtk module aware Now that gtk support builds as a module, CONFIG_GTK changed from y to m. Adjust Makefile correspondingly. Signed-off-by: Bruce Rogers Message-id: 20180307155517.32570-1-brogers@suse.com Signed-off-by: Gerd Hoffmann --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9a75c48ae0..026fa17dc0 100644 --- a/Makefile +++ b/Makefile @@ -851,7 +851,7 @@ ifneq ($(BLOBS),) $(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \ done endif -ifeq ($(CONFIG_GTK),y) +ifeq ($(CONFIG_GTK),m) $(MAKE) -C po $@ endif $(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/keymaps" From 2ca5c43091324a68772dc348cdf157c63888c168 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 7 Mar 2018 16:42:57 +0100 Subject: [PATCH 03/14] sdl: workaround bug in sdl 2.0.8 headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=892087 Signed-off-by: Gerd Hoffmann Reviewed-by: Daniel P. Berrangé Message-id: 20180307154258.9313-1-kraxel@redhat.com --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index 356abee025..8c7124bf2b 100755 --- a/configure +++ b/configure @@ -2875,6 +2875,7 @@ if test "$sdl" != "no" ; then int main( void ) { return SDL_Init (SDL_INIT_VIDEO); } EOF sdl_cflags=$($sdlconfig --cflags 2>/dev/null) + sdl_cflags="$sdl_cflags -Wno-undef" # workaround 2.0.8 bug if test "$static" = "yes" ; then if $pkg_config $sdlname --exists; then sdl_libs=$($pkg_config $sdlname --static --libs 2>/dev/null) From 11c82b584a4578f7c7e408448c9f61c729acabae Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 6 Mar 2018 10:09:46 +0100 Subject: [PATCH 04/14] ui/gtk: make GtkGlArea usage a runtime option Compile in both gtk-egl and gtk-gl-area, then allow to choose at runtime instead of compile time which opengl variant we want use. Signed-off-by: Gerd Hoffmann Message-id: 20180306090951.22932-2-kraxel@redhat.com --- include/ui/gtk.h | 2 ++ ui/Makefile.objs | 3 +-- ui/gtk.c | 53 ++++++++++++++++++++++++++---------------------- 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/include/ui/gtk.h b/include/ui/gtk.h index 849c896eef..f6dafc5961 100644 --- a/include/ui/gtk.h +++ b/include/ui/gtk.h @@ -90,6 +90,8 @@ typedef struct VirtualConsole { }; } VirtualConsole; +extern bool gtk_use_gl_area; + /* ui/gtk.c */ void gd_update_windowsize(VirtualConsole *vc); diff --git a/ui/Makefile.objs b/ui/Makefile.objs index dcd54a5287..d1203bb80a 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -52,11 +52,10 @@ common-obj-y += egl-context.o common-obj-$(CONFIG_OPENGL_DMABUF) += egl-headless.o ifeq ($(CONFIG_GTK_GL),y) gtk.mo-objs += gtk-gl-area.o -else +endif gtk.mo-objs += gtk-egl.o gtk.mo-libs += $(OPENGL_LIBS) endif -endif shader.o-libs += $(OPENGL_LIBS) console-gl.o-libs += $(OPENGL_LIBS) diff --git a/ui/gtk.c b/ui/gtk.c index 563cff32b8..856429a02f 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -243,6 +243,8 @@ typedef struct VCChardev { #define TYPE_CHARDEV_VC "chardev-vc" #define VC_CHARDEV(obj) OBJECT_CHECK(VCChardev, (obj), TYPE_CHARDEV_VC) +bool gtk_use_gl_area; + static void gd_grab_pointer(VirtualConsole *vc, const char *reason); static void gd_ungrab_pointer(GtkDisplayState *s); static void gd_grab_keyboard(VirtualConsole *vc, const char *reason); @@ -453,7 +455,7 @@ static void gd_update_full_redraw(VirtualConsole *vc) int ww, wh; gdk_drawable_get_size(gtk_widget_get_window(area), &ww, &wh); #if defined(CONFIG_GTK_GL) - if (vc->gfx.gls) { + if (vc->gfx.gls && gtk_use_gl_area) { gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area)); return; } @@ -725,7 +727,7 @@ static const DisplayChangeListenerOps dcl_gl_area_ops = { .dpy_gl_update = gd_gl_area_scanout_flush, }; -#else +#endif /* CONFIG_GTK_GL */ static const DisplayChangeListenerOps dcl_egl_ops = { .dpy_name = "gtk-egl", @@ -745,7 +747,6 @@ static const DisplayChangeListenerOps dcl_egl_ops = { .dpy_gl_update = gd_egl_scanout_flush, }; -#endif /* CONFIG_GTK_GL */ #endif /* CONFIG_OPENGL */ /** QEMU Events **/ @@ -844,13 +845,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 + if (gtk_use_gl_area) { + /* invoke render callback please */ + return FALSE; + } else { + gd_egl_draw(vc); + return TRUE; + } } #endif @@ -1993,7 +1994,7 @@ static void gd_connect_vc_gfx_signals(VirtualConsole *vc) g_signal_connect(vc->gfx.drawing_area, "draw", G_CALLBACK(gd_draw_event), vc); #if defined(CONFIG_GTK_GL) - if (display_opengl) { + if (gtk_use_gl_area) { /* wire up GtkGlArea events */ g_signal_connect(vc->gfx.drawing_area, "render", G_CALLBACK(gd_render_event), vc); @@ -2116,26 +2117,29 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc, #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. - */ + if (gtk_use_gl_area) { + vc->gfx.drawing_area = gtk_gl_area_new(); + vc->gfx.dcl.ops = &dcl_gl_area_ops; + } else +#endif /* CONFIG_GTK_GL */ + { + 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); + 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 */ + vc->gfx.dcl.ops = &dcl_egl_ops; + } } else #endif { @@ -2437,6 +2441,7 @@ static void early_gtk_display_init(DisplayOptions *opts) if (opts->has_gl && opts->gl) { #if defined(CONFIG_OPENGL) #if defined(CONFIG_GTK_GL) + gtk_use_gl_area = true; gtk_gl_area_init(); #else gtk_egl_init(); From c923cbedb20d5d4153a02d474ea710d634720622 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 6 Mar 2018 10:09:47 +0100 Subject: [PATCH 05/14] ui/gtk: group gtk.mo declarations in Makefile Signed-off-by: Gerd Hoffmann Message-id: 20180306090951.22932-3-kraxel@redhat.com --- ui/Makefile.objs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ui/Makefile.objs b/ui/Makefile.objs index d1203bb80a..b560ee12c3 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -38,6 +38,13 @@ common-obj-$(CONFIG_GTK) += gtk.mo gtk.mo-objs := gtk.o gtk.mo-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) gtk.mo-libs := $(GTK_LIBS) $(VTE_LIBS) +ifeq ($(CONFIG_OPENGL),y) +gtk.mo-objs += gtk-egl.o +gtk.mo-libs += $(OPENGL_LIBS) +ifeq ($(CONFIG_GTK_GL),y) +gtk.mo-objs += gtk-gl-area.o +endif +endif common-obj-$(CONFIG_CURSES) += curses.mo curses.mo-objs := curses.o @@ -50,11 +57,6 @@ common-obj-y += console-gl.o common-obj-y += egl-helpers.o common-obj-y += egl-context.o common-obj-$(CONFIG_OPENGL_DMABUF) += egl-headless.o -ifeq ($(CONFIG_GTK_GL),y) -gtk.mo-objs += gtk-gl-area.o -endif -gtk.mo-objs += gtk-egl.o -gtk.mo-libs += $(OPENGL_LIBS) endif shader.o-libs += $(OPENGL_LIBS) From 2f92f37c9ecaa2a51f75455046b4d1b665db5c12 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 6 Mar 2018 10:09:48 +0100 Subject: [PATCH 06/14] ui/opengl: Makefile cleanup With gtk.mo bits moved away we don't need the ifeq any more. Also add missing opengl libs for some objects. Signed-off-by: Gerd Hoffmann Message-id: 20180306090951.22932-4-kraxel@redhat.com --- ui/Makefile.objs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ui/Makefile.objs b/ui/Makefile.objs index b560ee12c3..cc784346cb 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -51,14 +51,14 @@ curses.mo-objs := curses.o curses.mo-cflags := $(CURSES_CFLAGS) curses.mo-libs := $(CURSES_LIBS) -ifeq ($(CONFIG_OPENGL),y) -common-obj-y += shader.o -common-obj-y += console-gl.o -common-obj-y += egl-helpers.o -common-obj-y += egl-context.o +common-obj-$(CONFIG_OPENGL) += shader.o +common-obj-$(CONFIG_OPENGL) += console-gl.o +common-obj-$(CONFIG_OPENGL) += egl-helpers.o +common-obj-$(CONFIG_OPENGL) += egl-context.o common-obj-$(CONFIG_OPENGL_DMABUF) += egl-headless.o -endif shader.o-libs += $(OPENGL_LIBS) console-gl.o-libs += $(OPENGL_LIBS) egl-helpers.o-libs += $(OPENGL_LIBS) +egl-context.o-libs += $(OPENGL_LIBS) +egl-headless.o-libs += $(OPENGL_LIBS) From 4c70280592f5357c66f95173ec907920f48c99fa Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 6 Mar 2018 10:09:49 +0100 Subject: [PATCH 07/14] ui/gtk: use GtkGlArea on wayland only For dma-buf support we need a egl context. The gtk x11 backend uses glx contexts though. We can't use the GtkGlArea widget on x11 because of that, so use our own gtk-egl code instead. wayland continues to use the GtkGlArea widget. Signed-off-by: Gerd Hoffmann Message-id: 20180306090951.22932-5-kraxel@redhat.com --- ui/gtk.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 856429a02f..4a1622b887 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -2440,12 +2440,15 @@ static void early_gtk_display_init(DisplayOptions *opts) assert(opts->type == DISPLAY_TYPE_GTK); if (opts->has_gl && opts->gl) { #if defined(CONFIG_OPENGL) -#if defined(CONFIG_GTK_GL) - gtk_use_gl_area = true; - gtk_gl_area_init(); -#else - gtk_egl_init(); +#if defined(CONFIG_GTK_GL) && defined(GDK_WINDOWING_WAYLAND) + if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) { + gtk_use_gl_area = true; + gtk_gl_area_init(); + } #endif + { + gtk_egl_init(); + } #endif } From 70763fea4fbbe2984fd2a8f6ce9c77114af80792 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 6 Mar 2018 10:09:50 +0100 Subject: [PATCH 08/14] ui/gtk-egl: add scanout_dmabuf support Add support for dmabuf scanouts to gtk-egl. Signed-off-by: Gerd Hoffmann Message-id: 20180306090951.22932-6-kraxel@redhat.com --- include/ui/gtk.h | 4 ++++ ui/gtk-egl.c | 23 +++++++++++++++++++++++ ui/gtk.c | 2 ++ 3 files changed, 29 insertions(+) diff --git a/include/ui/gtk.h b/include/ui/gtk.h index f6dafc5961..84c992c227 100644 --- a/include/ui/gtk.h +++ b/include/ui/gtk.h @@ -113,6 +113,10 @@ void gd_egl_scanout_texture(DisplayChangeListener *dcl, uint32_t backing_height, uint32_t x, uint32_t y, uint32_t w, uint32_t h); +void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl, + QemuDmaBuf *dmabuf); +void gd_egl_release_dmabuf(DisplayChangeListener *dcl, + QemuDmaBuf *dmabuf); void gd_egl_scanout_flush(DisplayChangeListener *dcl, uint32_t x, uint32_t y, uint32_t w, uint32_t h); void gtk_egl_init(void); diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index eb86c26a1d..2c83c22d04 100644 --- a/ui/gtk-egl.c +++ b/ui/gtk-egl.c @@ -194,6 +194,29 @@ void gd_egl_scanout_texture(DisplayChangeListener *dcl, backing_id, false); } +void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl, + QemuDmaBuf *dmabuf) +{ +#ifdef CONFIG_OPENGL_DMABUF + egl_dmabuf_import_texture(dmabuf); + if (!dmabuf->texture) { + return; + } + + gd_egl_scanout_texture(dcl, dmabuf->texture, + false, dmabuf->width, dmabuf->height, + 0, 0, dmabuf->width, dmabuf->height); +#endif +} + +void gd_egl_release_dmabuf(DisplayChangeListener *dcl, + QemuDmaBuf *dmabuf) +{ +#ifdef CONFIG_OPENGL_DMABUF + egl_dmabuf_release_texture(dmabuf); +#endif +} + void gd_egl_scanout_flush(DisplayChangeListener *dcl, uint32_t x, uint32_t y, uint32_t w, uint32_t h) { diff --git a/ui/gtk.c b/ui/gtk.c index 4a1622b887..cf2061d716 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -744,6 +744,8 @@ static const DisplayChangeListenerOps dcl_egl_ops = { .dpy_gl_ctx_get_current = qemu_egl_get_current_context, .dpy_gl_scanout_disable = gd_egl_scanout_disable, .dpy_gl_scanout_texture = gd_egl_scanout_texture, + .dpy_gl_scanout_dmabuf = gd_egl_scanout_dmabuf, + .dpy_gl_release_dmabuf = gd_egl_release_dmabuf, .dpy_gl_update = gd_egl_scanout_flush, }; From f1bd313264925dfb229a2152eb3f60fe55746b83 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 6 Mar 2018 10:09:51 +0100 Subject: [PATCH 09/14] ui/gtk-egl: add cursor_dmabuf support Add support for cursor dmabufs to gtk-egl. Just blend in the cursor (if we have one) when rendering the dmabuf. Signed-off-by: Gerd Hoffmann Message-id: 20180306090951.22932-7-kraxel@redhat.com --- include/ui/gtk.h | 8 ++++++++ ui/gtk-egl.c | 40 +++++++++++++++++++++++++++++++++++++++- ui/gtk.c | 2 ++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/include/ui/gtk.h b/include/ui/gtk.h index 84c992c227..2922fc64b2 100644 --- a/include/ui/gtk.h +++ b/include/ui/gtk.h @@ -54,6 +54,9 @@ typedef struct VirtualGfxConsole { int x, y, w, h; egl_fb guest_fb; egl_fb win_fb; + egl_fb cursor_fb; + int cursor_x; + int cursor_y; bool y0_top; bool scanout_mode; #endif @@ -115,6 +118,11 @@ void gd_egl_scanout_texture(DisplayChangeListener *dcl, uint32_t w, uint32_t h); void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl, QemuDmaBuf *dmabuf); +void gd_egl_cursor_dmabuf(DisplayChangeListener *dcl, + QemuDmaBuf *dmabuf, bool have_hot, + uint32_t hot_x, uint32_t hot_y); +void gd_egl_cursor_position(DisplayChangeListener *dcl, + uint32_t pos_x, uint32_t pos_y); void gd_egl_release_dmabuf(DisplayChangeListener *dcl, QemuDmaBuf *dmabuf); void gd_egl_scanout_flush(DisplayChangeListener *dcl, diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index 2c83c22d04..9390c6762e 100644 --- a/ui/gtk-egl.c +++ b/ui/gtk-egl.c @@ -19,6 +19,7 @@ #include "ui/console.h" #include "ui/gtk.h" #include "ui/egl-helpers.h" +#include "ui/shader.h" #include "sysemu/sysemu.h" @@ -209,6 +210,35 @@ void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl, #endif } +void gd_egl_cursor_dmabuf(DisplayChangeListener *dcl, + QemuDmaBuf *dmabuf, bool have_hot, + uint32_t hot_x, uint32_t hot_y) +{ +#ifdef CONFIG_OPENGL_DMABUF + VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + + if (dmabuf) { + egl_dmabuf_import_texture(dmabuf); + if (!dmabuf->texture) { + return; + } + egl_fb_setup_for_tex(&vc->gfx.cursor_fb, dmabuf->width, dmabuf->height, + dmabuf->texture, false); + } else { + egl_fb_destroy(&vc->gfx.cursor_fb); + } +#endif +} + +void gd_egl_cursor_position(DisplayChangeListener *dcl, + uint32_t pos_x, uint32_t pos_y) +{ + VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + + vc->gfx.cursor_x = pos_x; + vc->gfx.cursor_y = pos_y; +} + void gd_egl_release_dmabuf(DisplayChangeListener *dcl, QemuDmaBuf *dmabuf) { @@ -237,7 +267,15 @@ void gd_egl_scanout_flush(DisplayChangeListener *dcl, window = gtk_widget_get_window(vc->gfx.drawing_area); gdk_drawable_get_size(window, &ww, &wh); egl_fb_setup_default(&vc->gfx.win_fb, ww, wh); - egl_fb_blit(&vc->gfx.win_fb, &vc->gfx.guest_fb, !vc->gfx.y0_top); + if (vc->gfx.cursor_fb.texture) { + egl_texture_blit(vc->gfx.gls, &vc->gfx.win_fb, &vc->gfx.guest_fb, + vc->gfx.y0_top); + egl_texture_blend(vc->gfx.gls, &vc->gfx.win_fb, &vc->gfx.cursor_fb, + vc->gfx.y0_top, + vc->gfx.cursor_x, vc->gfx.cursor_y); + } else { + egl_fb_blit(&vc->gfx.win_fb, &vc->gfx.guest_fb, !vc->gfx.y0_top); + } eglSwapBuffers(qemu_egl_display, vc->gfx.esurface); } diff --git a/ui/gtk.c b/ui/gtk.c index cf2061d716..ef5bc42094 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -745,6 +745,8 @@ static const DisplayChangeListenerOps dcl_egl_ops = { .dpy_gl_scanout_disable = gd_egl_scanout_disable, .dpy_gl_scanout_texture = gd_egl_scanout_texture, .dpy_gl_scanout_dmabuf = gd_egl_scanout_dmabuf, + .dpy_gl_cursor_dmabuf = gd_egl_cursor_dmabuf, + .dpy_gl_cursor_position = gd_egl_cursor_position, .dpy_gl_release_dmabuf = gd_egl_release_dmabuf, .dpy_gl_update = gd_egl_scanout_flush, }; From 2e5567c903ad05d312de0c3188cb2d3b856fa4c4 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 8 Mar 2018 17:18:03 +0100 Subject: [PATCH 10/14] vnc: deal with surface NULL pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Secondary displays in multihead setups are allowed to have a NULL DisplaySurface. Typically user interfaces handle this by hiding the window which shows the display in question. This isn't an option for vnc though because it simply hasn't a concept of windows or outputs. So handle the situation by showing a placeholder DisplaySurface instead. Also check in console_select whenever a surface is preset in the first place before requesting an update. This fixes a segfault which can be triggered by switching to an unused display (via vtrl-alt-) in a multihead setup, for example using -device virtio-vga,max_outputs=2. Cc: Christian Borntraeger Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Tested-by: Christian Borntraeger Message-id: 20180308161803.6152-1-kraxel@redhat.com --- include/ui/console.h | 2 ++ ui/console.c | 10 ++++++---- ui/vnc.c | 10 ++++++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/include/ui/console.h b/include/ui/console.h index aae9e44cb3..5fca9afcbc 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -260,6 +260,8 @@ DisplaySurface *qemu_create_displaysurface_guestmem(int width, int height, pixman_format_code_t format, int linesize, uint64_t addr); +DisplaySurface *qemu_create_message_surface(int w, int h, + const char *msg); PixelFormat qemu_default_pixelformat(int bpp); DisplaySurface *qemu_create_displaysurface(int width, int height); diff --git a/ui/console.c b/ui/console.c index 6ab4ff3baf..348610dd43 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1039,8 +1039,10 @@ void console_select(unsigned int index) dcl->ops->dpy_gfx_switch(dcl, s->surface); } } - dpy_gfx_update(s, 0, 0, surface_width(s->surface), - surface_height(s->surface)); + if (s->surface) { + dpy_gfx_update(s, 0, 0, surface_width(s->surface), + surface_height(s->surface)); + } } if (ds->have_text) { dpy_text_resize(s, s->width, s->height); @@ -1370,8 +1372,8 @@ DisplaySurface *qemu_create_displaysurface_guestmem(int width, int height, return surface; } -static DisplaySurface *qemu_create_message_surface(int w, int h, - const char *msg) +DisplaySurface *qemu_create_message_surface(int w, int h, + const char *msg) { DisplaySurface *surface = qemu_create_displaysurface(w, h); pixman_color_t bg = color_table_rgb[0][QEMU_COLOR_BLACK]; diff --git a/ui/vnc.c b/ui/vnc.c index 13c28cabb0..e164eb798c 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -746,9 +746,19 @@ static void vnc_update_server_surface(VncDisplay *vd) static void vnc_dpy_switch(DisplayChangeListener *dcl, DisplaySurface *surface) { + static const char placeholder_msg[] = + "Display output is not active."; + static DisplaySurface *placeholder; VncDisplay *vd = container_of(dcl, VncDisplay, dcl); VncState *vs; + if (surface == NULL) { + if (placeholder == NULL) { + placeholder = qemu_create_message_surface(640, 480, placeholder_msg); + } + surface = placeholder; + } + vnc_abort_display_jobs(vd); vd->ds = surface; From e181f8bbd011dbe9f30a58145215f47c4bb6ac6b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 8 Mar 2018 10:06:15 +0100 Subject: [PATCH 11/14] spice: drop dprint() debug logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some calls are deleted, some are converted into tracepoints. Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau Message-id: 20180308090618.30147-2-kraxel@redhat.com --- ui/spice-display.c | 75 ++++++++++++++-------------------------------- ui/trace-events | 9 ++++++ 2 files changed, 31 insertions(+), 53 deletions(-) diff --git a/ui/spice-display.c b/ui/spice-display.c index 98ccdfb687..79ea4df02c 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -26,20 +26,8 @@ #include "ui/spice-display.h" -static int debug = 0; bool spice_opengl; -static void GCC_FMT_ATTR(2, 3) dprint(int level, const char *fmt, ...) -{ - va_list args; - - if (level <= debug) { - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - } -} - int qemu_spice_rect_is_empty(const QXLRect* r) { return r->top == r->bottom || r->left == r->right; @@ -322,8 +310,6 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd) { QXLDevMemSlot memslot; - dprint(1, "%s/%d:\n", __func__, ssd->qxl.id); - memset(&memslot, 0, sizeof(memslot)); memslot.slot_group_id = MEMSLOT_GROUP_HOST; memslot.virt_end = ~0; @@ -347,10 +333,6 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) ssd->buf = g_malloc(ssd->bufsize); } - dprint(1, "%s/%d: %ux%u (size %" PRIu64 "/%d)\n", __func__, ssd->qxl.id, - surface_width(ssd->ds), surface_height(ssd->ds), - surface_size, ssd->bufsize); - surface.format = SPICE_SURFACE_FMT_32_xRGB; surface.width = surface_width(ssd->ds); surface.height = surface_height(ssd->ds); @@ -366,8 +348,6 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd) { - dprint(1, "%s/%d:\n", __func__, ssd->qxl.id); - qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC); } @@ -389,8 +369,7 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd, { QXLRect update_area; - dprint(2, "%s/%d: x %d y %d w %d h %d\n", __func__, - ssd->qxl.id, x, y, w, h); + trace_qemu_spice_display_update(ssd->qxl.id, x, y, w, h); update_area.left = x, update_area.right = x + w; update_area.top = y; @@ -413,8 +392,10 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, surface_height(surface) == pixman_image_get_height(ssd->surface) && surface_format(surface) == pixman_image_get_format(ssd->surface)) { /* no-resize fast path: just swap backing store */ - dprint(1, "%s/%d: fast (%dx%d)\n", __func__, ssd->qxl.id, - surface_width(surface), surface_height(surface)); + trace_qemu_spice_display_surface(ssd->qxl.id, + surface_width(surface), + surface_height(surface), + true); qemu_mutex_lock(&ssd->lock); ssd->ds = surface; pixman_image_unref(ssd->surface); @@ -427,11 +408,10 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, } /* full mode switch */ - dprint(1, "%s/%d: full (%dx%d -> %dx%d)\n", __func__, ssd->qxl.id, - ssd->surface ? pixman_image_get_width(ssd->surface) : 0, - ssd->surface ? pixman_image_get_height(ssd->surface) : 0, - surface ? surface_width(surface) : 0, - surface ? surface_height(surface) : 0); + trace_qemu_spice_display_surface(ssd->qxl.id, + surface ? surface_width(surface) : 0, + surface ? surface_height(surface) : 0, + false); memset(&ssd->dirty, 0, sizeof(ssd->dirty)); if (ssd->surface) { @@ -495,7 +475,6 @@ void qemu_spice_cursor_refresh_bh(void *opaque) void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) { - dprint(3, "%s/%d:\n", __func__, ssd->qxl.id); graphic_hw_update(ssd->dcl.con); qemu_mutex_lock(&ssd->lock); @@ -505,10 +484,10 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) } qemu_mutex_unlock(&ssd->lock); + trace_qemu_spice_display_refresh(ssd->qxl.id, ssd->notify); if (ssd->notify) { ssd->notify = 0; qemu_spice_wakeup(ssd); - dprint(2, "%s/%d: notify\n", __func__, ssd->qxl.id); } } @@ -516,21 +495,17 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker) { - SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); - - dprint(1, "%s/%d:\n", __func__, ssd->qxl.id); + /* nothing to do */ } static void interface_set_compression_level(QXLInstance *sin, int level) { - dprint(1, "%s/%d:\n", __func__, sin->id); /* nothing to do */ } #if SPICE_NEEDS_SET_MM_TIME static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time) { - dprint(3, "%s/%d:\n", __func__, sin->id); /* nothing to do */ } #endif @@ -554,8 +529,6 @@ static int interface_get_command(QXLInstance *sin, QXLCommandExt *ext) SimpleSpiceUpdate *update; int ret = false; - dprint(3, "%s/%d:\n", __func__, ssd->qxl.id); - qemu_mutex_lock(&ssd->lock); update = QTAILQ_FIRST(&ssd->updates); if (update != NULL) { @@ -570,7 +543,6 @@ static int interface_get_command(QXLInstance *sin, QXLCommandExt *ext) static int interface_req_cmd_notification(QXLInstance *sin) { - dprint(2, "%s/%d:\n", __func__, sin->id); return 1; } @@ -582,7 +554,6 @@ static void interface_release_resource(QXLInstance *sin, SimpleSpiceCursor *cursor; QXLCommandExt *ext; - dprint(2, "%s/%d:\n", __func__, ssd->qxl.id); ext = (void *)(intptr_t)(rext.info->id); switch (ext->cmd.type) { case QXL_CMD_DRAW: @@ -603,8 +574,6 @@ static int interface_get_cursor_command(QXLInstance *sin, QXLCommandExt *ext) SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); int ret; - dprint(3, "%s/%d:\n", __func__, ssd->qxl.id); - qemu_mutex_lock(&ssd->lock); if (ssd->ptr_define) { *ext = ssd->ptr_define->ext; @@ -623,7 +592,6 @@ static int interface_get_cursor_command(QXLInstance *sin, QXLCommandExt *ext) static int interface_req_cursor_notification(QXLInstance *sin) { - dprint(2, "%s:\n", __func__); return 1; } @@ -680,7 +648,7 @@ static void interface_set_client_capabilities(QXLInstance *sin, uint8_t client_present, uint8_t caps[58]) { - dprint(3, "%s:\n", __func__); + /* nothing to do */ } static int interface_client_monitors_config(QXLInstance *sin, @@ -705,9 +673,9 @@ static int interface_client_monitors_config(QXLInstance *sin, info.width = mc->monitors[head].width; info.height = mc->monitors[head].height; } + + trace_qemu_spice_ui_info(ssd->qxl.id, info.width, info.height); dpy_set_ui_info(ssd->dcl.con, &info); - dprint(1, "%s/%d: size %dx%d\n", __func__, ssd->qxl.id, - info.width, info.height); return 1; } @@ -902,9 +870,10 @@ static void spice_gl_switch(DisplayChangeListener *dcl, return; } - dprint(1, "%s: %dx%d (stride %d/%d, fourcc 0x%x)\n", __func__, - surface_width(ssd->ds), surface_height(ssd->ds), - surface_stride(ssd->ds), stride, fourcc); + trace_qemu_spice_gl_surface(ssd->qxl.id, + surface_width(ssd->ds), + surface_height(ssd->ds), + fourcc); /* note: spice server will close the fd */ spice_qxl_gl_scanout(&ssd->qxl, fd, @@ -932,7 +901,7 @@ static void qemu_spice_gl_scanout_disable(DisplayChangeListener *dcl) { SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); - dprint(1, "%s: no framebuffer\n", __func__); + trace_qemu_spice_gl_scanout_disable(ssd->qxl.id); spice_qxl_gl_scanout(&ssd->qxl, -1, 0, 0, 0, 0, false); qemu_spice_gl_monitor_config(ssd, 0, 0, 0, 0); ssd->have_surface = false; @@ -957,8 +926,7 @@ static void qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl, fprintf(stderr, "%s: failed to get fd for texture\n", __func__); return; } - dprint(1, "%s: %dx%d (stride %d, fourcc 0x%x)\n", __func__, - w, h, stride, fourcc); + trace_qemu_spice_gl_scanout_texture(ssd->qxl.id, w, h, fourcc); /* note: spice server will close the fd */ spice_qxl_gl_scanout(&ssd->qxl, fd, backing_width, backing_height, @@ -978,7 +946,8 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl, return; } - dprint(2, "%s: %dx%d+%d+%d\n", __func__, w, h, x, y); + + trace_qemu_spice_gl_update(ssd->qxl.id, w, h, x, y); qemu_spice_gl_block(ssd, true); cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0); spice_qxl_gl_draw_async(&ssd->qxl, x, y, w, h, cookie); diff --git a/ui/trace-events b/ui/trace-events index 861b68a305..518e950a01 100644 --- a/ui/trace-events +++ b/ui/trace-events @@ -75,6 +75,15 @@ qemu_spice_create_primary_surface(int qid, uint32_t sid, void *surface, int asyn qemu_spice_destroy_primary_surface(int qid, uint32_t sid, int async) "%d sid=%u async=%d" qemu_spice_wakeup(uint32_t qid) "%d" qemu_spice_create_update(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "lr %d -> %d, tb -> %d -> %d" +qemu_spice_display_update(int qid, uint32_t x, uint32_t y, uint32_t w, uint32_t h) "%d +%d+%d %dx%d" +qemu_spice_display_surface(int qid, uint32_t w, uint32_t h, int fast) "%d %dx%d, fast %d" +qemu_spice_display_refresh(int qid, int notify) "%d notify %d" +qemu_spice_ui_info(int qid, uint32_t width, uint32_t height) "%d %dx%d" + +qemu_spice_gl_surface(int qid, uint32_t w, uint32_t h, uint32_t fourcc) "%d %dx%d, fourcc 0x%x" +qemu_spice_gl_scanout_disable(int qid) "%d" +qemu_spice_gl_scanout_texture(int qid, uint32_t w, uint32_t h, uint32_t fourcc) "%d %dx%d, fourcc 0x%x" +qemu_spice_gl_update(int qid, uint32_t x, uint32_t y, uint32_t w, uint32_t h) "%d +%d+%d %dx%d" # ui/keymaps.c keymap_parse(const char *file) "file %s" From cd2452b279b217d7e6ee48478d6bb3109f388fcb Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 8 Mar 2018 10:06:16 +0100 Subject: [PATCH 12/14] spice: add scanout_dmabuf support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for scanout dmabufs. Just pass them through to spice-server. Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau Message-id: 20180308090618.30147-3-kraxel@redhat.com --- ui/spice-display.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ui/spice-display.c b/ui/spice-display.c index 79ea4df02c..4c33c92ae5 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -936,6 +936,20 @@ static void qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl, ssd->have_scanout = true; } +static void qemu_spice_gl_scanout_dmabuf(DisplayChangeListener *dcl, + QemuDmaBuf *dmabuf) +{ + SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); + + /* note: spice server will close the fd, so hand over a dup */ + spice_qxl_gl_scanout(&ssd->qxl, dup(dmabuf->fd), + dmabuf->width, dmabuf->height, + dmabuf->stride, dmabuf->fourcc, false); + qemu_spice_gl_monitor_config(ssd, 0, 0, dmabuf->width, dmabuf->height); + ssd->have_surface = false; + ssd->have_scanout = true; +} + static void qemu_spice_gl_update(DisplayChangeListener *dcl, uint32_t x, uint32_t y, uint32_t w, uint32_t h) { @@ -969,6 +983,7 @@ static const DisplayChangeListenerOps display_listener_gl_ops = { .dpy_gl_scanout_disable = qemu_spice_gl_scanout_disable, .dpy_gl_scanout_texture = qemu_spice_gl_scanout_texture, + .dpy_gl_scanout_dmabuf = qemu_spice_gl_scanout_dmabuf, .dpy_gl_update = qemu_spice_gl_update, }; From b153f9019b5fcf7c085de688b123eb34f924f870 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 8 Mar 2018 10:06:17 +0100 Subject: [PATCH 13/14] spice: add cursor_dmabuf support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for cursor dmabufs. qemu has to render the cursor for that, so in case a cursor is present qemu allocates a new dmabuf, blits the scanout, blends in the pointer and passes on the new dmabuf to spice-server. Without cursor qemu continues to simply pass on the scanout dmabuf as-is. Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau Message-id: 20180308090618.30147-4-kraxel@redhat.com --- include/ui/spice-display.h | 9 +++ ui/spice-display.c | 114 +++++++++++++++++++++++++++++++++++-- ui/trace-events | 3 + 3 files changed, 121 insertions(+), 5 deletions(-) diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h index 6b5c73b21c..87a84a59d4 100644 --- a/include/ui/spice-display.h +++ b/include/ui/spice-display.h @@ -122,6 +122,15 @@ struct SimpleSpiceDisplay { int gl_updates; bool have_scanout; bool have_surface; + + QemuDmaBuf *guest_dmabuf; + bool guest_dmabuf_refresh; + bool render_cursor; + + egl_fb guest_fb; + egl_fb blit_fb; + egl_fb cursor_fb; + bool have_hot; #endif }; diff --git a/ui/spice-display.c b/ui/spice-display.c index 4c33c92ae5..fe734821dd 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -941,25 +941,126 @@ static void qemu_spice_gl_scanout_dmabuf(DisplayChangeListener *dcl, { SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); - /* note: spice server will close the fd, so hand over a dup */ - spice_qxl_gl_scanout(&ssd->qxl, dup(dmabuf->fd), - dmabuf->width, dmabuf->height, - dmabuf->stride, dmabuf->fourcc, false); - qemu_spice_gl_monitor_config(ssd, 0, 0, dmabuf->width, dmabuf->height); + ssd->guest_dmabuf = dmabuf; + ssd->guest_dmabuf_refresh = true; + ssd->have_surface = false; ssd->have_scanout = true; } +static void qemu_spice_gl_cursor_dmabuf(DisplayChangeListener *dcl, + QemuDmaBuf *dmabuf, bool have_hot, + uint32_t hot_x, uint32_t hot_y) +{ + SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); + + ssd->have_hot = have_hot; + ssd->hot_x = hot_x; + ssd->hot_y = hot_y; + + trace_qemu_spice_gl_cursor(ssd->qxl.id, dmabuf != NULL, have_hot); + if (dmabuf) { + egl_dmabuf_import_texture(dmabuf); + if (!dmabuf->texture) { + return; + } + egl_fb_setup_for_tex(&ssd->cursor_fb, dmabuf->width, dmabuf->height, + dmabuf->texture, false); + } else { + egl_fb_destroy(&ssd->cursor_fb); + } +} + +static void qemu_spice_gl_cursor_position(DisplayChangeListener *dcl, + uint32_t pos_x, uint32_t pos_y) +{ + SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); + + ssd->ptr_x = pos_x; + ssd->ptr_y = pos_y; +} + +static void qemu_spice_gl_release_dmabuf(DisplayChangeListener *dcl, + QemuDmaBuf *dmabuf) +{ + SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); + + if (ssd->guest_dmabuf == dmabuf) { + ssd->guest_dmabuf = NULL; + ssd->guest_dmabuf_refresh = false; + } + egl_dmabuf_release_texture(dmabuf); +} + static void qemu_spice_gl_update(DisplayChangeListener *dcl, uint32_t x, uint32_t y, uint32_t w, uint32_t h) { SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); + EGLint stride = 0, fourcc = 0; + bool render_cursor = false; + bool y_0_top = false; /* FIXME */ uint64_t cookie; + int fd; if (!ssd->have_scanout) { return; } + if (ssd->cursor_fb.texture) { + render_cursor = true; + } + if (ssd->render_cursor != render_cursor) { + ssd->render_cursor = render_cursor; + ssd->guest_dmabuf_refresh = true; + egl_fb_destroy(&ssd->blit_fb); + } + + if (ssd->guest_dmabuf_refresh) { + QemuDmaBuf *dmabuf = ssd->guest_dmabuf; + if (render_cursor) { + egl_dmabuf_import_texture(dmabuf); + if (!dmabuf->texture) { + return; + } + + /* source framebuffer */ + egl_fb_setup_for_tex(&ssd->guest_fb, + dmabuf->width, dmabuf->height, + dmabuf->texture, false); + + /* dest framebuffer */ + if (ssd->blit_fb.width != dmabuf->width || + ssd->blit_fb.height != dmabuf->height) { + trace_qemu_spice_gl_render_dmabuf(ssd->qxl.id, dmabuf->width, + dmabuf->height); + egl_fb_destroy(&ssd->blit_fb); + egl_fb_setup_new_tex(&ssd->blit_fb, + dmabuf->width, dmabuf->height); + fd = egl_get_fd_for_texture(ssd->blit_fb.texture, + &stride, &fourcc); + spice_qxl_gl_scanout(&ssd->qxl, fd, + dmabuf->width, dmabuf->height, + stride, fourcc, false); + } + } else { + trace_qemu_spice_gl_forward_dmabuf(ssd->qxl.id, + dmabuf->width, dmabuf->height); + /* note: spice server will close the fd, so hand over a dup */ + spice_qxl_gl_scanout(&ssd->qxl, dup(dmabuf->fd), + dmabuf->width, dmabuf->height, + dmabuf->stride, dmabuf->fourcc, false); + } + qemu_spice_gl_monitor_config(ssd, 0, 0, dmabuf->width, dmabuf->height); + ssd->guest_dmabuf_refresh = false; + } + + if (render_cursor) { + egl_texture_blit(ssd->gls, &ssd->blit_fb, &ssd->guest_fb, + !y_0_top); + egl_texture_blend(ssd->gls, &ssd->blit_fb, &ssd->cursor_fb, + !y_0_top, ssd->ptr_x, ssd->ptr_y); + glFlush(); + } trace_qemu_spice_gl_update(ssd->qxl.id, w, h, x, y); qemu_spice_gl_block(ssd, true); @@ -984,6 +1085,9 @@ static const DisplayChangeListenerOps display_listener_gl_ops = { .dpy_gl_scanout_disable = qemu_spice_gl_scanout_disable, .dpy_gl_scanout_texture = qemu_spice_gl_scanout_texture, .dpy_gl_scanout_dmabuf = qemu_spice_gl_scanout_dmabuf, + .dpy_gl_cursor_dmabuf = qemu_spice_gl_cursor_dmabuf, + .dpy_gl_cursor_position = qemu_spice_gl_cursor_position, + .dpy_gl_release_dmabuf = qemu_spice_gl_release_dmabuf, .dpy_gl_update = qemu_spice_gl_update, }; diff --git a/ui/trace-events b/ui/trace-events index 518e950a01..a957f363f1 100644 --- a/ui/trace-events +++ b/ui/trace-events @@ -83,6 +83,9 @@ qemu_spice_ui_info(int qid, uint32_t width, uint32_t height) "%d %dx%d" qemu_spice_gl_surface(int qid, uint32_t w, uint32_t h, uint32_t fourcc) "%d %dx%d, fourcc 0x%x" qemu_spice_gl_scanout_disable(int qid) "%d" qemu_spice_gl_scanout_texture(int qid, uint32_t w, uint32_t h, uint32_t fourcc) "%d %dx%d, fourcc 0x%x" +qemu_spice_gl_cursor(int qid, bool enabled, bool hotspot) "%d enabled %d, hotspot %d" +qemu_spice_gl_forward_dmabuf(int qid, uint32_t width, uint32_t height) "%d %dx%d" +qemu_spice_gl_render_dmabuf(int qid, uint32_t width, uint32_t height) "%d %dx%d" qemu_spice_gl_update(int qid, uint32_t x, uint32_t y, uint32_t w, uint32_t h) "%d +%d+%d %dx%d" # ui/keymaps.c From f771c5440e04626f1cf9a6a7d1b1c6cd8168cacd Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 5 Mar 2018 17:37:48 +0100 Subject: [PATCH 14/14] qapi: Add device ID and head parameters to screendump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU's screendump command can only take dumps from the primary display. When using multiple VGA cards, there is no way to get a dump from a secondary card or other display heads yet. So let's add a 'device' and a 'head' parameter to the HMP and QMP commands to be able to specify alternative devices and heads with the screendump command, too. Reviewed-by: Daniel P. Berrangé Acked-by: Dr. David Alan Gilbert Reviewed-by: Gerd Hoffmann Signed-off-by: Thomas Huth Reviewed-by: Eric Blake Message-id: 1520267868-31778-1-git-send-email-thuth@redhat.com Signed-off-by: Gerd Hoffmann --- hmp-commands.hx | 7 ++++--- hmp.c | 4 +++- qapi/ui.json | 10 +++++++++- ui/console.c | 24 +++++++++++++++++++----- 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 964eb515cf..1723cbe1df 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -253,9 +253,10 @@ ETEXI { .name = "screendump", - .args_type = "filename:F", - .params = "filename", - .help = "save screen into PPM image 'filename'", + .args_type = "filename:F,device:s?,head:i?", + .params = "filename [device [head]]", + .help = "save screen from head 'head' of display device 'device' " + "into PPM image 'filename'", .cmd = hmp_screendump, }, diff --git a/hmp.c b/hmp.c index 016cb5c4f1..ba9e299ee2 100644 --- a/hmp.c +++ b/hmp.c @@ -2140,9 +2140,11 @@ err_out: void hmp_screendump(Monitor *mon, const QDict *qdict) { const char *filename = qdict_get_str(qdict, "filename"); + const char *id = qdict_get_try_str(qdict, "device"); + int64_t head = qdict_get_try_int(qdict, "head", 0); Error *err = NULL; - qmp_screendump(filename, &err); + qmp_screendump(filename, id != NULL, id, id != NULL, head, &err); hmp_handle_error(mon, &err); } diff --git a/qapi/ui.json b/qapi/ui.json index 3e82f25ac5..5d01ad4304 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -77,6 +77,13 @@ # # @filename: the path of a new PPM file to store the image # +# @device: ID of the display device that should be dumped. If this parameter +# is missing, the primary display will be used. (Since 2.12) +# +# @head: head to use in case the device supports multiple heads. If this +# parameter is missing, head #0 will be used. Also note that the head +# can only be specified in conjunction with the device ID. (Since 2.12) +# # Returns: Nothing on success # # Since: 0.14.0 @@ -88,7 +95,8 @@ # <- { "return": {} } # ## -{ 'command': 'screendump', 'data': {'filename': 'str'} } +{ 'command': 'screendump', + 'data': {'filename': 'str', '*device': 'str', '*head': 'int'} } ## # == Spice diff --git a/ui/console.c b/ui/console.c index 348610dd43..a8868fc04f 100644 --- a/ui/console.c +++ b/ui/console.c @@ -344,14 +344,28 @@ write_err: goto out; } -void qmp_screendump(const char *filename, Error **errp) +void qmp_screendump(const char *filename, bool has_device, const char *device, + bool has_head, int64_t head, Error **errp) { - QemuConsole *con = qemu_console_lookup_by_index(0); + QemuConsole *con; DisplaySurface *surface; - if (con == NULL) { - error_setg(errp, "There is no QemuConsole I can screendump from."); - return; + if (has_device) { + con = qemu_console_lookup_by_device_name(device, has_head ? head : 0, + errp); + if (!con) { + return; + } + } else { + if (has_head) { + error_setg(errp, "'head' must be specified together with 'device'"); + return; + } + con = qemu_console_lookup_by_index(0); + if (!con) { + error_setg(errp, "There is no console to take a screendump from"); + return; + } } graphic_hw_update(con);