mirror of https://github.com/xemu-project/xemu.git
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:
parent
25c001a403
commit
e64d4b6a9b
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue