From e64d4b6a9bc3ba216a988276bcdc27d06fd48e59 Mon Sep 17 00:00:00 2001 From: Vivek Kasireddy Date: Wed, 26 May 2021 16:14:21 -0700 Subject: [PATCH] virtio-gpu: Refactor virtio_gpu_set_scanout Store the meta-data associated with a FB in a new object (struct virtio_gpu_framebuffer) and pass the object to set_scanout. Also move code in set_scanout into a do_set_scanout function. This will be helpful when adding set_scanout_blob API. Based-on-patch-by: Gerd Hoffmann Cc: Gerd Hoffmann Signed-off-by: Vivek Kasireddy Message-Id: <20210526231429.1045476-7-vivek.kasireddy@intel.com> Signed-off-by: Gerd Hoffmann --- hw/display/virtio-gpu.c | 157 +++++++++++++++++++-------------- include/hw/virtio/virtio-gpu.h | 8 ++ 2 files changed, 98 insertions(+), 67 deletions(-) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 7b5296f0d0..fdcedfc61e 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -500,14 +500,91 @@ static void virtio_unref_resource(pixman_image_t *image, void *data) pixman_image_unref(data); } +static void virtio_gpu_do_set_scanout(VirtIOGPU *g, + uint32_t scanout_id, + struct virtio_gpu_framebuffer *fb, + struct virtio_gpu_simple_resource *res, + struct virtio_gpu_rect *r, + uint32_t *error) +{ + struct virtio_gpu_simple_resource *ores; + struct virtio_gpu_scanout *scanout; + uint8_t *data; + + if (scanout_id >= g->parent_obj.conf.max_outputs) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d", + __func__, scanout_id); + *error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; + return; + } + scanout = &g->parent_obj.scanout[scanout_id]; + + if (r->x > fb->width || + r->y > fb->height || + r->width < 16 || + r->height < 16 || + r->width > fb->width || + r->height > fb->height || + r->x + r->width > fb->width || + r->y + r->height > fb->height) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout %d bounds for" + " resource %d, rect (%d,%d)+%d,%d, fb %d %d\n", + __func__, scanout_id, res->resource_id, + r->x, r->y, r->width, r->height, + fb->width, fb->height); + *error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + return; + } + + g->parent_obj.enable = 1; + data = (uint8_t *)pixman_image_get_data(res->image); + + /* create a surface for this scanout */ + if (!scanout->ds || + surface_data(scanout->ds) != data + fb->offset || + scanout->width != r->width || + scanout->height != r->height) { + pixman_image_t *rect; + void *ptr = data + fb->offset; + rect = pixman_image_create_bits(fb->format, r->width, r->height, + ptr, fb->stride); + + if (res->image) { + pixman_image_ref(res->image); + pixman_image_set_destroy_function(rect, virtio_unref_resource, + res->image); + } + + /* realloc the surface ptr */ + scanout->ds = qemu_create_displaysurface_pixman(rect); + if (!scanout->ds) { + *error = VIRTIO_GPU_RESP_ERR_UNSPEC; + return; + } + + pixman_image_unref(rect); + dpy_gfx_replace_surface(g->parent_obj.scanout[scanout_id].con, + scanout->ds); + } + + ores = virtio_gpu_find_resource(g, scanout->resource_id); + if (ores) { + ores->scanout_bitmask &= ~(1 << scanout_id); + } + + res->scanout_bitmask |= (1 << scanout_id); + scanout->resource_id = res->resource_id; + scanout->x = r->x; + scanout->y = r->y; + scanout->width = r->width; + scanout->height = r->height; +} + static void virtio_gpu_set_scanout(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { - struct virtio_gpu_simple_resource *res, *ores; - struct virtio_gpu_scanout *scanout; - pixman_format_code_t format; - uint32_t offset; - int bpp; + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_framebuffer fb = { 0 }; struct virtio_gpu_set_scanout ss; VIRTIO_GPU_FILL_CMD(ss); @@ -515,80 +592,26 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id, ss.r.width, ss.r.height, ss.r.x, ss.r.y); - if (ss.scanout_id >= g->parent_obj.conf.max_outputs) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d", - __func__, ss.scanout_id); - cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; - return; - } - - g->parent_obj.enable = 1; if (ss.resource_id == 0) { virtio_gpu_disable_scanout(g, ss.scanout_id); return; } - /* create a surface for this scanout */ res = virtio_gpu_find_check_resource(g, ss.resource_id, true, __func__, &cmd->error); if (!res) { return; } - if (ss.r.x > res->width || - ss.r.y > res->height || - ss.r.width < 16 || - ss.r.height < 16 || - ss.r.width > res->width || - ss.r.height > res->height || - ss.r.x + ss.r.width > res->width || - ss.r.y + ss.r.height > res->height) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout %d bounds for" - " resource %d, (%d,%d)+%d,%d vs %d %d\n", - __func__, ss.scanout_id, ss.resource_id, ss.r.x, ss.r.y, - ss.r.width, ss.r.height, res->width, res->height); - cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; - return; - } + fb.format = pixman_image_get_format(res->image); + fb.bytes_pp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(fb.format), 8); + fb.width = pixman_image_get_width(res->image); + fb.height = pixman_image_get_height(res->image); + fb.stride = pixman_image_get_stride(res->image); + fb.offset = ss.r.x * fb.bytes_pp + ss.r.y * fb.stride; - scanout = &g->parent_obj.scanout[ss.scanout_id]; - - format = pixman_image_get_format(res->image); - bpp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(format), 8); - offset = (ss.r.x * bpp) + ss.r.y * pixman_image_get_stride(res->image); - if (!scanout->ds || surface_data(scanout->ds) - != ((uint8_t *)pixman_image_get_data(res->image) + offset) || - scanout->width != ss.r.width || - scanout->height != ss.r.height) { - pixman_image_t *rect; - void *ptr = (uint8_t *)pixman_image_get_data(res->image) + offset; - rect = pixman_image_create_bits(format, ss.r.width, ss.r.height, ptr, - pixman_image_get_stride(res->image)); - pixman_image_ref(res->image); - pixman_image_set_destroy_function(rect, virtio_unref_resource, - res->image); - /* realloc the surface ptr */ - scanout->ds = qemu_create_displaysurface_pixman(rect); - if (!scanout->ds) { - cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; - return; - } - pixman_image_unref(rect); - dpy_gfx_replace_surface(g->parent_obj.scanout[ss.scanout_id].con, - scanout->ds); - } - - ores = virtio_gpu_find_resource(g, scanout->resource_id); - if (ores) { - ores->scanout_bitmask &= ~(1 << ss.scanout_id); - } - - res->scanout_bitmask |= (1 << ss.scanout_id); - scanout->resource_id = ss.resource_id; - scanout->x = ss.r.x; - scanout->y = ss.r.y; - scanout->width = ss.r.width; - scanout->height = ss.r.height; + virtio_gpu_do_set_scanout(g, ss.scanout_id, + &fb, res, &ss.r, &cmd->error); } int virtio_gpu_create_mapping_iov(VirtIOGPU *g, diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 265b1c516c..b83a91a67f 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -59,6 +59,14 @@ struct virtio_gpu_simple_resource { QTAILQ_ENTRY(virtio_gpu_simple_resource) next; }; +struct virtio_gpu_framebuffer { + pixman_format_code_t format; + uint32_t bytes_pp; + uint32_t width, height; + uint32_t stride; + uint32_t offset; +}; + struct virtio_gpu_scanout { QemuConsole *con; DisplaySurface *ds;