Skip to content

Commit

Permalink
virtio-gpu: fix scanout migration post-load
Browse files Browse the repository at this point in the history
The current post-loading code for scanout has a FIXME: it doesn't take
the resource region/rect into account. But there is more, when adding
blob migration support in commit f66767f, I didn't realize that blob
resources could be used for scanouts. This situationn leads to a crash
during post-load, as they don't have an associated res->image.

virtio_gpu_do_set_scanout() handle all cases, but requires the
associated virtio_gpu_framebuffer, which is currently not saved during
migration.

Add a v2 of "virtio-gpu-one-scanout" with the framebuffer fields, so we
can restore blob scanouts, as well as fixing the existing FIXME.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Sebastian Ott <sebott@redhat.com>
  • Loading branch information
elmarco committed Mar 12, 2024
1 parent cab47b2 commit dfcf74f
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 10 deletions.
51 changes: 41 additions & 10 deletions hw/display/virtio-gpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,7 @@ static void virtio_unref_resource(pixman_image_t *image, void *data)
static void virtio_gpu_update_scanout(VirtIOGPU *g,
uint32_t scanout_id,
struct virtio_gpu_simple_resource *res,
struct virtio_gpu_framebuffer *fb,
struct virtio_gpu_rect *r)
{
struct virtio_gpu_simple_resource *ores;
Expand All @@ -617,9 +618,10 @@ static void virtio_gpu_update_scanout(VirtIOGPU *g,
scanout->y = r->y;
scanout->width = r->width;
scanout->height = r->height;
scanout->fb = *fb;
}

static void virtio_gpu_do_set_scanout(VirtIOGPU *g,
static bool virtio_gpu_do_set_scanout(VirtIOGPU *g,
uint32_t scanout_id,
struct virtio_gpu_framebuffer *fb,
struct virtio_gpu_simple_resource *res,
Expand All @@ -645,19 +647,20 @@ static void virtio_gpu_do_set_scanout(VirtIOGPU *g,
r->x, r->y, r->width, r->height,
fb->width, fb->height);
*error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
return;
return false;
}

g->parent_obj.enable = 1;

if (res->blob) {
if (console_has_gl(scanout->con)) {
if (!virtio_gpu_update_dmabuf(g, scanout_id, res, fb, r)) {
virtio_gpu_update_scanout(g, scanout_id, res, r);
virtio_gpu_update_scanout(g, scanout_id, res, fb, r);
} else {
*error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
return false;
}
return;
return true;
}

data = res->blob;
Expand Down Expand Up @@ -693,7 +696,8 @@ static void virtio_gpu_do_set_scanout(VirtIOGPU *g,
scanout->ds);
}

virtio_gpu_update_scanout(g, scanout_id, res, r);
virtio_gpu_update_scanout(g, scanout_id, res, fb, r);
return true;
}

static void virtio_gpu_set_scanout(VirtIOGPU *g,
Expand Down Expand Up @@ -1164,7 +1168,8 @@ static void virtio_gpu_cursor_bh(void *opaque)

static const VMStateDescription vmstate_virtio_gpu_scanout = {
.name = "virtio-gpu-one-scanout",
.version_id = 1,
.version_id = 2,
.minimum_version_id = 1,
.fields = (const VMStateField[]) {
VMSTATE_UINT32(resource_id, struct virtio_gpu_scanout),
VMSTATE_UINT32(width, struct virtio_gpu_scanout),
Expand All @@ -1176,6 +1181,12 @@ static const VMStateDescription vmstate_virtio_gpu_scanout = {
VMSTATE_UINT32(cursor.hot_y, struct virtio_gpu_scanout),
VMSTATE_UINT32(cursor.pos.x, struct virtio_gpu_scanout),
VMSTATE_UINT32(cursor.pos.y, struct virtio_gpu_scanout),
VMSTATE_UINT32_V(fb.format, struct virtio_gpu_scanout, 2),
VMSTATE_UINT32_V(fb.bytes_pp, struct virtio_gpu_scanout, 2),
VMSTATE_UINT32_V(fb.width, struct virtio_gpu_scanout, 2),
VMSTATE_UINT32_V(fb.height, struct virtio_gpu_scanout, 2),
VMSTATE_UINT32_V(fb.stride, struct virtio_gpu_scanout, 2),
VMSTATE_UINT32_V(fb.offset, struct virtio_gpu_scanout, 2),
VMSTATE_END_OF_LIST()
},
};
Expand Down Expand Up @@ -1347,6 +1358,7 @@ static int virtio_gpu_blob_save(QEMUFile *f, void *opaque, size_t size,
if (!res->blob_size) {
continue;
}
assert(!res->image);
qemu_put_be32(f, res->resource_id);
qemu_put_be32(f, res->blob_size);
qemu_put_be32(f, res->iov_cnt);
Expand Down Expand Up @@ -1409,21 +1421,40 @@ static int virtio_gpu_post_load(void *opaque, int version_id)
int i;

for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
/* FIXME: should take scanout.r.{x,y} into account */
scanout = &g->parent_obj.scanout[i];
if (!scanout->resource_id) {
continue;
}

res = virtio_gpu_find_resource(g, scanout->resource_id);
if (!res) {
return -EINVAL;
}
scanout->ds = qemu_create_displaysurface_pixman(res->image);

if (scanout->fb.format != 0) {
uint32_t error = 0;
struct virtio_gpu_rect r = {
.x = scanout->x,
.y = scanout->y,
.width = scanout->width,
.height = scanout->height
};

if (!virtio_gpu_do_set_scanout(g, i, &scanout->fb, res, &r, &error)) {
return -EINVAL;
}
} else {
/* legacy v1 migration support */
if (!res->image) {
return -EINVAL;
}
scanout->ds = qemu_create_displaysurface_pixman(res->image);
#ifdef WIN32
qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, 0);
qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, 0);
#endif
dpy_gfx_replace_surface(scanout->con, scanout->ds);
}

dpy_gfx_replace_surface(scanout->con, scanout->ds);
dpy_gfx_update_full(scanout->con);
if (scanout->cursor.resource_id) {
update_cursor(g, &scanout->cursor);
Expand Down
1 change: 1 addition & 0 deletions include/hw/virtio/virtio-gpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ struct virtio_gpu_scanout {
uint32_t resource_id;
struct virtio_gpu_update_cursor cursor;
QEMUCursor *current_cursor;
struct virtio_gpu_framebuffer fb;
};

struct virtio_gpu_requested_state {
Expand Down

0 comments on commit dfcf74f

Please sign in to comment.