Create a thread-specific opengl context for the renderer. This avoids having to synchronize a single context between the rendering and display threads.
The display must support calling gl_ctx* functions from a different thread later on, return an error if it doesn't. Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com> --- hw/display/virtio-gpu.c | 19 +++++++++++++++++++ hw/display/virtio-vga.c | 11 +++++++++++ ui/console.c | 4 ++++ include/hw/virtio/virtio-gpu.h | 1 + include/ui/console.h | 1 + 5 files changed, 36 insertions(+) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 157b9ba..a238090 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -954,12 +954,31 @@ static void virtio_gpu_gl_block(void *opaque, bool block) } } +static void virtio_gpu_gl_register(DisplayChangeListener *dcl, + void *hw, Error **errp) +{ + VirtIOGPU *g = hw; + QEMUGLParams qparams = { + .major_ver = 2, + }; + + if (g->iothread && !dpy_gl_ctx_is_mt_safe(dcl->con)) { + error_setg(errp, "The display does not support a rendering thread"); + return; + } + + if (g->iothread && !g->thread_ctx) { + g->thread_ctx = dpy_gl_ctx_create(dcl->con, &qparams); + } +} + const GraphicHwOps virtio_gpu_ops = { .invalidate = virtio_gpu_invalidate_display, .gfx_update = virtio_gpu_update_display, .text_update = virtio_gpu_text_update, .ui_info = virtio_gpu_ui_info, .gl_block = virtio_gpu_gl_block, + .gl_register = virtio_gpu_gl_register, }; static const VMStateDescription vmstate_virtio_gpu_scanout = { diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index 5ba6daa..bf4048b 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -76,12 +76,23 @@ static void virtio_vga_gl_block(void *opaque, bool block) } } +static void virtio_vga_gl_register(DisplayChangeListener *dcl, + void *hw, Error **errp) +{ + VirtIOVGA *vvga = hw; + + if (virtio_gpu_ops.gl_register) { + virtio_gpu_ops.gl_register(dcl, &vvga->vdev, errp); + } +} + static const GraphicHwOps virtio_vga_ops = { .invalidate = virtio_vga_invalidate_display, .gfx_update = virtio_vga_update_display, .text_update = virtio_vga_text_update, .ui_info = virtio_vga_ui_info, .gl_block = virtio_vga_gl_block, + .gl_register = virtio_vga_gl_register, }; static const VMStateDescription vmstate_virtio_vga = { diff --git a/ui/console.c b/ui/console.c index 52b204c..a2e410e 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1414,6 +1414,10 @@ void register_displaychangelistener(DisplayChangeListener *dcl) } } text_console_update_cursor(NULL); + + if (con->hw_ops->gl_register) { + con->hw_ops->gl_register(dcl, con->hw, &error_fatal); + } } void update_displaychangelistener(DisplayChangeListener *dcl, diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 834ef4f..406a4e8 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -134,6 +134,7 @@ typedef struct VirtIOGPU { int renderer_blocked; IOThread *iothread; + QEMUGLContext thread_ctx; QEMUTimer *fence_poll; QEMUTimer *print_stats; diff --git a/include/ui/console.h b/include/ui/console.h index 2e7bb0e..ed5975f 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -367,6 +367,7 @@ typedef struct GraphicHwOps { 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_register)(DisplayChangeListener *dcl, void *hw, Error **errp); } GraphicHwOps; QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head, -- 2.9.0