Displaying rendered resources requires blocking qemu GPU to avoid extra
framebuffer copies. For an external display, via Spice currently, there
is a callback to block/unblock the rendering in the same thread.
But with the vhost-user-gpu backend, the qemu process doesn't handle
the rendering itself, and the blocking callback isn't effective.
Instead, the backend must be notified when the display code is done.
Fix this by adding a new GraphicHwOps callback to indicate the GL state
is flushed, and we are done manipulating the shared GL resources. Call
it from gtk and spice display.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <
20210204105232.834642-19-marcandre.lureau@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
}
static void
-vhost_user_gpu_gl_unblock(VirtIOGPUBase *b)
+vhost_user_gpu_gl_flushed(VirtIOGPUBase *b)
{
VhostUserGPU *g = VHOST_USER_GPU(b);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_CLASS(klass);
- vgc->gl_unblock = vhost_user_gpu_gl_unblock;
+ vgc->gl_flushed = vhost_user_gpu_gl_flushed;
vdc->realize = vhost_user_gpu_device_realize;
vdc->reset = vhost_user_gpu_reset;
}
static void
-virtio_gpu_gl_block(void *opaque, bool block)
+virtio_gpu_gl_flushed(void *opaque)
{
VirtIOGPUBase *g = opaque;
VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_GET_CLASS(g);
+ if (vgc->gl_flushed) {
+ vgc->gl_flushed(g);
+ }
+}
+
+static void
+virtio_gpu_gl_block(void *opaque, bool block)
+{
+ VirtIOGPUBase *g = opaque;
+
if (block) {
g->renderer_blocked++;
} else {
g->renderer_blocked--;
}
assert(g->renderer_blocked >= 0);
-
- if (g->renderer_blocked == 0) {
- vgc->gl_unblock(g);
- }
}
static int
.text_update = virtio_gpu_text_update,
.ui_info = virtio_gpu_ui_info,
.gl_block = virtio_gpu_gl_block,
+ .gl_flushed = virtio_gpu_gl_flushed,
};
bool
g->processing_cmdq = false;
}
-static void virtio_gpu_gl_unblock(VirtIOGPUBase *b)
+static void virtio_gpu_gl_flushed(VirtIOGPUBase *b)
{
VirtIOGPU *g = VIRTIO_GPU(b);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_CLASS(klass);
- vgc->gl_unblock = virtio_gpu_gl_unblock;
+ vgc->gl_flushed = virtio_gpu_gl_flushed;
vdc->realize = virtio_gpu_device_realize;
vdc->reset = virtio_gpu_reset;
vdc->get_config = virtio_gpu_get_config;
}
}
+static void virtio_vga_base_gl_flushed(void *opaque)
+{
+ VirtIOVGABase *vvga = opaque;
+ VirtIOGPUBase *g = vvga->vgpu;
+
+ if (g->hw_ops->gl_flushed) {
+ g->hw_ops->gl_flushed(g);
+ }
+}
+
static int virtio_vga_base_get_flags(void *opaque)
{
VirtIOVGABase *vvga = opaque;
.text_update = virtio_vga_base_text_update,
.ui_info = virtio_vga_base_ui_info,
.gl_block = virtio_vga_base_gl_block,
+ .gl_flushed = virtio_vga_base_gl_flushed,
};
static const VMStateDescription vmstate_virtio_vga_base = {
struct VirtIOGPUBaseClass {
VirtioDeviceClass parent;
- void (*gl_unblock)(VirtIOGPUBase *g);
+ void (*gl_flushed)(VirtIOGPUBase *g);
};
#define VIRTIO_GPU_BASE_PROPERTIES(_state, _conf) \
void (*update_interval)(void *opaque, uint64_t interval);
int (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info);
void (*gl_block)(void *opaque, bool block);
+ void (*gl_flushed)(void *opaque);
} GraphicHwOps;
QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
void graphic_hw_invalidate(QemuConsole *con);
void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata);
void graphic_hw_gl_block(QemuConsole *con, bool block);
+void graphic_hw_gl_flushed(QemuConsole *con);
void qemu_console_early_init(void);
}
}
+void graphic_hw_gl_flushed(QemuConsole *con)
+{
+ assert(con != NULL);
+
+ if (con->hw_ops->gl_flushed) {
+ con->hw_ops->gl_flushed(con->hw);
+ }
+}
+
int qemu_console_get_window_id(QemuConsole *con)
{
return con->window_id;
vc->gfx.scale_x = (double)ww / surface_width(vc->gfx.ds);
vc->gfx.scale_y = (double)wh / surface_height(vc->gfx.ds);
}
+
+ glFlush();
+ graphic_hw_gl_flushed(vc->gfx.dcl.con);
}
void gd_egl_update(DisplayChangeListener *dcl,
surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh);
surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds);
}
+
+ glFlush();
+ graphic_hw_gl_flushed(vc->gfx.dcl.con);
}
void gd_gl_area_update(DisplayChangeListener *dcl,
surface_gl_render_texture(scon->gls, scon->surface);
SDL_GL_SwapWindow(scon->real_window);
+ graphic_hw_gl_flushed(scon->dcl.con);
}
void sdl2_gl_update(DisplayChangeListener *dcl,
egl_fb_blit(&scon->win_fb, &scon->guest_fb, !scon->y0_top);
SDL_GL_SwapWindow(scon->real_window);
+ graphic_hw_gl_flushed(dcl->con);
}
SimpleSpiceDisplay *ssd = opaque;
qemu_spice_gl_block(ssd, false);
+ graphic_hw_gl_flushed(ssd->dcl.con);
}
static void qemu_spice_gl_block_timer(void *opaque)