When the backend sends VHOST_USER_GPU_SCANOUT with zero dimensions to
disable a scanout, the frontend only calls qemu_console_set_surface(NULL)
without releasing the g->dmabuf[] entry or invoking
qemu_console_gl_scanout_disable(). Display listeners (GTK, SDL) can
therefore remain in GL scanout mode and keep redrawing the stale buffer.

Release the DMA-BUF and call qemu_console_gl_scanout_disable() in the
SCANOUT handler when a previously active DMA-BUF exists.

Additionally, vhost_user_gpu_reset() and
vhost_user_gpu_instance_finalize() never iterate the dmabuf[] array, so
active DMA-BUFs leak on device reset or object destruction. Add cleanup
loops to both paths.

Fixes: 267f664658fe ("hw/display: add vhost-user-vga & gpu-pci")
Signed-off-by: Marc-André Lureau <[email protected]>
---
 hw/display/vhost-user-gpu.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c
index c09aca041135..3f1fd333eeab 100644
--- a/hw/display/vhost-user-gpu.c
+++ b/hw/display/vhost-user-gpu.c
@@ -263,6 +263,11 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, 
VhostUserGpuMsg *msg)
         con = s->con;
 
         if (m->width == 0) {
+            if (g->dmabuf[m->scanout_id]) {
+                qemu_console_gl_release_dmabuf(con, g->dmabuf[m->scanout_id]);
+                g_clear_pointer(&g->dmabuf[m->scanout_id], qemu_dmabuf_free);
+                qemu_console_gl_scanout_disable(con);
+            }
             qemu_console_set_surface(con, NULL);
         } else {
             s->ds = qemu_create_displaysurface(m->width, m->height);
@@ -631,6 +636,10 @@ vhost_user_gpu_instance_finalize(Object *obj)
 {
     VhostUserGPU *g = VHOST_USER_GPU(obj);
 
+    for (int i = 0; i < g->parent_obj.conf.max_outputs; i++) {
+        g_clear_pointer(&g->dmabuf[i], qemu_dmabuf_free);
+    }
+
     object_unref(OBJECT(g->vhost));
 }
 
@@ -639,6 +648,15 @@ vhost_user_gpu_reset(VirtIODevice *vdev)
 {
     VhostUserGPU *g = VHOST_USER_GPU(vdev);
 
+    for (int i = 0; i < g->parent_obj.conf.max_outputs; i++) {
+        if (g->dmabuf[i]) {
+            QemuConsole *con = g->parent_obj.scanout[i].con;
+            qemu_console_gl_release_dmabuf(con, g->dmabuf[i]);
+            g_clear_pointer(&g->dmabuf[i], qemu_dmabuf_free);
+            qemu_console_gl_scanout_disable(con);
+        }
+    }
+
     virtio_gpu_base_reset(VIRTIO_GPU_BASE(vdev));
 
     vhost_user_backend_stop(g->vhost);

-- 
2.55.0.543.g5ebe2ebe4ea8


Reply via email to