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 <kraxel@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
Message-Id: <20210526231429.1045476-7-vivek.kasireddy@intel.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
Vivek Kasireddy 2021-05-26 16:14:21 -07:00 committed by Gerd Hoffmann
parent 25c001a403
commit e64d4b6a9b
2 changed files with 98 additions and 67 deletions

View File

@ -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,

View File

@ -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;