gtk,spice: add dmabuf support.
sdl,vnc,gtk: bugfixes. ui/qapi: add device ID and head parameters to screendump. build: try improve handling of clang warnings. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJapkS4AAoJEEy22O7T6HE4868P/i1HqNsrWjvQOlslHSiqa+L+ t1YYM47qdy+Qv12z9wc5dVYLZy6xhKqUE41Ks/5IdeDmOmnSJSU6YNnQsav0BNwJ RDsaahiIVHyWN5cihZeL9aZvw6c+2GjJ2oBJbLgeogqukKuHluEfcSXfUPT3AT+M yGZe3jqQXqSqdG9B3yYxejFOnlAy26HlqD9CmTeqs9es2m9kUq3b/0EQaJd4BwiU 1ObNqJy32t+6NjIlhlgUAFuZm+M+E/gCFQqjfnERiQPzMuE3d2go87mHfZ3LkvSl dCOrQJ7kEFJB2hjppVvm8NtpQ9QUS4KXpwqtyJEh6+cuHVpgOxBNUyeiSV3ItjQa tMlFsFIpR4YBD/Gj5pbx8doqfSpFV8tMv62ncCrfsC2/8XqGtLO33DZPguJDJOee qg8hzc7VIZmuT4fpjyMDzOkGG6X5fKnSSRvnpEkswBz0Vyf8t/0B029ksr9Jxger AvrOB96LWVW8mR1ksI/HO3iMkDeQP/xiHGUh4Cy1cR+qJuVVKNwXBQHg3viDcpbV YdoBG5CQ2MDsI7v3XvNihCqLFMZ2OigpAGLDe4a26IR/3Rz+0XEIdtfZHcGbxJ6l 4cAb4JP+DOgVGGLyRBW+bDcg7q4BXwCp77mzipcsocnMu/HtZ5uoSH+EKFkKLcnP PKpab2lurVbG9oqYfD1P =3Hmp -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kraxel/tags/ui-20180312-pull-request' into staging gtk,spice: add dmabuf support. sdl,vnc,gtk: bugfixes. ui/qapi: add device ID and head parameters to screendump. build: try improve handling of clang warnings. # gpg: Signature made Mon 12 Mar 2018 09:13:28 GMT # gpg: using RSA key 4CB6D8EED3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" # Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138 * remotes/kraxel/tags/ui-20180312-pull-request: qapi: Add device ID and head parameters to screendump spice: add cursor_dmabuf support spice: add scanout_dmabuf support spice: drop dprint() debug logging vnc: deal with surface NULL pointers ui/gtk-egl: add cursor_dmabuf support ui/gtk-egl: add scanout_dmabuf support ui/gtk: use GtkGlArea on wayland only ui/opengl: Makefile cleanup ui/gtk: group gtk.mo declarations in Makefile ui/gtk: make GtkGlArea usage a runtime option sdl: workaround bug in sdl 2.0.8 headers make: switch language file build to be gtk module aware build: try improve handling of clang warnings Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
b16a54da06
2
Makefile
2
Makefile
|
@ -851,7 +851,7 @@ ifneq ($(BLOBS),)
|
||||||
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \
|
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \
|
||||||
done
|
done
|
||||||
endif
|
endif
|
||||||
ifeq ($(CONFIG_GTK),y)
|
ifeq ($(CONFIG_GTK),m)
|
||||||
$(MAKE) -C po $@
|
$(MAKE) -C po $@
|
||||||
endif
|
endif
|
||||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/keymaps"
|
$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/keymaps"
|
||||||
|
|
3
configure
vendored
3
configure
vendored
|
@ -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="-Wendif-labels -Wno-shift-negative-value $gcc_flags"
|
||||||
gcc_flags="-Wno-initializer-overrides -Wexpansion-to-defined $gcc_flags"
|
gcc_flags="-Wno-initializer-overrides -Wexpansion-to-defined $gcc_flags"
|
||||||
gcc_flags="-Wno-string-plus-int $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
|
# 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
|
# enable it for all configure tests. If a configure test failed due
|
||||||
# to -Werror this would just silently disable some features,
|
# to -Werror this would just silently disable some features,
|
||||||
|
@ -2874,6 +2875,7 @@ if test "$sdl" != "no" ; then
|
||||||
int main( void ) { return SDL_Init (SDL_INIT_VIDEO); }
|
int main( void ) { return SDL_Init (SDL_INIT_VIDEO); }
|
||||||
EOF
|
EOF
|
||||||
sdl_cflags=$($sdlconfig --cflags 2>/dev/null)
|
sdl_cflags=$($sdlconfig --cflags 2>/dev/null)
|
||||||
|
sdl_cflags="$sdl_cflags -Wno-undef" # workaround 2.0.8 bug
|
||||||
if test "$static" = "yes" ; then
|
if test "$static" = "yes" ; then
|
||||||
if $pkg_config $sdlname --exists; then
|
if $pkg_config $sdlname --exists; then
|
||||||
sdl_libs=$($pkg_config $sdlname --static --libs 2>/dev/null)
|
sdl_libs=$($pkg_config $sdlname --static --libs 2>/dev/null)
|
||||||
|
@ -4860,7 +4862,6 @@ fi
|
||||||
pragma_disable_unused_but_set=no
|
pragma_disable_unused_but_set=no
|
||||||
cat > $TMPC << EOF
|
cat > $TMPC << EOF
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
|
||||||
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
|
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
|
|
@ -253,9 +253,10 @@ ETEXI
|
||||||
|
|
||||||
{
|
{
|
||||||
.name = "screendump",
|
.name = "screendump",
|
||||||
.args_type = "filename:F",
|
.args_type = "filename:F,device:s?,head:i?",
|
||||||
.params = "filename",
|
.params = "filename [device [head]]",
|
||||||
.help = "save screen into PPM image 'filename'",
|
.help = "save screen from head 'head' of display device 'device' "
|
||||||
|
"into PPM image 'filename'",
|
||||||
.cmd = hmp_screendump,
|
.cmd = hmp_screendump,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
4
hmp.c
4
hmp.c
|
@ -2140,9 +2140,11 @@ err_out:
|
||||||
void hmp_screendump(Monitor *mon, const QDict *qdict)
|
void hmp_screendump(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
const char *filename = qdict_get_str(qdict, "filename");
|
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;
|
Error *err = NULL;
|
||||||
|
|
||||||
qmp_screendump(filename, &err);
|
qmp_screendump(filename, id != NULL, id, id != NULL, head, &err);
|
||||||
hmp_handle_error(mon, &err);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -260,6 +260,8 @@ DisplaySurface *qemu_create_displaysurface_guestmem(int width, int height,
|
||||||
pixman_format_code_t format,
|
pixman_format_code_t format,
|
||||||
int linesize,
|
int linesize,
|
||||||
uint64_t addr);
|
uint64_t addr);
|
||||||
|
DisplaySurface *qemu_create_message_surface(int w, int h,
|
||||||
|
const char *msg);
|
||||||
PixelFormat qemu_default_pixelformat(int bpp);
|
PixelFormat qemu_default_pixelformat(int bpp);
|
||||||
|
|
||||||
DisplaySurface *qemu_create_displaysurface(int width, int height);
|
DisplaySurface *qemu_create_displaysurface(int width, int height);
|
||||||
|
|
|
@ -54,6 +54,9 @@ typedef struct VirtualGfxConsole {
|
||||||
int x, y, w, h;
|
int x, y, w, h;
|
||||||
egl_fb guest_fb;
|
egl_fb guest_fb;
|
||||||
egl_fb win_fb;
|
egl_fb win_fb;
|
||||||
|
egl_fb cursor_fb;
|
||||||
|
int cursor_x;
|
||||||
|
int cursor_y;
|
||||||
bool y0_top;
|
bool y0_top;
|
||||||
bool scanout_mode;
|
bool scanout_mode;
|
||||||
#endif
|
#endif
|
||||||
|
@ -90,6 +93,8 @@ typedef struct VirtualConsole {
|
||||||
};
|
};
|
||||||
} VirtualConsole;
|
} VirtualConsole;
|
||||||
|
|
||||||
|
extern bool gtk_use_gl_area;
|
||||||
|
|
||||||
/* ui/gtk.c */
|
/* ui/gtk.c */
|
||||||
void gd_update_windowsize(VirtualConsole *vc);
|
void gd_update_windowsize(VirtualConsole *vc);
|
||||||
|
|
||||||
|
@ -111,6 +116,15 @@ void gd_egl_scanout_texture(DisplayChangeListener *dcl,
|
||||||
uint32_t backing_height,
|
uint32_t backing_height,
|
||||||
uint32_t x, uint32_t y,
|
uint32_t x, uint32_t y,
|
||||||
uint32_t w, uint32_t h);
|
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,
|
void gd_egl_scanout_flush(DisplayChangeListener *dcl,
|
||||||
uint32_t x, uint32_t y, uint32_t w, uint32_t h);
|
uint32_t x, uint32_t y, uint32_t w, uint32_t h);
|
||||||
void gtk_egl_init(void);
|
void gtk_egl_init(void);
|
||||||
|
|
|
@ -122,6 +122,15 @@ struct SimpleSpiceDisplay {
|
||||||
int gl_updates;
|
int gl_updates;
|
||||||
bool have_scanout;
|
bool have_scanout;
|
||||||
bool have_surface;
|
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
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
10
qapi/ui.json
10
qapi/ui.json
|
@ -77,6 +77,13 @@
|
||||||
#
|
#
|
||||||
# @filename: the path of a new PPM file to store the image
|
# @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
|
# Returns: Nothing on success
|
||||||
#
|
#
|
||||||
# Since: 0.14.0
|
# Since: 0.14.0
|
||||||
|
@ -88,7 +95,8 @@
|
||||||
# <- { "return": {} }
|
# <- { "return": {} }
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
{ 'command': 'screendump', 'data': {'filename': 'str'} }
|
{ 'command': 'screendump',
|
||||||
|
'data': {'filename': 'str', '*device': 'str', '*head': 'int'} }
|
||||||
|
|
||||||
##
|
##
|
||||||
# == Spice
|
# == Spice
|
||||||
|
|
|
@ -38,26 +38,27 @@ common-obj-$(CONFIG_GTK) += gtk.mo
|
||||||
gtk.mo-objs := gtk.o
|
gtk.mo-objs := gtk.o
|
||||||
gtk.mo-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS)
|
gtk.mo-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS)
|
||||||
gtk.mo-libs := $(GTK_LIBS) $(VTE_LIBS)
|
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
|
common-obj-$(CONFIG_CURSES) += curses.mo
|
||||||
curses.mo-objs := curses.o
|
curses.mo-objs := curses.o
|
||||||
curses.mo-cflags := $(CURSES_CFLAGS)
|
curses.mo-cflags := $(CURSES_CFLAGS)
|
||||||
curses.mo-libs := $(CURSES_LIBS)
|
curses.mo-libs := $(CURSES_LIBS)
|
||||||
|
|
||||||
ifeq ($(CONFIG_OPENGL),y)
|
common-obj-$(CONFIG_OPENGL) += shader.o
|
||||||
common-obj-y += shader.o
|
common-obj-$(CONFIG_OPENGL) += console-gl.o
|
||||||
common-obj-y += console-gl.o
|
common-obj-$(CONFIG_OPENGL) += egl-helpers.o
|
||||||
common-obj-y += egl-helpers.o
|
common-obj-$(CONFIG_OPENGL) += egl-context.o
|
||||||
common-obj-y += egl-context.o
|
|
||||||
common-obj-$(CONFIG_OPENGL_DMABUF) += egl-headless.o
|
common-obj-$(CONFIG_OPENGL_DMABUF) += egl-headless.o
|
||||||
ifeq ($(CONFIG_GTK_GL),y)
|
|
||||||
gtk.mo-objs += gtk-gl-area.o
|
|
||||||
else
|
|
||||||
gtk.mo-objs += gtk-egl.o
|
|
||||||
gtk.mo-libs += $(OPENGL_LIBS)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
shader.o-libs += $(OPENGL_LIBS)
|
shader.o-libs += $(OPENGL_LIBS)
|
||||||
console-gl.o-libs += $(OPENGL_LIBS)
|
console-gl.o-libs += $(OPENGL_LIBS)
|
||||||
egl-helpers.o-libs += $(OPENGL_LIBS)
|
egl-helpers.o-libs += $(OPENGL_LIBS)
|
||||||
|
egl-context.o-libs += $(OPENGL_LIBS)
|
||||||
|
egl-headless.o-libs += $(OPENGL_LIBS)
|
||||||
|
|
34
ui/console.c
34
ui/console.c
|
@ -344,14 +344,28 @@ write_err:
|
||||||
goto out;
|
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;
|
DisplaySurface *surface;
|
||||||
|
|
||||||
if (con == NULL) {
|
if (has_device) {
|
||||||
error_setg(errp, "There is no QemuConsole I can screendump from.");
|
con = qemu_console_lookup_by_device_name(device, has_head ? head : 0,
|
||||||
return;
|
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);
|
graphic_hw_update(con);
|
||||||
|
@ -1039,8 +1053,10 @@ void console_select(unsigned int index)
|
||||||
dcl->ops->dpy_gfx_switch(dcl, s->surface);
|
dcl->ops->dpy_gfx_switch(dcl, s->surface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dpy_gfx_update(s, 0, 0, surface_width(s->surface),
|
if (s->surface) {
|
||||||
surface_height(s->surface));
|
dpy_gfx_update(s, 0, 0, surface_width(s->surface),
|
||||||
|
surface_height(s->surface));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ds->have_text) {
|
if (ds->have_text) {
|
||||||
dpy_text_resize(s, s->width, s->height);
|
dpy_text_resize(s, s->width, s->height);
|
||||||
|
@ -1370,8 +1386,8 @@ DisplaySurface *qemu_create_displaysurface_guestmem(int width, int height,
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DisplaySurface *qemu_create_message_surface(int w, int h,
|
DisplaySurface *qemu_create_message_surface(int w, int h,
|
||||||
const char *msg)
|
const char *msg)
|
||||||
{
|
{
|
||||||
DisplaySurface *surface = qemu_create_displaysurface(w, h);
|
DisplaySurface *surface = qemu_create_displaysurface(w, h);
|
||||||
pixman_color_t bg = color_table_rgb[0][QEMU_COLOR_BLACK];
|
pixman_color_t bg = color_table_rgb[0][QEMU_COLOR_BLACK];
|
||||||
|
|
63
ui/gtk-egl.c
63
ui/gtk-egl.c
|
@ -19,6 +19,7 @@
|
||||||
#include "ui/console.h"
|
#include "ui/console.h"
|
||||||
#include "ui/gtk.h"
|
#include "ui/gtk.h"
|
||||||
#include "ui/egl-helpers.h"
|
#include "ui/egl-helpers.h"
|
||||||
|
#include "ui/shader.h"
|
||||||
|
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
|
|
||||||
|
@ -194,6 +195,58 @@ void gd_egl_scanout_texture(DisplayChangeListener *dcl,
|
||||||
backing_id, false);
|
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_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)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_OPENGL_DMABUF
|
||||||
|
egl_dmabuf_release_texture(dmabuf);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void gd_egl_scanout_flush(DisplayChangeListener *dcl,
|
void gd_egl_scanout_flush(DisplayChangeListener *dcl,
|
||||||
uint32_t x, uint32_t y, uint32_t w, uint32_t h)
|
uint32_t x, uint32_t y, uint32_t w, uint32_t h)
|
||||||
{
|
{
|
||||||
|
@ -214,7 +267,15 @@ void gd_egl_scanout_flush(DisplayChangeListener *dcl,
|
||||||
window = gtk_widget_get_window(vc->gfx.drawing_area);
|
window = gtk_widget_get_window(vc->gfx.drawing_area);
|
||||||
gdk_drawable_get_size(window, &ww, &wh);
|
gdk_drawable_get_size(window, &ww, &wh);
|
||||||
egl_fb_setup_default(&vc->gfx.win_fb, 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);
|
eglSwapBuffers(qemu_egl_display, vc->gfx.esurface);
|
||||||
}
|
}
|
||||||
|
|
68
ui/gtk.c
68
ui/gtk.c
|
@ -243,6 +243,8 @@ typedef struct VCChardev {
|
||||||
#define TYPE_CHARDEV_VC "chardev-vc"
|
#define TYPE_CHARDEV_VC "chardev-vc"
|
||||||
#define VC_CHARDEV(obj) OBJECT_CHECK(VCChardev, (obj), TYPE_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_grab_pointer(VirtualConsole *vc, const char *reason);
|
||||||
static void gd_ungrab_pointer(GtkDisplayState *s);
|
static void gd_ungrab_pointer(GtkDisplayState *s);
|
||||||
static void gd_grab_keyboard(VirtualConsole *vc, const char *reason);
|
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;
|
int ww, wh;
|
||||||
gdk_drawable_get_size(gtk_widget_get_window(area), &ww, &wh);
|
gdk_drawable_get_size(gtk_widget_get_window(area), &ww, &wh);
|
||||||
#if defined(CONFIG_GTK_GL)
|
#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));
|
gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -725,7 +727,7 @@ static const DisplayChangeListenerOps dcl_gl_area_ops = {
|
||||||
.dpy_gl_update = gd_gl_area_scanout_flush,
|
.dpy_gl_update = gd_gl_area_scanout_flush,
|
||||||
};
|
};
|
||||||
|
|
||||||
#else
|
#endif /* CONFIG_GTK_GL */
|
||||||
|
|
||||||
static const DisplayChangeListenerOps dcl_egl_ops = {
|
static const DisplayChangeListenerOps dcl_egl_ops = {
|
||||||
.dpy_name = "gtk-egl",
|
.dpy_name = "gtk-egl",
|
||||||
|
@ -742,10 +744,13 @@ static const DisplayChangeListenerOps dcl_egl_ops = {
|
||||||
.dpy_gl_ctx_get_current = qemu_egl_get_current_context,
|
.dpy_gl_ctx_get_current = qemu_egl_get_current_context,
|
||||||
.dpy_gl_scanout_disable = gd_egl_scanout_disable,
|
.dpy_gl_scanout_disable = gd_egl_scanout_disable,
|
||||||
.dpy_gl_scanout_texture = gd_egl_scanout_texture,
|
.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,
|
.dpy_gl_update = gd_egl_scanout_flush,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* CONFIG_GTK_GL */
|
|
||||||
#endif /* CONFIG_OPENGL */
|
#endif /* CONFIG_OPENGL */
|
||||||
|
|
||||||
/** QEMU Events **/
|
/** QEMU Events **/
|
||||||
|
@ -844,13 +849,13 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
|
||||||
|
|
||||||
#if defined(CONFIG_OPENGL)
|
#if defined(CONFIG_OPENGL)
|
||||||
if (vc->gfx.gls) {
|
if (vc->gfx.gls) {
|
||||||
#if defined(CONFIG_GTK_GL)
|
if (gtk_use_gl_area) {
|
||||||
/* invoke render callback please */
|
/* invoke render callback please */
|
||||||
return FALSE;
|
return FALSE;
|
||||||
#else
|
} else {
|
||||||
gd_egl_draw(vc);
|
gd_egl_draw(vc);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
#endif
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1993,7 +1998,7 @@ static void gd_connect_vc_gfx_signals(VirtualConsole *vc)
|
||||||
g_signal_connect(vc->gfx.drawing_area, "draw",
|
g_signal_connect(vc->gfx.drawing_area, "draw",
|
||||||
G_CALLBACK(gd_draw_event), vc);
|
G_CALLBACK(gd_draw_event), vc);
|
||||||
#if defined(CONFIG_GTK_GL)
|
#if defined(CONFIG_GTK_GL)
|
||||||
if (display_opengl) {
|
if (gtk_use_gl_area) {
|
||||||
/* wire up GtkGlArea events */
|
/* wire up GtkGlArea events */
|
||||||
g_signal_connect(vc->gfx.drawing_area, "render",
|
g_signal_connect(vc->gfx.drawing_area, "render",
|
||||||
G_CALLBACK(gd_render_event), vc);
|
G_CALLBACK(gd_render_event), vc);
|
||||||
|
@ -2116,26 +2121,29 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
|
||||||
#if defined(CONFIG_OPENGL)
|
#if defined(CONFIG_OPENGL)
|
||||||
if (display_opengl) {
|
if (display_opengl) {
|
||||||
#if defined(CONFIG_GTK_GL)
|
#if defined(CONFIG_GTK_GL)
|
||||||
vc->gfx.drawing_area = gtk_gl_area_new();
|
if (gtk_use_gl_area) {
|
||||||
vc->gfx.dcl.ops = &dcl_gl_area_ops;
|
vc->gfx.drawing_area = gtk_gl_area_new();
|
||||||
#else
|
vc->gfx.dcl.ops = &dcl_gl_area_ops;
|
||||||
vc->gfx.drawing_area = gtk_drawing_area_new();
|
} else
|
||||||
/*
|
#endif /* CONFIG_GTK_GL */
|
||||||
* gtk_widget_set_double_buffered() was deprecated in 3.14.
|
{
|
||||||
* It is required for opengl rendering on X11 though. A
|
vc->gfx.drawing_area = gtk_drawing_area_new();
|
||||||
* proper replacement (native opengl support) is only
|
/*
|
||||||
* available in 3.16+. Silence the warning if possible.
|
* 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
|
#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
#endif
|
#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
|
#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
vc->gfx.dcl.ops = &dcl_egl_ops;
|
vc->gfx.dcl.ops = &dcl_egl_ops;
|
||||||
#endif /* CONFIG_GTK_GL */
|
}
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@ -2436,11 +2444,15 @@ static void early_gtk_display_init(DisplayOptions *opts)
|
||||||
assert(opts->type == DISPLAY_TYPE_GTK);
|
assert(opts->type == DISPLAY_TYPE_GTK);
|
||||||
if (opts->has_gl && opts->gl) {
|
if (opts->has_gl && opts->gl) {
|
||||||
#if defined(CONFIG_OPENGL)
|
#if defined(CONFIG_OPENGL)
|
||||||
#if defined(CONFIG_GTK_GL)
|
#if defined(CONFIG_GTK_GL) && defined(GDK_WINDOWING_WAYLAND)
|
||||||
gtk_gl_area_init();
|
if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) {
|
||||||
#else
|
gtk_use_gl_area = true;
|
||||||
gtk_egl_init();
|
gtk_gl_area_init();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
gtk_egl_init();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,20 +26,8 @@
|
||||||
|
|
||||||
#include "ui/spice-display.h"
|
#include "ui/spice-display.h"
|
||||||
|
|
||||||
static int debug = 0;
|
|
||||||
bool spice_opengl;
|
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)
|
int qemu_spice_rect_is_empty(const QXLRect* r)
|
||||||
{
|
{
|
||||||
return r->top == r->bottom || r->left == r->right;
|
return r->top == r->bottom || r->left == r->right;
|
||||||
|
@ -322,8 +310,6 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
|
||||||
{
|
{
|
||||||
QXLDevMemSlot memslot;
|
QXLDevMemSlot memslot;
|
||||||
|
|
||||||
dprint(1, "%s/%d:\n", __func__, ssd->qxl.id);
|
|
||||||
|
|
||||||
memset(&memslot, 0, sizeof(memslot));
|
memset(&memslot, 0, sizeof(memslot));
|
||||||
memslot.slot_group_id = MEMSLOT_GROUP_HOST;
|
memslot.slot_group_id = MEMSLOT_GROUP_HOST;
|
||||||
memslot.virt_end = ~0;
|
memslot.virt_end = ~0;
|
||||||
|
@ -347,10 +333,6 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
|
||||||
ssd->buf = g_malloc(ssd->bufsize);
|
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.format = SPICE_SURFACE_FMT_32_xRGB;
|
||||||
surface.width = surface_width(ssd->ds);
|
surface.width = surface_width(ssd->ds);
|
||||||
surface.height = surface_height(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)
|
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);
|
qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,8 +369,7 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
|
||||||
{
|
{
|
||||||
QXLRect update_area;
|
QXLRect update_area;
|
||||||
|
|
||||||
dprint(2, "%s/%d: x %d y %d w %d h %d\n", __func__,
|
trace_qemu_spice_display_update(ssd->qxl.id, x, y, w, h);
|
||||||
ssd->qxl.id, x, y, w, h);
|
|
||||||
update_area.left = x,
|
update_area.left = x,
|
||||||
update_area.right = x + w;
|
update_area.right = x + w;
|
||||||
update_area.top = y;
|
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_height(surface) == pixman_image_get_height(ssd->surface) &&
|
||||||
surface_format(surface) == pixman_image_get_format(ssd->surface)) {
|
surface_format(surface) == pixman_image_get_format(ssd->surface)) {
|
||||||
/* no-resize fast path: just swap backing store */
|
/* no-resize fast path: just swap backing store */
|
||||||
dprint(1, "%s/%d: fast (%dx%d)\n", __func__, ssd->qxl.id,
|
trace_qemu_spice_display_surface(ssd->qxl.id,
|
||||||
surface_width(surface), surface_height(surface));
|
surface_width(surface),
|
||||||
|
surface_height(surface),
|
||||||
|
true);
|
||||||
qemu_mutex_lock(&ssd->lock);
|
qemu_mutex_lock(&ssd->lock);
|
||||||
ssd->ds = surface;
|
ssd->ds = surface;
|
||||||
pixman_image_unref(ssd->surface);
|
pixman_image_unref(ssd->surface);
|
||||||
|
@ -427,11 +408,10 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* full mode switch */
|
/* full mode switch */
|
||||||
dprint(1, "%s/%d: full (%dx%d -> %dx%d)\n", __func__, ssd->qxl.id,
|
trace_qemu_spice_display_surface(ssd->qxl.id,
|
||||||
ssd->surface ? pixman_image_get_width(ssd->surface) : 0,
|
surface ? surface_width(surface) : 0,
|
||||||
ssd->surface ? pixman_image_get_height(ssd->surface) : 0,
|
surface ? surface_height(surface) : 0,
|
||||||
surface ? surface_width(surface) : 0,
|
false);
|
||||||
surface ? surface_height(surface) : 0);
|
|
||||||
|
|
||||||
memset(&ssd->dirty, 0, sizeof(ssd->dirty));
|
memset(&ssd->dirty, 0, sizeof(ssd->dirty));
|
||||||
if (ssd->surface) {
|
if (ssd->surface) {
|
||||||
|
@ -495,7 +475,6 @@ void qemu_spice_cursor_refresh_bh(void *opaque)
|
||||||
|
|
||||||
void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
|
void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
|
||||||
{
|
{
|
||||||
dprint(3, "%s/%d:\n", __func__, ssd->qxl.id);
|
|
||||||
graphic_hw_update(ssd->dcl.con);
|
graphic_hw_update(ssd->dcl.con);
|
||||||
|
|
||||||
qemu_mutex_lock(&ssd->lock);
|
qemu_mutex_lock(&ssd->lock);
|
||||||
|
@ -505,10 +484,10 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
|
||||||
}
|
}
|
||||||
qemu_mutex_unlock(&ssd->lock);
|
qemu_mutex_unlock(&ssd->lock);
|
||||||
|
|
||||||
|
trace_qemu_spice_display_refresh(ssd->qxl.id, ssd->notify);
|
||||||
if (ssd->notify) {
|
if (ssd->notify) {
|
||||||
ssd->notify = 0;
|
ssd->notify = 0;
|
||||||
qemu_spice_wakeup(ssd);
|
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)
|
static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker)
|
||||||
{
|
{
|
||||||
SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
|
/* nothing to do */
|
||||||
|
|
||||||
dprint(1, "%s/%d:\n", __func__, ssd->qxl.id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void interface_set_compression_level(QXLInstance *sin, int level)
|
static void interface_set_compression_level(QXLInstance *sin, int level)
|
||||||
{
|
{
|
||||||
dprint(1, "%s/%d:\n", __func__, sin->id);
|
|
||||||
/* nothing to do */
|
/* nothing to do */
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SPICE_NEEDS_SET_MM_TIME
|
#if SPICE_NEEDS_SET_MM_TIME
|
||||||
static void interface_set_mm_time(QXLInstance *sin, uint32_t 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 */
|
/* nothing to do */
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -554,8 +529,6 @@ static int interface_get_command(QXLInstance *sin, QXLCommandExt *ext)
|
||||||
SimpleSpiceUpdate *update;
|
SimpleSpiceUpdate *update;
|
||||||
int ret = false;
|
int ret = false;
|
||||||
|
|
||||||
dprint(3, "%s/%d:\n", __func__, ssd->qxl.id);
|
|
||||||
|
|
||||||
qemu_mutex_lock(&ssd->lock);
|
qemu_mutex_lock(&ssd->lock);
|
||||||
update = QTAILQ_FIRST(&ssd->updates);
|
update = QTAILQ_FIRST(&ssd->updates);
|
||||||
if (update != NULL) {
|
if (update != NULL) {
|
||||||
|
@ -570,7 +543,6 @@ static int interface_get_command(QXLInstance *sin, QXLCommandExt *ext)
|
||||||
|
|
||||||
static int interface_req_cmd_notification(QXLInstance *sin)
|
static int interface_req_cmd_notification(QXLInstance *sin)
|
||||||
{
|
{
|
||||||
dprint(2, "%s/%d:\n", __func__, sin->id);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,7 +554,6 @@ static void interface_release_resource(QXLInstance *sin,
|
||||||
SimpleSpiceCursor *cursor;
|
SimpleSpiceCursor *cursor;
|
||||||
QXLCommandExt *ext;
|
QXLCommandExt *ext;
|
||||||
|
|
||||||
dprint(2, "%s/%d:\n", __func__, ssd->qxl.id);
|
|
||||||
ext = (void *)(intptr_t)(rext.info->id);
|
ext = (void *)(intptr_t)(rext.info->id);
|
||||||
switch (ext->cmd.type) {
|
switch (ext->cmd.type) {
|
||||||
case QXL_CMD_DRAW:
|
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);
|
SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dprint(3, "%s/%d:\n", __func__, ssd->qxl.id);
|
|
||||||
|
|
||||||
qemu_mutex_lock(&ssd->lock);
|
qemu_mutex_lock(&ssd->lock);
|
||||||
if (ssd->ptr_define) {
|
if (ssd->ptr_define) {
|
||||||
*ext = ssd->ptr_define->ext;
|
*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)
|
static int interface_req_cursor_notification(QXLInstance *sin)
|
||||||
{
|
{
|
||||||
dprint(2, "%s:\n", __func__);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -680,7 +648,7 @@ static void interface_set_client_capabilities(QXLInstance *sin,
|
||||||
uint8_t client_present,
|
uint8_t client_present,
|
||||||
uint8_t caps[58])
|
uint8_t caps[58])
|
||||||
{
|
{
|
||||||
dprint(3, "%s:\n", __func__);
|
/* nothing to do */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int interface_client_monitors_config(QXLInstance *sin,
|
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.width = mc->monitors[head].width;
|
||||||
info.height = mc->monitors[head].height;
|
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);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -902,9 +870,10 @@ static void spice_gl_switch(DisplayChangeListener *dcl,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dprint(1, "%s: %dx%d (stride %d/%d, fourcc 0x%x)\n", __func__,
|
trace_qemu_spice_gl_surface(ssd->qxl.id,
|
||||||
surface_width(ssd->ds), surface_height(ssd->ds),
|
surface_width(ssd->ds),
|
||||||
surface_stride(ssd->ds), stride, fourcc);
|
surface_height(ssd->ds),
|
||||||
|
fourcc);
|
||||||
|
|
||||||
/* note: spice server will close the fd */
|
/* note: spice server will close the fd */
|
||||||
spice_qxl_gl_scanout(&ssd->qxl, 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);
|
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);
|
spice_qxl_gl_scanout(&ssd->qxl, -1, 0, 0, 0, 0, false);
|
||||||
qemu_spice_gl_monitor_config(ssd, 0, 0, 0, 0);
|
qemu_spice_gl_monitor_config(ssd, 0, 0, 0, 0);
|
||||||
ssd->have_surface = false;
|
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__);
|
fprintf(stderr, "%s: failed to get fd for texture\n", __func__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dprint(1, "%s: %dx%d (stride %d, fourcc 0x%x)\n", __func__,
|
trace_qemu_spice_gl_scanout_texture(ssd->qxl.id, w, h, fourcc);
|
||||||
w, h, stride, fourcc);
|
|
||||||
|
|
||||||
/* note: spice server will close the fd */
|
/* note: spice server will close the fd */
|
||||||
spice_qxl_gl_scanout(&ssd->qxl, fd, backing_width, backing_height,
|
spice_qxl_gl_scanout(&ssd->qxl, fd, backing_width, backing_height,
|
||||||
|
@ -968,17 +936,133 @@ static void qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl,
|
||||||
ssd->have_scanout = true;
|
ssd->have_scanout = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qemu_spice_gl_scanout_dmabuf(DisplayChangeListener *dcl,
|
||||||
|
QemuDmaBuf *dmabuf)
|
||||||
|
{
|
||||||
|
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
|
||||||
|
|
||||||
|
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,
|
static void qemu_spice_gl_update(DisplayChangeListener *dcl,
|
||||||
uint32_t x, uint32_t y, uint32_t w, uint32_t h)
|
uint32_t x, uint32_t y, uint32_t w, uint32_t h)
|
||||||
{
|
{
|
||||||
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
|
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;
|
uint64_t cookie;
|
||||||
|
int fd;
|
||||||
|
|
||||||
if (!ssd->have_scanout) {
|
if (!ssd->have_scanout) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dprint(2, "%s: %dx%d+%d+%d\n", __func__, w, h, x, y);
|
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);
|
qemu_spice_gl_block(ssd, true);
|
||||||
cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0);
|
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);
|
spice_qxl_gl_draw_async(&ssd->qxl, x, y, w, h, cookie);
|
||||||
|
@ -1000,6 +1084,10 @@ static const DisplayChangeListenerOps display_listener_gl_ops = {
|
||||||
|
|
||||||
.dpy_gl_scanout_disable = qemu_spice_gl_scanout_disable,
|
.dpy_gl_scanout_disable = qemu_spice_gl_scanout_disable,
|
||||||
.dpy_gl_scanout_texture = qemu_spice_gl_scanout_texture,
|
.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,
|
.dpy_gl_update = qemu_spice_gl_update,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,18 @@ 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_destroy_primary_surface(int qid, uint32_t sid, int async) "%d sid=%u async=%d"
|
||||||
qemu_spice_wakeup(uint32_t qid) "%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_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_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
|
# ui/keymaps.c
|
||||||
keymap_parse(const char *file) "file %s"
|
keymap_parse(const char *file) "file %s"
|
||||||
|
|
10
ui/vnc.c
10
ui/vnc.c
|
@ -746,9 +746,19 @@ static void vnc_update_server_surface(VncDisplay *vd)
|
||||||
static void vnc_dpy_switch(DisplayChangeListener *dcl,
|
static void vnc_dpy_switch(DisplayChangeListener *dcl,
|
||||||
DisplaySurface *surface)
|
DisplaySurface *surface)
|
||||||
{
|
{
|
||||||
|
static const char placeholder_msg[] =
|
||||||
|
"Display output is not active.";
|
||||||
|
static DisplaySurface *placeholder;
|
||||||
VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
|
VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
|
||||||
VncState *vs;
|
VncState *vs;
|
||||||
|
|
||||||
|
if (surface == NULL) {
|
||||||
|
if (placeholder == NULL) {
|
||||||
|
placeholder = qemu_create_message_surface(640, 480, placeholder_msg);
|
||||||
|
}
|
||||||
|
surface = placeholder;
|
||||||
|
}
|
||||||
|
|
||||||
vnc_abort_display_jobs(vd);
|
vnc_abort_display_jobs(vd);
|
||||||
vd->ds = surface;
|
vd->ds = surface;
|
||||||
|
|
||||||
|
|
|
@ -170,7 +170,7 @@ Coroutine *qemu_coroutine_new(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_VALGRIND_H
|
#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... */
|
/* Work around an unused variable in the valgrind.h macro... */
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
#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);
|
VALGRIND_STACK_DEREGISTER(co->valgrind_stack_id);
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
|
#if defined(CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE) && !defined(__clang__)
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue