diff options
Diffstat (limited to 'ui')
-rw-r--r-- | ui/Makefile.objs | 25 | ||||
-rw-r--r-- | ui/console.c | 34 | ||||
-rw-r--r-- | ui/gtk-egl.c | 63 | ||||
-rw-r--r-- | ui/gtk.c | 68 | ||||
-rw-r--r-- | ui/spice-display.c | 194 | ||||
-rw-r--r-- | ui/trace-events | 12 | ||||
-rw-r--r-- | ui/vnc.c | 10 |
7 files changed, 303 insertions, 103 deletions
diff --git a/ui/Makefile.objs b/ui/Makefile.objs index dcd54a5287..cc784346cb 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -38,26 +38,27 @@ 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 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 -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) console-gl.o-libs += $(OPENGL_LIBS) egl-helpers.o-libs += $(OPENGL_LIBS) +egl-context.o-libs += $(OPENGL_LIBS) +egl-headless.o-libs += $(OPENGL_LIBS) diff --git a/ui/console.c b/ui/console.c index 6ab4ff3baf..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); @@ -1039,8 +1053,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 +1386,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/gtk-egl.c b/ui/gtk-egl.c index eb86c26a1d..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" @@ -194,6 +195,58 @@ 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_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, 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); 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); } @@ -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", @@ -742,10 +744,13 @@ 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_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, }; -#endif /* CONFIG_GTK_GL */ #endif /* CONFIG_OPENGL */ /** QEMU Events **/ @@ -844,13 +849,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 +1998,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 +2121,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 { @@ -2436,11 +2444,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_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 } diff --git a/ui/spice-display.c b/ui/spice-display.c index 98ccdfb687..fe734821dd 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, @@ -968,17 +936,133 @@ 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); + + 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; } - 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); 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); @@ -1000,6 +1084,10 @@ 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 861b68a305..a957f363f1 100644 --- a/ui/trace-events +++ b/ui/trace-events @@ -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_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_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 keymap_parse(const char *file) "file %s" @@ -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; |