dm: virtio-gpu: cursor surpport

Hardware cursor emulation of virtio-gpu video adapter. Guest vm can
show its own cursor in virtual display, not share the cursor with
service vm. It also accelerated by SDL(OpenGL ES 2.0 backend) API
with hardware acceleration based on the GPU hardware own by service
vm.

Tracked-On: #7210
Signed-off-by: Sun, Peng <peng.p.sun@linux.intel.com>
Reviewed-by: Zhao, yakui <yakui.zhao@intel.com>
Acked-by: Wang, Yu1 <yu1.wang@intel.com>
This commit is contained in:
Sun, Peng 2022-02-25 22:04:04 +08:00 committed by acrnsi-robot
parent fae4286cb3
commit f2cfa761ae
3 changed files with 181 additions and 3 deletions

View File

@ -250,6 +250,26 @@ struct virtio_gpu_resource_flush {
uint32_t padding;
};
/*
* Command: VIRTIO_GPU_CMD_UPDATE_CURSOR
* Command: VIRTIO_GPU_CMD_MOVE_CURSOR
*/
struct virtio_gpu_cursor_pos {
uint32_t scanout_id;
uint32_t x;
uint32_t y;
uint32_t padding;
};
struct virtio_gpu_update_cursor {
struct virtio_gpu_ctrl_hdr hdr;
struct virtio_gpu_cursor_pos pos;
uint32_t resource_id;
uint32_t hot_x;
uint32_t hot_y;
uint32_t padding;
};
/*
* Per-device struct
*/
@ -261,6 +281,7 @@ struct virtio_gpu {
int vdpy_handle;
LIST_HEAD(,virtio_gpu_resource_2d) r2d_list;
struct vdpy_display_bh ctrl_bh;
struct vdpy_display_bh cursor_bh;
};
struct virtio_gpu_command {
@ -866,16 +887,62 @@ virtio_gpu_notify_controlq(void *vdev, struct virtio_vq_info *vq)
}
static void
virtio_gpu_notify_cursorq(void *vdev, struct virtio_vq_info *vq)
virtio_gpu_cmd_update_cursor(struct virtio_gpu_command *cmd)
{
struct virtio_gpu_update_cursor req;
struct virtio_gpu_resource_2d *r2d;
struct cursor cur;
struct virtio_gpu *gpu;
gpu = cmd->gpu;
memcpy(&req, cmd->iov[0].iov_base, sizeof(req));
if (req.resource_id > 0) {
r2d = virtio_gpu_find_resource_2d(cmd->gpu, req.resource_id);
if (r2d == NULL) {
pr_err("%s: Illegal resource id %d\n", __func__,
req.resource_id);
return;
}
cur.x = req.pos.x;
cur.y = req.pos.y;
cur.hot_x = req.hot_x;
cur.hot_y = req.hot_y;
cur.width = r2d->width;
cur.height = r2d->height;
pixman_image_ref(r2d->image);
cur.data = pixman_image_get_data(r2d->image);
vdpy_cursor_define(gpu->vdpy_handle, &cur);
pixman_image_unref(r2d->image);
}
}
static void
virtio_gpu_cmd_move_cursor(struct virtio_gpu_command *cmd)
{
struct virtio_gpu_update_cursor req;
struct virtio_gpu *gpu;
gpu = cmd->gpu;
memcpy(&req, cmd->iov[0].iov_base, sizeof(req));
vdpy_cursor_move(gpu->vdpy_handle, req.pos.x, req.pos.y);
}
static void
virtio_gpu_cursor_bh(void *data)
{
struct virtio_gpu *vdev;
struct virtio_vq_info *vq;
struct virtio_gpu_command cmd;
struct virtio_gpu_ctrl_hdr hdr;
struct iovec iov[VIRTIO_GPU_MAXSEGS];
int n;
uint16_t idx;
vq = (struct virtio_vq_info *)data;
vdev = (struct virtio_gpu *)(vq->base);
cmd.gpu = vdev;
cmd.iolen = 0;
while (vq_has_descs(vq)) {
n = vq_getchain(vq, &idx, iov, VIRTIO_GPU_MAXSEGS, NULL);
if (n < 0) {
@ -890,8 +957,13 @@ virtio_gpu_notify_cursorq(void *vdev, struct virtio_vq_info *vq)
cmd.iov = iov;
memcpy(&hdr, iov[0].iov_base, sizeof(hdr));
switch (hdr.type) {
case VIRTIO_GPU_CMD_UPDATE_CURSOR:
virtio_gpu_cmd_update_cursor(&cmd);
break;
case VIRTIO_GPU_CMD_MOVE_CURSOR:
virtio_gpu_cmd_move_cursor(&cmd);
break;
default:
virtio_gpu_cmd_unspec(&cmd);
break;
}
@ -900,6 +972,15 @@ virtio_gpu_notify_cursorq(void *vdev, struct virtio_vq_info *vq)
vq_endchains(vq, 1); /* Generate interrupt if appropriate. */
}
static void
virtio_gpu_notify_cursorq(void *vdev, struct virtio_vq_info *vq)
{
struct virtio_gpu *gpu;
gpu = (struct virtio_gpu *)vdev;
vdpy_submit_bh(gpu->vdpy_handle, &gpu->cursor_bh);
}
static int
virtio_gpu_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
{
@ -957,9 +1038,11 @@ virtio_gpu_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
gpu->vq[VIRTIO_GPU_CURSORQ].qsize = VIRTIO_GPU_RINGSZ;
gpu->vq[VIRTIO_GPU_CURSORQ].notify = virtio_gpu_notify_cursorq;
/* Initialize the ctrl bh_task */
/* Initialize the ctrl/cursor bh_task */
gpu->ctrl_bh.task_cb = virtio_gpu_ctrl_bh;
gpu->ctrl_bh.data = &gpu->vq[VIRTIO_GPU_CONTROLQ];
gpu->cursor_bh.task_cb = virtio_gpu_cursor_bh;
gpu->cursor_bh.data = &gpu->vq[VIRTIO_GPU_CURSORQ];
/* prepare the config space */
gpu->cfg.events_read = 0;

View File

@ -54,6 +54,8 @@ static struct display {
int guest_width, guest_height;
int screen;
struct surface surf;
struct cursor cur;
SDL_Texture *cursor_tex;
/* Add one UI_timer(33ms) to render the buffers from guest_vm */
struct acrn_timer ui_timer;
struct vdpy_display_bh ui_timer_bh;
@ -630,9 +632,20 @@ vdpy_surface_set(int handle, struct surface *surf)
vdpy.dpy_img = src_img;
}
void
vdpy_cursor_position_transformation(struct display *vdpy, SDL_Rect *rect)
{
rect->x = (vdpy->cur.x * vdpy->width) / vdpy->guest_width;
rect->y = (vdpy->cur.y * vdpy->height) / vdpy->guest_height;
rect->w = (vdpy->cur.width * vdpy->width) / vdpy->guest_width;
rect->h = (vdpy->cur.height * vdpy->height) / vdpy->guest_height;
}
void
vdpy_surface_update(int handle, struct surface *surf)
{
SDL_Rect cursor_rect;
if (handle != vdpy.s.n_connect) {
return;
}
@ -648,18 +661,71 @@ vdpy_surface_update(int handle, struct surface *surf)
SDL_RenderClear(vdpy.dpy_renderer);
SDL_RenderCopy(vdpy.dpy_renderer, vdpy.dpy_texture, NULL, NULL);
/* This should be handled after rendering the surface_texture.
* Otherwise it will be hidden
*/
if (vdpy.cursor_tex) {
vdpy_cursor_position_transformation(&vdpy, &cursor_rect);
SDL_RenderCopy(vdpy.dpy_renderer, vdpy.cursor_tex,
NULL, &cursor_rect);
}
SDL_RenderPresent(vdpy.dpy_renderer);
/* update the rendering time */
clock_gettime(CLOCK_MONOTONIC, &vdpy.last_time);
}
void
vdpy_cursor_define(int handle, struct cursor *cur)
{
if (handle != vdpy.s.n_connect) {
return;
}
if (cur->data == NULL)
return;
if (vdpy.cursor_tex)
SDL_DestroyTexture(vdpy.cursor_tex);
vdpy.cursor_tex = SDL_CreateTexture(
vdpy.dpy_renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
cur->width, cur->height);
if (vdpy.cursor_tex == NULL) {
pr_err("Failed to create sdl_cursor surface for %p.\n", cur);
return;
}
SDL_SetTextureBlendMode(vdpy.cursor_tex, SDL_BLENDMODE_BLEND);
vdpy.cur = *cur;
SDL_UpdateTexture(vdpy.cursor_tex, NULL, cur->data, cur->width * 4);
}
void
vdpy_cursor_move(int handle, uint32_t x, uint32_t y)
{
if (handle != vdpy.s.n_connect) {
return;
}
/* Only move the position of the cursor. The cursor_texture
* will be handled in surface_update
*/
vdpy.cur.x = x;
vdpy.cur.y = y;
}
static void
vdpy_sdl_ui_refresh(void *data)
{
struct display *ui_vdpy;
struct timespec cur_time;
uint64_t elapsed_time;
SDL_Rect cursor_rect;
ui_vdpy = (struct display *)data;
@ -678,6 +744,16 @@ vdpy_sdl_ui_refresh(void *data)
SDL_RenderClear(ui_vdpy->dpy_renderer);
SDL_RenderCopy(ui_vdpy->dpy_renderer, ui_vdpy->dpy_texture, NULL, NULL);
/* This should be handled after rendering the surface_texture.
* Otherwise it will be hidden
*/
if (ui_vdpy->cursor_tex) {
vdpy_cursor_position_transformation(ui_vdpy, &cursor_rect);
SDL_RenderCopy(ui_vdpy->dpy_renderer, ui_vdpy->cursor_tex,
NULL, &cursor_rect);
}
SDL_RenderPresent(ui_vdpy->dpy_renderer);
}
@ -817,6 +893,10 @@ vdpy_sdl_display_thread(void *data)
SDL_DestroyTexture(vdpy.dpy_texture);
vdpy.dpy_texture = NULL;
}
if (vdpy.cursor_tex) {
SDL_DestroyTexture(vdpy.cursor_tex);
vdpy.cursor_tex = NULL;
}
sdl_fail:
if (vdpy.dpy_renderer) {

View File

@ -66,6 +66,19 @@ struct surface {
void *pixel;
};
struct cursor {
enum surface_type surf_type;
/* use pixman_format as the intermediate-format */
pixman_format_code_t surf_format;
uint32_t x;
uint32_t y;
uint32_t hot_x;
uint32_t hot_y;
uint32_t width;
uint32_t height;
void *data;
};
int vdpy_parse_cmd_option(const char *opts);
void gfx_ui_init();
int vdpy_init();
@ -74,6 +87,8 @@ void vdpy_surface_set(int handle, struct surface *surf);
void vdpy_surface_update(int handle, struct surface *surf);
bool vdpy_submit_bh(int handle, struct vdpy_display_bh *bh);
void vdpy_get_edid(int handle, uint8_t *edid, size_t size);
void vdpy_cursor_define(int handle, struct cursor *cur);
void vdpy_cursor_move(int handle, uint32_t x, uint32_t y);
int vdpy_deinit(int handle);
void gfx_ui_deinit();