On 2026/03/02 5:48, Dmitry Osipenko wrote:
> QEMU's display GL core is tied to main-loop thread and virtio-gpu
> interacts with display while processing GPU commands. virtio_gpu_ctrl_bh()
> works in generic AIO context that can be processed from vCPU thread, while
> GL and UI toolkits are bound to the main-loop thread. Bounce the ctrl-bh
> execution if running from a thread other than main to fix the problem.
I think you can make use of iohandler_get_aio_context() instead of bouncing.
Regards,
Akihiko Odaki
>
> 0 SDL_GL_MakeCurrent() (libSDL3)
> 1 SDL_GL_MakeCurrent_REAL() (libSDL2)
> 2 sdl2_gl_make_context_current() (ui/sdl2-gl.c:201)
> 3 make_current() (virglrenderer.c:639)
> 4 vrend_finish_context_switch() (vrend_renderer.c:11630)
> 5 vrend_hw_switch_context() (vrend_renderer.c:11613)
> 6 vrend_renderer_force_ctx_0() (vrend_renderer.c:12986)
> 7 virgl_renderer_force_ctx_0() (virglrenderer.c:460)
> 8 virtio_gpu_virgl_process_cmd() (virtio-gpu-virgl.c:1013)
> 9 virtio_gpu_process_cmdq() (virtio-gpu.c:1050)
> 10 virtio_gpu_gl_handle_ctrl() (virtio-gpu-gl.c:86)
> 11 aio_bh_poll() (util/async.c)
> 12 aio_poll() (util/aio-posix.c)
> 13 blk_pwrite() (block/block-gen.c:1985)
> 14 pflash_update() (pflash_cfi01.c:396)
> 15 pflash_write() (pflash_cfi01.c:541)
> 16 memory_region_dispatch_write() (system/memory.c:1554)
> 17 flatview_write() (system/physmem.c:3333)
> 18 address_space_write() (system/physmem.c:3453)
> 19 kvm_cpu_exec() (accel/kvm/kall-all.c:3248)
> 20 kvm_vcpu_thread_fn() (accel/kvm/kaccel-ops.c:53)
>
> Cc: qemu-stable@nongnu.org
> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> ---
> hw/display/virtio-gpu.c | 12 +++++++++++-
> include/hw/virtio/virtio-gpu.h | 2 ++
> 2 files changed, 13 insertions(+), 1 deletion(-)
>
> diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
> index 643e91ca2a7a..d0737cbba8a2 100644
> --- a/hw/display/virtio-gpu.c
> +++ b/hw/display/virtio-gpu.c
> @@ -1126,7 +1126,16 @@ static void virtio_gpu_ctrl_bh(void *opaque)
> VirtIOGPU *g = opaque;
> VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g);
>
> - vgc->handle_ctrl(VIRTIO_DEVICE(g), g->ctrl_vq);
> + /*
> + * Bounce handling to main-loop thread as display UI toolkit
> + * and GL context are bounded there.
> + */
> + if (qemu_get_thread_id() == g->thread_id) {
> + vgc->handle_ctrl(VIRTIO_DEVICE(g), g->ctrl_vq);
> + } else {
> + aio_bh_schedule_oneshot(qemu_get_aio_context(),
> + virtio_gpu_ctrl_bh, g);
> + }
> }
>
> static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq)
> @@ -1533,6 +1542,7 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
> QTAILQ_INIT(&g->reslist);
> QTAILQ_INIT(&g->cmdq);
> QTAILQ_INIT(&g->fenceq);
> + g->thread_id = qemu_get_thread_id();
> }
>
> static void virtio_gpu_device_unrealize(DeviceState *qdev)
> diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
> index 58e0f91fda65..d3bd8ed0d28a 100644
> --- a/include/hw/virtio/virtio-gpu.h
> +++ b/include/hw/virtio/virtio-gpu.h
> @@ -218,6 +218,8 @@ struct VirtIOGPU {
> } dmabuf;
>
> GArray *capset_ids;
> +
> + int thread_id;
> };
>
> struct VirtIOGPUClass {