[QEMU PATCH v5 2/2] virtgpu: do not destroy resources when guest does S3

From: Jiqian Chen
Date: Tue Sep 19 2023 - 07:03:15 EST


After guest VM resumed, you will get a black screen, and the display
can't come back. It is because when guest did resuming, it called
into qemu to call virtio_gpu_gl_reset. In that function, it destroyed
resources created by command VIRTIO_GPU_CMD_RESOURCE_CREATE_*, which
were used for display. As a result, guest's screen can't come back to
the time when it was suspended.

So when freeze_mode is set FREEZE_S3 by guest, we can know that guest
is doing S3, and we can prevent Qemu to destroy the resources.

Signed-off-by: Jiqian Chen <Jiqian.Chen@xxxxxxx>
---
hw/display/virtio-gpu-gl.c | 9 ++++++++-
hw/display/virtio-gpu.c | 12 ++++++++++--
2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c
index e06be60dfb..2519dc12ff 100644
--- a/hw/display/virtio-gpu-gl.c
+++ b/hw/display/virtio-gpu-gl.c
@@ -100,7 +100,14 @@ static void virtio_gpu_gl_reset(VirtIODevice *vdev)
*/
if (gl->renderer_inited && !gl->renderer_reset) {
virtio_gpu_virgl_reset_scanout(g);
- gl->renderer_reset = true;
+ /*
+ * If guest is suspending, we shouldn't reset renderer,
+ * otherwise, the display can't come back to the time when
+ * it was suspended after guest resumed.
+ */
+ if (vdev->freeze_mode != VIRTIO_PCI_FREEZE_MODE_FREEZE_S3) {
+ gl->renderer_reset = true;
+ }
}
}

diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 93857ad523..d363b886dc 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -1412,11 +1412,19 @@ static void virtio_gpu_device_unrealize(DeviceState *qdev)
static void virtio_gpu_reset_bh(void *opaque)
{
VirtIOGPU *g = VIRTIO_GPU(opaque);
+ VirtIODevice *vdev = &g->parent_obj.parent_obj;
struct virtio_gpu_simple_resource *res, *tmp;
int i = 0;

- QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) {
- virtio_gpu_resource_destroy(g, res);
+ /*
+ * If guest is suspending, we shouldn't destroy resources,
+ * otherwise, the display can't come back to the time when
+ * it was suspended after guest resumed.
+ */
+ if (vdev->freeze_mode != VIRTIO_PCI_FREEZE_MODE_FREEZE_S3) {
+ QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) {
+ virtio_gpu_resource_destroy(g, res);
+ }
}

for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
--
2.34.1