diff --git a/devicemodel/hw/pci/virtio/virtio_gpu.c b/devicemodel/hw/pci/virtio/virtio_gpu.c index 56942456c..ff8a84f1f 100644 --- a/devicemodel/hw/pci/virtio/virtio_gpu.c +++ b/devicemodel/hw/pci/virtio/virtio_gpu.c @@ -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; diff --git a/devicemodel/hw/vdisplay_sdl.c b/devicemodel/hw/vdisplay_sdl.c index 891aa4ceb..48beddc2c 100644 --- a/devicemodel/hw/vdisplay_sdl.c +++ b/devicemodel/hw/vdisplay_sdl.c @@ -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) { diff --git a/devicemodel/include/vdisplay.h b/devicemodel/include/vdisplay.h index 9a14866b4..79448ef6f 100644 --- a/devicemodel/include/vdisplay.h +++ b/devicemodel/include/vdisplay.h @@ -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();