@@ -121,6 +121,8 @@ struct SimpleSpiceDisplay {
QEMUBH *gl_unblock_bh;
QEMUTimer *gl_unblock_timer;
int dmabuf_fd;
+ ConsoleGLState *gls;
+ int gl_updates;
#endif
};
@@ -821,6 +821,72 @@ static void qemu_spice_gl_block_timer(void *opaque)
fprintf(stderr, "WARNING: spice: no gl-draw-done within one second\n");
}
+static void spice_gl_refresh(DisplayChangeListener *dcl)
+{
+ SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
+ uint64_t cookie;
+
+ if (!ssd->ds || qemu_console_is_gl_blocked(ssd->dcl.con)) {
+ return;
+ }
+
+ graphic_hw_update(dcl->con);
+ if (ssd->gl_updates) {
+ 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, 0, 0,
+ surface_width(ssd->ds),
+ surface_height(ssd->ds),
+ cookie);
+ ssd->gl_updates = 0;
+ }
+}
+
+static void spice_gl_update(DisplayChangeListener *dcl,
+ int x, int y, int w, int h)
+{
+ SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
+
+ surface_gl_update_texture(ssd->gls, ssd->ds, x, y, w, h);
+ ssd->gl_updates++;
+}
+
+static void spice_gl_switch(DisplayChangeListener *dcl,
+ struct DisplaySurface *new_surface)
+{
+ SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
+ EGLint stride, fourcc;
+ int fd;
+
+ if (ssd->ds) {
+ surface_gl_destroy_texture(ssd->gls, ssd->ds);
+ }
+ ssd->ds = new_surface;
+ if (ssd->ds) {
+ surface_gl_create_texture(ssd->gls, ssd->ds);
+ fd = egl_get_fd_for_texture(ssd->ds->texture,
+ &stride, &fourcc);
+ if (fd < 0) {
+ surface_gl_destroy_texture(ssd->gls, ssd->ds);
+ 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);
+
+ spice_qxl_gl_scanout(&ssd->qxl, fd,
+ surface_width(ssd->ds),
+ surface_height(ssd->ds),
+ stride, fourcc, false);
+
+ if (ssd->dmabuf_fd != -1) {
+ close(ssd->dmabuf_fd);
+ }
+ ssd->dmabuf_fd = fd;
+ }
+}
+
static QEMUGLContext qemu_spice_gl_create_context(DisplayChangeListener *dcl,
QEMUGLParams *params)
{
@@ -876,13 +942,13 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl,
}
static const DisplayChangeListenerOps display_listener_gl_ops = {
- .dpy_name = "spice-egl",
- .dpy_gfx_update = display_update,
- .dpy_gfx_switch = display_switch,
- .dpy_gfx_check_format = qemu_pixman_check_format,
- .dpy_refresh = display_refresh,
- .dpy_mouse_set = display_mouse_set,
- .dpy_cursor_define = display_mouse_define,
+ .dpy_name = "spice-egl",
+ .dpy_gfx_update = spice_gl_update,
+ .dpy_gfx_switch = spice_gl_switch,
+ .dpy_gfx_check_format = console_gl_check_format,
+ .dpy_refresh = spice_gl_refresh,
+ .dpy_mouse_set = display_mouse_set,
+ .dpy_cursor_define = display_mouse_define,
.dpy_gl_ctx_create = qemu_spice_gl_create_context,
.dpy_gl_ctx_destroy = qemu_egl_destroy_context,
@@ -915,6 +981,7 @@ static void qemu_spice_display_init_one(QemuConsole *con)
ssd->gl_unblock_bh = qemu_bh_new(qemu_spice_gl_unblock_bh, ssd);
ssd->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
qemu_spice_gl_block_timer, ssd);
+ ssd->gls = console_gl_init_context();
}
#endif
ssd->dcl.con = con;
This switches over spice (in opengl mode) to render DisplaySurface updates into a opengl texture, using the helper functions in ui/console-gl.c. With this patch applied spice (with gl=on) will stop using qxl rendering ops, it will use dma-buf passing all the time, i.e. for bios/bootloader (before virtio-gpu driver is loaded) too. This should improve performance even using spice (with gl=on) with non-accelerated stdvga because we stop squeezing all display updates through a unix/tcp socket and basically using a shared memory transport instead. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- include/ui/spice-display.h | 2 ++ ui/spice-display.c | 81 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 76 insertions(+), 7 deletions(-)