[PATCH v2 3/8] ACRN:DM:VGPU: Add virtio_gpu_scanout structure to handle virtio-gpu-cmds correctly
Zhao, Yakui
Now it only supports one scanout for virtio-gpu. So the scanout_id is ignored in
course of handling virtio-gpu cmd. In order to handle the virtio-gpu cmd correctly, it adds the virtio_gpu_scanout structure so that it can record the scanout info. v1->v2: Refine the field in virtio_gpu_scanout and error message for scanout_id Signed-off-by: Zhao Yakui <yakui.zhao@...> --- devicemodel/hw/pci/virtio/virtio_gpu.c | 63 ++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/devicemodel/hw/pci/virtio/virtio_gpu.c b/devicemodel/hw/pci/virtio/virtio_gpu.c index cf3d20823..d802209ad 100644 --- a/devicemodel/hw/pci/virtio/virtio_gpu.c +++ b/devicemodel/hw/pci/virtio/virtio_gpu.c @@ -348,6 +348,16 @@ enum vga_thread_status { VGA_THREAD_EOL = 0, VGA_THREAD_RUNNING }; + +struct virtio_gpu_scanout { + int scanout_id; + uint32_t resource_id; + struct virtio_gpu_rect scanout_rect; + pixman_image_t *cur_img; + struct dma_buf_info *dma_buf; + bool is_active; +}; + /* * Per-device struct */ @@ -366,6 +376,8 @@ struct virtio_gpu { int32_t vga_thread_status; uint8_t edid[VIRTIO_GPU_EDID_SIZE]; bool is_blob_supported; + int scanout_num; + struct virtio_gpu_scanout *gpu_scanouts; }; struct virtio_gpu_command { @@ -782,12 +794,22 @@ virtio_gpu_cmd_set_scanout(struct virtio_gpu_command *cmd) struct virtio_gpu_ctrl_hdr resp; struct surface surf; struct virtio_gpu *gpu; + struct virtio_gpu_scanout *gpu_scanout; gpu = cmd->gpu; memcpy(&req, cmd->iov[0].iov_base, sizeof(req)); memset(&resp, 0, sizeof(resp)); virtio_gpu_update_resp_fence(&cmd->hdr, &resp); + if (req.scanout_id >= gpu->scanout_num) { + pr_err("%s: Invalid scanout_id %d\n", req.scanout_id); + resp.type = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; + memcpy(cmd->iov[1].iov_base, &resp, sizeof(resp)); + return; + } + gpu_scanout = gpu->gpu_scanouts + req.scanout_id; + gpu_scanout->scanout_id = req.scanout_id; + r2d = virtio_gpu_find_resource_2d(gpu, req.resource_id); if ((req.resource_id == 0) || (r2d == NULL)) { vdpy_surface_set(gpu->vdpy_handle, 0, NULL); @@ -1130,6 +1152,7 @@ virtio_gpu_cmd_set_scanout_blob(struct virtio_gpu_command *cmd) struct surface surf; uint32_t drm_fourcc; struct virtio_gpu *gpu; + struct virtio_gpu_scanout *gpu_scanout; gpu = cmd->gpu; memset(&surf, 0, sizeof(surf)); @@ -1140,6 +1163,14 @@ virtio_gpu_cmd_set_scanout_blob(struct virtio_gpu_command *cmd) if (cmd->gpu->vga.enable) { cmd->gpu->vga.enable = false; } + if (req.scanout_id >= gpu->scanout_num) { + pr_err("%s: Invalid scanout_id %d\n", req.scanout_id); + resp.type = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; + memcpy(cmd->iov[cmd->iovcnt - 1].iov_base, &resp, sizeof(resp)); + return; + } + gpu_scanout = gpu->gpu_scanouts + req.scanout_id; + gpu_scanout->scanout_id = req.scanout_id; if (req.resource_id == 0) { resp.type = VIRTIO_GPU_RESP_OK_NODATA; memcpy(cmd->iov[cmd->iovcnt - 1].iov_base, &resp, sizeof(resp)); @@ -1485,10 +1516,22 @@ virtio_gpu_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts) gpu->vq, BACKEND_VBSU); + gpu->scanout_num = 1; gpu->vdpy_handle = vdpy_init(NULL); gpu->base.mtx = &gpu->mtx; gpu->base.device_caps = VIRTIO_GPU_S_HOSTCAPS; + if (gpu->scanout_num < 0) { + pr_err("%s: return incorrect scanout num %d\n", gpu->scanout_num); + return -1; + } + gpu->gpu_scanouts = calloc(gpu->scanout_num, sizeof(struct virtio_gpu_scanout)); + if (gpu->gpu_scanouts == NULL) { + pr_err("%s: out of memory for gpu_scanouts\n", __func__); + free(gpu); + return -1; + } + if (vm_allow_dmabuf(gpu->base.dev->vmctx)) { FILE *fp; char buf[16]; @@ -1643,6 +1686,7 @@ virtio_gpu_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts) { struct virtio_gpu *gpu; struct virtio_gpu_resource_2d *r2d; + int i; gpu = (struct virtio_gpu *)dev->arg; gpu->vga.enable = false; @@ -1661,6 +1705,25 @@ virtio_gpu_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts) gpu->vga.gc = NULL; } + for (i=0; i < gpu->scanout_num; i++) { + struct virtio_gpu_scanout *gpu_scanout; + + gpu_scanout = gpu->gpu_scanouts + i; + if (gpu_scanout && gpu_scanout->is_active) { + if (gpu_scanout->cur_img) { + pixman_image_unref(gpu_scanout->cur_img); + gpu_scanout->cur_img = NULL; + } + if (gpu_scanout->dma_buf) { + virtio_gpu_dmabuf_unref(gpu_scanout->dma_buf); + gpu_scanout->dma_buf = NULL; + } + gpu_scanout->is_active = false; + } + } + free(gpu->gpu_scanouts); + gpu->gpu_scanouts = NULL; + pthread_mutex_destroy(&gpu->vga_thread_mtx); while (LIST_FIRST(&gpu->r2d_list)) { r2d = LIST_FIRST(&gpu->r2d_list); -- 2.25.1 |
|
[PATCH v2 2/8] ACRN:DM:VDisplay: vdpy_init connection returns the supported number of vScreen
Zhao, Yakui
Vdisplay module will create the gui_window (vScreen) based on the virtio-gpu
parameter. When virtio-gpu device tries to establish the connection with vdisplay module, it will return the supported number of vScreen. Then the virtio-gpu device can initialize the correct info for the guest_vm. BTW: The number is fixed to 1. Signed-off-by: Zhao Yakui <yakui.zhao@...> --- devicemodel/hw/pci/virtio/virtio_gpu.c | 2 +- devicemodel/hw/vdisplay_sdl.c | 4 +++- devicemodel/include/vdisplay.h | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/devicemodel/hw/pci/virtio/virtio_gpu.c b/devicemodel/hw/pci/virtio/virtio_gpu.c index 2f8c4362e..cf3d20823 100644 --- a/devicemodel/hw/pci/virtio/virtio_gpu.c +++ b/devicemodel/hw/pci/virtio/virtio_gpu.c @@ -1485,7 +1485,7 @@ virtio_gpu_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts) gpu->vq, BACKEND_VBSU); - gpu->vdpy_handle = vdpy_init(); + gpu->vdpy_handle = vdpy_init(NULL); gpu->base.mtx = &gpu->mtx; gpu->base.device_caps = VIRTIO_GPU_S_HOSTCAPS; diff --git a/devicemodel/hw/vdisplay_sdl.c b/devicemodel/hw/vdisplay_sdl.c index 567a2de6f..4cf19f985 100644 --- a/devicemodel/hw/vdisplay_sdl.c +++ b/devicemodel/hw/vdisplay_sdl.c @@ -1069,7 +1069,7 @@ bool vdpy_submit_bh(int handle, struct vdpy_display_bh *bh_task) } int -vdpy_init() +vdpy_init(int *num_vscreens) { int err, count; @@ -1100,6 +1100,8 @@ vdpy_init() } vdpy.s.n_connect++; + if (num_vscreens) + *num_vscreens = 1; return vdpy.s.n_connect; } diff --git a/devicemodel/include/vdisplay.h b/devicemodel/include/vdisplay.h index fc0e91b46..ab15566d9 100644 --- a/devicemodel/include/vdisplay.h +++ b/devicemodel/include/vdisplay.h @@ -85,7 +85,7 @@ struct cursor { int vdpy_parse_cmd_option(const char *opts); int gfx_ui_init(); -int vdpy_init(); +int vdpy_init(int *num_vscreens); void vdpy_get_display_info(int handle, int scanout_id, struct display_info *info); void vdpy_surface_set(int handle, int scanout_id, struct surface *surf); void vdpy_surface_update(int handle, int scanout_id, struct surface *surf); -- 2.25.1 |
|
[PATCH v2 1/8] ACRN:DM:VDISPLAY: Refine display API to support multi scanout_window
Zhao, Yakui
Currenly it can support only one display_win. When virtio-gpu wants to display
the framebuffer from Guest_vm, it will render it into the default win. In order to support multi-window, the scanout_id is added for display API. After display API is refined, the vdisplay and virtio-gpu can support the multi-win independently. BTW: Now the scanout_id is not implemented in vdisplay module and the virtio-gpu always passes the zero. It will be implemeneted in the later patches. Signed-off-by: Zhao Yakui <yakui.zhao@...> --- devicemodel/hw/pci/virtio/virtio_gpu.c | 28 +++++++++++++------------- devicemodel/hw/vdisplay_sdl.c | 12 +++++------ devicemodel/include/vdisplay.h | 12 +++++------ 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/devicemodel/hw/pci/virtio/virtio_gpu.c b/devicemodel/hw/pci/virtio/virtio_gpu.c index 4ba219bc1..2f8c4362e 100644 --- a/devicemodel/hw/pci/virtio/virtio_gpu.c +++ b/devicemodel/hw/pci/virtio/virtio_gpu.c @@ -556,7 +556,7 @@ virtio_gpu_cmd_get_edid(struct virtio_gpu_command *cmd) resp.size = 128; resp.hdr.type = VIRTIO_GPU_RESP_OK_EDID; virtio_gpu_update_resp_fence(&cmd->hdr, &resp.hdr); - vdpy_get_edid(gpu->vdpy_handle, resp.edid, resp.size); + vdpy_get_edid(gpu->vdpy_handle, 0, resp.edid, resp.size); memcpy(cmd->iov[1].iov_base, &resp, sizeof(resp)); } @@ -570,7 +570,7 @@ virtio_gpu_cmd_get_display_info(struct virtio_gpu_command *cmd) gpu = cmd->gpu; cmd->iolen = sizeof(resp); memset(&resp, 0, sizeof(resp)); - vdpy_get_display_info(gpu->vdpy_handle, &info); + vdpy_get_display_info(gpu->vdpy_handle, 0, &info); resp.hdr.type = VIRTIO_GPU_RESP_OK_DISPLAY_INFO; virtio_gpu_update_resp_fence(&cmd->hdr, &resp.hdr); resp.pmodes[0].enabled = 1; @@ -790,7 +790,7 @@ virtio_gpu_cmd_set_scanout(struct virtio_gpu_command *cmd) r2d = virtio_gpu_find_resource_2d(gpu, req.resource_id); if ((req.resource_id == 0) || (r2d == NULL)) { - vdpy_surface_set(gpu->vdpy_handle, NULL); + vdpy_surface_set(gpu->vdpy_handle, 0, NULL); resp.type = VIRTIO_GPU_RESP_OK_NODATA; memcpy(cmd->iov[1].iov_base, &resp, sizeof(resp)); return; @@ -814,7 +814,7 @@ virtio_gpu_cmd_set_scanout(struct virtio_gpu_command *cmd) surf.stride = pixman_image_get_stride(r2d->image); surf.surf_format = r2d->format; surf.surf_type = SURFACE_PIXMAN; - vdpy_surface_set(gpu->vdpy_handle, &surf); + vdpy_surface_set(gpu->vdpy_handle, 0, &surf); pixman_image_unref(r2d->image); resp.type = VIRTIO_GPU_RESP_OK_NODATA; } @@ -934,7 +934,7 @@ virtio_gpu_cmd_resource_flush(struct virtio_gpu_command *cmd) virtio_gpu_dmabuf_ref(r2d->dma_info); surf.dma_info.dmabuf_fd = r2d->dma_info->dmabuf_fd; surf.surf_type = SURFACE_DMABUF; - vdpy_surface_update(gpu->vdpy_handle, &surf); + vdpy_surface_update(gpu->vdpy_handle, 0, &surf); resp.type = VIRTIO_GPU_RESP_OK_NODATA; memcpy(cmd->iov[1].iov_base, &resp, sizeof(resp)); virtio_gpu_dmabuf_unref(r2d->dma_info); @@ -949,7 +949,7 @@ virtio_gpu_cmd_resource_flush(struct virtio_gpu_command *cmd) surf.stride = pixman_image_get_stride(r2d->image); surf.surf_format = r2d->format; surf.surf_type = SURFACE_PIXMAN; - vdpy_surface_update(gpu->vdpy_handle, &surf); + vdpy_surface_update(gpu->vdpy_handle, 0, &surf); pixman_image_unref(r2d->image); cmd->iolen = sizeof(resp); @@ -1143,7 +1143,7 @@ virtio_gpu_cmd_set_scanout_blob(struct virtio_gpu_command *cmd) if (req.resource_id == 0) { resp.type = VIRTIO_GPU_RESP_OK_NODATA; memcpy(cmd->iov[cmd->iovcnt - 1].iov_base, &resp, sizeof(resp)); - vdpy_surface_set(gpu->vdpy_handle, NULL); + vdpy_surface_set(gpu->vdpy_handle, 0, NULL); return; } r2d = virtio_gpu_find_resource_2d(cmd->gpu, req.resource_id); @@ -1187,7 +1187,7 @@ virtio_gpu_cmd_set_scanout_blob(struct virtio_gpu_command *cmd) break; } surf.dma_info.surf_fourcc = drm_fourcc; - vdpy_surface_set(gpu->vdpy_handle, &surf); + vdpy_surface_set(gpu->vdpy_handle, 0, &surf); resp.type = VIRTIO_GPU_RESP_OK_NODATA; memcpy(cmd->iov[cmd->iovcnt - 1].iov_base, &resp, sizeof(resp)); virtio_gpu_dmabuf_unref(r2d->dma_info); @@ -1312,7 +1312,7 @@ virtio_gpu_cmd_update_cursor(struct virtio_gpu_command *cmd) cur.height = r2d->height; pixman_image_ref(r2d->image); cur.data = pixman_image_get_data(r2d->image); - vdpy_cursor_define(gpu->vdpy_handle, &cur); + vdpy_cursor_define(gpu->vdpy_handle, 0, &cur); pixman_image_unref(r2d->image); } } @@ -1325,7 +1325,7 @@ virtio_gpu_cmd_move_cursor(struct virtio_gpu_command *cmd) gpu = cmd->gpu; memcpy(&req, cmd->iov[0].iov_base, sizeof(req)); - vdpy_cursor_move(gpu->vdpy_handle, req.pos.x, req.pos.y); + vdpy_cursor_move(gpu->vdpy_handle, 0, req.pos.x, req.pos.y); } static void @@ -1397,10 +1397,10 @@ virtio_gpu_vga_bh(void *param) gpu->vga.surf.pixel = gpu->vga.gc->gc_image->data; gpu->vga.surf.surf_format = PIXMAN_a8r8g8b8; gpu->vga.surf.surf_type = SURFACE_PIXMAN; - vdpy_surface_set(gpu->vdpy_handle, &gpu->vga.surf); + vdpy_surface_set(gpu->vdpy_handle, 0, &gpu->vga.surf); } - vdpy_surface_update(gpu->vdpy_handle, &gpu->vga.surf); + vdpy_surface_update(gpu->vdpy_handle, 0, &gpu->vga.surf); } static void * @@ -1553,7 +1553,7 @@ virtio_gpu_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts) pci_set_cfgdata16(dev, PCIR_SUBVEND_0, VIRTIO_VENDOR); LIST_INIT(&gpu->r2d_list); - vdpy_get_display_info(gpu->vdpy_handle, &info); + vdpy_get_display_info(gpu->vdpy_handle, 0, &info); /*** PCI Config BARs setup ***/ /** BAR0: VGA framebuffer **/ @@ -1566,7 +1566,7 @@ virtio_gpu_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts) /** BAR2: VGA & Virtio Modern regs **/ /* EDID data blob [0x000~0x3ff] */ - vdpy_get_edid(gpu->vdpy_handle, gpu->edid, VIRTIO_GPU_EDID_SIZE); + vdpy_get_edid(gpu->vdpy_handle, 0, gpu->edid, VIRTIO_GPU_EDID_SIZE); /* VGA ioports regs [0x400~0x41f] */ gpu->vga.gc = gc_init(info.width, info.height, ctx->fb_base); gpu->vga.dev = vga_init(gpu->vga.gc, 0); diff --git a/devicemodel/hw/vdisplay_sdl.c b/devicemodel/hw/vdisplay_sdl.c index 21ceb2325..567a2de6f 100644 --- a/devicemodel/hw/vdisplay_sdl.c +++ b/devicemodel/hw/vdisplay_sdl.c @@ -510,7 +510,7 @@ vdpy_edid_generate(uint8_t *edid, size_t size, struct edid_info *info) } void -vdpy_get_edid(int handle, uint8_t *edid, size_t size) +vdpy_get_edid(int handle, int scanout_id, uint8_t *edid, size_t size) { struct edid_info edid_info; @@ -534,7 +534,7 @@ vdpy_get_edid(int handle, uint8_t *edid, size_t size) } void -vdpy_get_display_info(int handle, struct display_info *info) +vdpy_get_display_info(int handle, int scanout_id, struct display_info *info) { if (handle == vdpy.s.n_connect) { info->xoff = vdpy.info.xoff; @@ -582,7 +582,7 @@ sdl_gl_display_init(void) } void -vdpy_surface_set(int handle, struct surface *surf) +vdpy_surface_set(int handle, int scanout_id, struct surface *surf) { pixman_image_t *src_img; int format; @@ -749,7 +749,7 @@ vdpy_cursor_position_transformation(struct display *vdpy, SDL_Rect *rect) } void -vdpy_surface_update(int handle, struct surface *surf) +vdpy_surface_update(int handle, int scanout_id, struct surface *surf) { SDL_Rect cursor_rect; @@ -792,7 +792,7 @@ vdpy_surface_update(int handle, struct surface *surf) } void -vdpy_cursor_define(int handle, struct cursor *cur) +vdpy_cursor_define(int handle, int scanout_id, struct cursor *cur) { if (handle != vdpy.s.n_connect) { return; @@ -826,7 +826,7 @@ vdpy_cursor_define(int handle, struct cursor *cur) } void -vdpy_cursor_move(int handle, uint32_t x, uint32_t y) +vdpy_cursor_move(int handle, int scanout_id, uint32_t x, uint32_t y) { if (handle != vdpy.s.n_connect) { return; diff --git a/devicemodel/include/vdisplay.h b/devicemodel/include/vdisplay.h index 99506469b..fc0e91b46 100644 --- a/devicemodel/include/vdisplay.h +++ b/devicemodel/include/vdisplay.h @@ -86,13 +86,13 @@ struct cursor { int vdpy_parse_cmd_option(const char *opts); int gfx_ui_init(); int vdpy_init(); -void vdpy_get_display_info(int handle, struct display_info *info); -void vdpy_surface_set(int handle, struct surface *surf); -void vdpy_surface_update(int handle, struct surface *surf); +void vdpy_get_display_info(int handle, int scanout_id, struct display_info *info); +void vdpy_surface_set(int handle, int scanout_id, struct surface *surf); +void vdpy_surface_update(int handle, int scanout_id, 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); +void vdpy_get_edid(int handle, int scanout_id, uint8_t *edid, size_t size); +void vdpy_cursor_define(int handle, int scanout_id, struct cursor *cur); +void vdpy_cursor_move(int handle, int scanout_id, uint32_t x, uint32_t y); int vdpy_deinit(int handle); void gfx_ui_deinit(); -- 2.25.1 |
|
[PATCH v2 0/8] ACRN:DM:VGPU Add the support of Multi-display for guest_vm
Zhao, Yakui
Virtio-gpu is added to support the display for Guest VM. The Virtio-gpu driver in guest vm
will try to submit the cmd of framebuffer that needs to be displayed. The virtio-gpu BE driver will call the vdisplay API to display the request framebuffer on the corresponding graphics window. But now only one display is supported for each VM. Based on the virtio-gpu spec, it can support multi-display so that the guest_vm can optimize to submit the display regions. This patch set will try to add the support of multi-display for guest_vm. And it will cover the below parts. 1. Refine display API tso that the VGPU and VDISPLAY module can add the function of multi-display/windows. 2. Refine the vdisplay module so that it can support multi-window 3. Refine the virtio-gpu BE module so that it can handle the multi-display request from guest_vm. v1->v2: update the error_message and other minor refinement Zhao Yakui (8): ACRN:DM:VDISPLAY: Refine display API to support multi scanout_window ACRN:DM:VDisplay: vdpy_init connection returns the supported number of vScreen ACRN:DM:VGPU: Add virtio_gpu_scanout structure to handle virtio-gpu-cmds correctly ACRN:DM:VGPU: Handle the virtio-gpu-cmds based on scanout_id in cmd_request ACRN:DM:VGPU: Handle the scanout_id for cursor virtio-gpu-cmd ACRN:DM:VGPU: virtio-gpu-flush cmds check whether one scanout_win needs to be displayed ACRN:DM:VGPU: Calibrate the offset in dmabuf/pixman_image to display the scanout_window ACRN:DM:VGPU: Return the parsed scanout_num to virtio_gpu in Guest_VM devicemodel/hw/pci/virtio/virtio_gpu.c | 255 +++++++++++++++++++++---- devicemodel/hw/vdisplay_sdl.c | 18 +- devicemodel/include/vdisplay.h | 15 +- 3 files changed, 231 insertions(+), 57 deletions(-) -- 2.25.1 |
|
Re: [PATCH] doc: update hypervisor shell usage
How about instead:
toggle quoted message
Show quoted text
The ACRN shell is a text-based terminal for the hypervisor, accessible via the target system's serial port. It is only available when the hypervisor build type is debug, the serial console port is configured, and a terminal emulator on your development computer is connected, typically via a serial-to-USB cable. The ACRN shell provides useful debugging commands for displaying internal system states, environment settings, and hypervisor statistics as well as reading and writing CPU model-specific registers (MSR). A short command history is maintained that lets you use the :kbd:`UP` and :kbd:`DOWN` keys to browse the command history and :kbd:`HOME`, :kbd:`END`, :kbd:`LEFT`, and :kbd:`RIGHT` keys to select an edit point within the command. Here's the list of commands supported by the ACRN shell, followed by example uses of these commands: -- david -----Original Message----- |
|
[PATCH v2 1/2] dm: vdisplay: refine vdisplay core concept abstractions
Sun, Peng
From: Sun Peng <peng.p.sun@...>
Add new concept "vscreen" to abstract all specs about screen in a display server. This can provide convenience to add more screens for one VM. Signed-off-by: Sun Peng <peng.p.sun@...> --- devicemodel/hw/vdisplay_sdl.c | 482 ++++++++++++++++++++-------------- 1 file changed, 288 insertions(+), 194 deletions(-) diff --git a/devicemodel/hw/vdisplay_sdl.c b/devicemodel/hw/vdisplay_sdl.c index 4b0ec69e5..e7cabb184 100644 --- a/devicemodel/hw/vdisplay_sdl.c +++ b/devicemodel/hw/vdisplay_sdl.c @@ -32,6 +32,7 @@ #define VDPY_MIN_WIDTH 640 #define VDPY_MIN_HEIGHT 480 #define transto_10bits(color) (uint16_t)(color * 1024 + 0.5) +#define VSCREEN_MAX_NUM 1 static unsigned char default_raw_argb[VDPY_DEFAULT_WIDTH * VDPY_DEFAULT_HEIGHT * 4]; @@ -51,27 +52,39 @@ struct egl_display_ops { PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; }; -static struct display { +struct vscreen { + struct display_info info; int pscreen_id; SDL_Rect pscreen_rect; - struct display_info info; - struct state s; - SDL_Texture *dpy_texture; - SDL_Window *dpy_win; - SDL_Renderer *dpy_renderer; - pixman_image_t *dpy_img; - pthread_t tid; - int width, height; // Width/height of dpy_win - int org_x, org_y; - int guest_width, guest_height; + bool is_fullscreen; + int org_x; + int org_y; + int width; + int height; + int guest_width; + int guest_height; struct surface surf; struct cursor cur; - SDL_Texture *cursor_tex; + SDL_Texture *surf_tex; + SDL_Texture *cur_tex; + int surf_updates; + int cur_updates; + SDL_Window *win; + SDL_Renderer *renderer; + pixman_image_t *img; + EGLImage egl_img; + /* Record the update_time that is activated from guest_vm */ + struct timespec last_time; +}; + +static struct display { + struct state s; + struct vscreen *vscrs; + int vscrs_num; + pthread_t tid; /* Add one UI_timer(33ms) to render the buffers from guest_vm */ struct acrn_timer ui_timer; struct vdpy_display_bh ui_timer_bh; - /* Record the update_time that is activated from guest_vm */ - struct timespec last_time; // protect the request_list pthread_mutex_t vdisplay_mutex; // receive the signal that request is submitted @@ -82,14 +95,11 @@ static struct display { SDL_GLContext eglContext; EGLDisplay eglDisplay; struct egl_display_ops gl_ops; - EGLImage cur_egl_img; } vdpy = { .s.is_ui_realized = false, .s.is_active = false, .s.is_wayland = false, .s.is_x11 = false, - .s.is_fullscreen = false, - .s.updates = 0, .s.n_connect = 0 }; @@ -514,10 +524,16 @@ void vdpy_get_edid(int handle, int scanout_id, uint8_t *edid, size_t size) { struct edid_info edid_info; + struct vscreen *vscr; + + if (scanout_id >= vdpy.vscrs_num) + return; + + vscr = vdpy.vscrs + scanout_id; if (handle == vdpy.s.n_connect) { - edid_info.prefx = vdpy.info.width; - edid_info.prefy = vdpy.info.height; + edid_info.prefx = vscr->info.width; + edid_info.prefy = vscr->info.height; edid_info.maxx = VDPY_MAX_WIDTH; edid_info.maxy = VDPY_MAX_HEIGHT; } else { @@ -537,11 +553,18 @@ vdpy_get_edid(int handle, int scanout_id, uint8_t *edid, size_t size) void vdpy_get_display_info(int handle, int scanout_id, struct display_info *info) { + struct vscreen *vscr; + + if (scanout_id >= vdpy.vscrs_num) + return; + + vscr = vdpy.vscrs + scanout_id; + if (handle == vdpy.s.n_connect) { - info->xoff = vdpy.info.xoff; - info->yoff = vdpy.info.yoff; - info->width = vdpy.info.width; - info->height = vdpy.info.height; + info->xoff = vscr->info.xoff; + info->yoff = vscr->info.yoff; + info->width = vscr->info.width; + info->height = vscr->info.height; } else { info->xoff = 0; info->yoff = 0; @@ -554,6 +577,8 @@ static void sdl_gl_display_init(void) { struct egl_display_ops *gl_ops = &vdpy.gl_ops; + struct vscreen *vscr; + int i; /* obtain the eglDisplay/eglContext */ vdpy.eglDisplay = eglGetCurrentDisplay(); @@ -570,7 +595,11 @@ sdl_gl_display_init(void) gl_ops->glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress("glEGLImageTargetTexture2DOES"); - vdpy.cur_egl_img = EGL_NO_IMAGE_KHR; + for (i = 0; i < vdpy.vscrs_num; i++) { + vscr = vdpy.vscrs + i; + vscr->egl_img = EGL_NO_IMAGE_KHR; + } + if ((gl_ops->eglCreateImageKHR == NULL) || (gl_ops->eglDestroyImageKHR == NULL) || (gl_ops->glEGLImageTargetTexture2DOES == NULL)) { @@ -588,6 +617,7 @@ vdpy_surface_set(int handle, int scanout_id, struct surface *surf) pixman_image_t *src_img; int format; int access, i; + struct vscreen *vscr; if (handle != vdpy.s.n_connect) { return; @@ -599,9 +629,15 @@ vdpy_surface_set(int handle, int scanout_id, struct surface *surf) return; } + if (scanout_id >= vdpy.vscrs_num) { + return; + } + + vscr = vdpy.vscrs + scanout_id; + if (surf == NULL ) { - vdpy.surf.width = 0; - vdpy.surf.height = 0; + vscr->surf.width = 0; + vscr->surf.height = 0; /* Need to use the default 640x480 for the SDL_Texture */ src_img = pixman_image_create_bits(PIXMAN_a8r8g8b8, VDPY_MIN_WIDTH, VDPY_MIN_HEIGHT, @@ -611,8 +647,8 @@ vdpy_surface_set(int handle, int scanout_id, struct surface *surf) pr_err("failed to create pixman_image\n"); return; } - vdpy.guest_width = VDPY_MIN_WIDTH; - vdpy.guest_height = VDPY_MIN_HEIGHT; + vscr->guest_width = VDPY_MIN_WIDTH; + vscr->guest_height = VDPY_MIN_HEIGHT; } else if (surf->surf_type == SURFACE_PIXMAN) { src_img = pixman_image_create_bits(surf->surf_format, surf->width, surf->height, surf->pixel, @@ -621,21 +657,21 @@ vdpy_surface_set(int handle, int scanout_id, struct surface *surf) pr_err("failed to create pixman_image\n"); return; } - vdpy.surf = *surf; - vdpy.guest_width = surf->width; - vdpy.guest_height = surf->height; + vscr->surf = *surf; + vscr->guest_width = surf->width; + vscr->guest_height = surf->height; } else if (surf->surf_type == SURFACE_DMABUF) { src_img = NULL; - vdpy.surf = *surf; - vdpy.guest_width = surf->width; - vdpy.guest_height = surf->height; + vscr->surf = *surf; + vscr->guest_width = surf->width; + vscr->guest_height = surf->height; } else { /* Unsupported type */ return; } - if (vdpy.dpy_texture) { - SDL_DestroyTexture(vdpy.dpy_texture); + if (vscr->surf_tex) { + SDL_DestroyTexture(vscr->surf_tex); } if (surf && (surf->surf_type == SURFACE_DMABUF)) { access = SDL_TEXTUREACCESS_STATIC; @@ -666,23 +702,23 @@ vdpy_surface_set(int handle, int scanout_id, struct surface *surf) pixman_image_get_format(src_img)); } } - vdpy.dpy_texture = SDL_CreateTexture(vdpy.dpy_renderer, + vscr->surf_tex = SDL_CreateTexture(vscr->renderer, format, access, - vdpy.guest_width, vdpy.guest_height); + vscr->guest_width, vscr->guest_height); - if (vdpy.dpy_texture == NULL) { + if (vscr->surf_tex == NULL) { pr_err("Failed to create SDL_texture for surface.\n"); } /* For the surf_switch, it will be updated in surface_update */ if (!surf) { - SDL_UpdateTexture(vdpy.dpy_texture, NULL, + SDL_UpdateTexture(vscr->surf_tex, NULL, pixman_image_get_data(src_img), pixman_image_get_stride(src_img)); - SDL_RenderClear(vdpy.dpy_renderer); - SDL_RenderCopy(vdpy.dpy_renderer, vdpy.dpy_texture, NULL, NULL); - SDL_RenderPresent(vdpy.dpy_renderer); + SDL_RenderClear(vscr->renderer); + SDL_RenderCopy(vscr->renderer, vscr->surf_tex, NULL, NULL); + SDL_RenderPresent(vscr->renderer); } else if (surf->surf_type == SURFACE_DMABUF) { EGLImageKHR egl_img = EGL_NO_IMAGE_KHR; EGLint attrs[64]; @@ -713,46 +749,54 @@ vdpy_surface_set(int handle, int scanout_id, struct surface *surf) return; } - SDL_GL_BindTexture(vdpy.dpy_texture, NULL, NULL); + SDL_GL_BindTexture(vscr->surf_tex, NULL, NULL); gl_ops->glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_img); - if (vdpy.cur_egl_img != EGL_NO_IMAGE_KHR) + if (vscr->egl_img != EGL_NO_IMAGE_KHR) gl_ops->eglDestroyImageKHR(vdpy.eglDisplay, - vdpy.cur_egl_img); + vscr->egl_img); /* In theory the created egl_img can be released after it is bound * to texture. * Now it is released next time so that it is controlled correctly */ - vdpy.cur_egl_img = egl_img; + vscr->egl_img = egl_img; } - if (vdpy.dpy_img) - pixman_image_unref(vdpy.dpy_img); + if (vscr->img) + pixman_image_unref(vscr->img); if (surf == NULL) { - SDL_SetWindowTitle(vdpy.dpy_win, + SDL_SetWindowTitle(vscr->win, "Not activate display yet!"); } else { - SDL_SetWindowTitle(vdpy.dpy_win, + SDL_SetWindowTitle(vscr->win, "ACRN Virtual Monitor"); } /* Replace the cur_img with the created_img */ - vdpy.dpy_img = src_img; + vscr->img = src_img; } void -vdpy_cursor_position_transformation(struct display *vdpy, SDL_Rect *rect) +vdpy_cursor_position_transformation(struct display *vdpy, int scanout_id, 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; + struct vscreen *vscr; + + if (scanout_id >= vdpy->vscrs_num) { + return; + } + + vscr = vdpy->vscrs + scanout_id; + rect->x = (vscr->cur.x * vscr->width) / vscr->guest_width; + rect->y = (vscr->cur.y * vscr->height) / vscr->guest_height; + rect->w = (vscr->cur.width * vscr->width) / vscr->guest_width; + rect->h = (vscr->cur.height * vscr->height) / vscr->guest_height; } void vdpy_surface_update(int handle, int scanout_id, struct surface *surf) { SDL_Rect cursor_rect; + struct vscreen *vscr; if (handle != vdpy.s.n_connect) { return; @@ -769,32 +813,39 @@ vdpy_surface_update(int handle, int scanout_id, struct surface *surf) return; } + if (scanout_id >= vdpy.vscrs_num) { + return; + } + + vscr = vdpy.vscrs + scanout_id; if (surf->surf_type == SURFACE_PIXMAN) - SDL_UpdateTexture(vdpy.dpy_texture, NULL, + SDL_UpdateTexture(vscr->surf_tex, NULL, surf->pixel, surf->stride); - SDL_RenderClear(vdpy.dpy_renderer); - SDL_RenderCopy(vdpy.dpy_renderer, vdpy.dpy_texture, NULL, NULL); + SDL_RenderClear(vscr->renderer); + SDL_RenderCopy(vscr->renderer, vscr->surf_tex, 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, + if (vscr->cur_tex) { + vdpy_cursor_position_transformation(&vdpy, scanout_id, &cursor_rect); + SDL_RenderCopy(vscr->renderer, vscr->cur_tex, NULL, &cursor_rect); } - SDL_RenderPresent(vdpy.dpy_renderer); + SDL_RenderPresent(vscr->renderer); /* update the rendering time */ - clock_gettime(CLOCK_MONOTONIC, &vdpy.last_time); + clock_gettime(CLOCK_MONOTONIC, &vscr->last_time); } void vdpy_cursor_define(int handle, int scanout_id, struct cursor *cur) { + struct vscreen *vscr; + if (handle != vdpy.s.n_connect) { return; } @@ -805,39 +856,52 @@ vdpy_cursor_define(int handle, int scanout_id, struct cursor *cur) return; } + if (scanout_id >= vdpy.vscrs_num) { + return; + } + if (cur->data == NULL) return; - if (vdpy.cursor_tex) - SDL_DestroyTexture(vdpy.cursor_tex); + vscr = vdpy.vscrs + scanout_id; + + if (vscr->cur_tex) + SDL_DestroyTexture(vscr->cur_tex); - vdpy.cursor_tex = SDL_CreateTexture( - vdpy.dpy_renderer, + vscr->cur_tex = SDL_CreateTexture( + vscr->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, cur->width, cur->height); - if (vdpy.cursor_tex == NULL) { + if (vscr->cur_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); + SDL_SetTextureBlendMode(vscr->cur_tex, SDL_BLENDMODE_BLEND); + vscr->cur = *cur; + SDL_UpdateTexture(vscr->cur_tex, NULL, cur->data, cur->width * 4); } void vdpy_cursor_move(int handle, int scanout_id, uint32_t x, uint32_t y) { + struct vscreen *vscr; + if (handle != vdpy.s.n_connect) { return; } + if (scanout_id >= vdpy.vscrs_num) { + return; + } + + vscr = vdpy.vscrs + scanout_id; /* Only move the position of the cursor. The cursor_texture * will be handled in surface_update */ - vdpy.cur.x = x; - vdpy.cur.y = y; + vscr->cur.x = x; + vscr->cur.y = y; } static void @@ -847,35 +911,41 @@ vdpy_sdl_ui_refresh(void *data) struct timespec cur_time; uint64_t elapsed_time; SDL_Rect cursor_rect; + struct vscreen *vscr; + int i; ui_vdpy = (struct display *)data; - /* Skip it if no surface needs to be rendered */ - if (ui_vdpy->dpy_texture == NULL) - return; + for (i = 0; i < vdpy.vscrs_num; i++) { + vscr = ui_vdpy->vscrs + i; - clock_gettime(CLOCK_MONOTONIC, &cur_time); + /* Skip it if no surface needs to be rendered */ + if (vscr->surf_tex == NULL) + continue; - elapsed_time = (cur_time.tv_sec - ui_vdpy->last_time.tv_sec) * 1000000000 + - cur_time.tv_nsec - ui_vdpy->last_time.tv_nsec; + clock_gettime(CLOCK_MONOTONIC, &cur_time); - /* the time interval is less than 10ms. Skip it */ - if (elapsed_time < 10000000) - return; + elapsed_time = (cur_time.tv_sec - vscr->last_time.tv_sec) * 1000000000 + + cur_time.tv_nsec - vscr->last_time.tv_nsec; - SDL_RenderClear(ui_vdpy->dpy_renderer); - SDL_RenderCopy(ui_vdpy->dpy_renderer, ui_vdpy->dpy_texture, NULL, NULL); + /* the time interval is less than 10ms. Skip it */ + if (elapsed_time < 10000000) + return; - /* 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_RenderClear(vscr->renderer); + SDL_RenderCopy(vscr->renderer, vscr->surf_tex, NULL, NULL); - SDL_RenderPresent(ui_vdpy->dpy_renderer); + /* This should be handled after rendering the surface_texture. + * Otherwise it will be hidden + */ + if (vscr->cur_tex) { + vdpy_cursor_position_transformation(ui_vdpy, i, &cursor_rect); + SDL_RenderCopy(vscr->renderer, vscr->cur_tex, + NULL, &cursor_rect); + } + + SDL_RenderPresent(vscr->renderer); + } } static void @@ -911,58 +981,64 @@ vdpy_sdl_display_thread(void *data) struct itimerspec ui_timer_spec; int max_width, max_height; int min_width, min_height; + struct vscreen *vscr; + int i; - max_width = MIN(vdpy.pscreen_rect.w, VDPY_MAX_WIDTH); - max_height = MIN(vdpy.pscreen_rect.h, VDPY_MAX_HEIGHT); - min_width = MAX(vdpy.pscreen_rect.w, VDPY_MIN_WIDTH); - min_height = MAX(vdpy.pscreen_rect.h, VDPY_MIN_HEIGHT); - if (vdpy.width && vdpy.height) { - /* clip the region between (640x480) and (1920x1080) */ - if (vdpy.width < min_width) - vdpy.width = min_width; - if (vdpy.width > max_width) - vdpy.width = max_width; - if (vdpy.height < min_height) - vdpy.height = min_height; - if (vdpy.height > max_height) - vdpy.height = max_height; - } else { - /* the default window(1280x720) is created with undefined pos - * when no geometry info is passed - */ - vdpy.org_x = 0xFFFF; - vdpy.org_y = 0xFFFF; - vdpy.width = VDPY_DEFAULT_WIDTH; - vdpy.height = VDPY_DEFAULT_HEIGHT; - } + for (i = 0; i < vdpy.vscrs_num; i++) { + vscr = vdpy.vscrs + i; + max_width = MIN(vscr->pscreen_rect.w, VDPY_MAX_WIDTH); + max_height = MIN(vscr->pscreen_rect.h, VDPY_MAX_HEIGHT); + min_width = MAX(vscr->pscreen_rect.w, VDPY_MIN_WIDTH); + min_height = MAX(vscr->pscreen_rect.h, VDPY_MIN_HEIGHT); + if (vscr->width && vscr->height) { + /* clip the region between (640x480) and (1920x1080) */ + if (vscr->width < min_width) + vscr->width = min_width; + if (vscr->width > max_width) + vscr->width = max_width; + if (vscr->height < min_height) + vscr->height = min_height; + if (vscr->height > max_height) + vscr->height = max_height; + } else { + /* the default window(1280x720) is created with undefined pos + * when no geometry info is passed + */ + vscr->org_x = 0xFFFF; + vscr->org_y = 0xFFFF; + vscr->width = VDPY_DEFAULT_WIDTH; + vscr->height = VDPY_DEFAULT_HEIGHT; + } - win_flags = SDL_WINDOW_OPENGL | - SDL_WINDOW_ALWAYS_ON_TOP | - SDL_WINDOW_SHOWN; - if (vdpy.s.is_fullscreen) { - win_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; - } - vdpy.dpy_win = NULL; - vdpy.dpy_renderer = NULL; - vdpy.dpy_img = NULL; - vdpy.org_x = vdpy.pscreen_rect.x; - vdpy.org_y = vdpy.pscreen_rect.y; - // Zoom to width and height of pscreen is fullscreen enabled - vdpy.dpy_win = SDL_CreateWindow("ACRN_DM", - vdpy.org_x, vdpy.org_y, - vdpy.width, vdpy.height, + win_flags = SDL_WINDOW_OPENGL | + SDL_WINDOW_ALWAYS_ON_TOP | + SDL_WINDOW_SHOWN; + if (vscr->is_fullscreen) { + win_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + } + vscr->win = NULL; + vscr->renderer = NULL; + vscr->img = NULL; + vscr->org_x = vscr->pscreen_rect.x; + vscr->org_y = vscr->pscreen_rect.y; + // Zoom to width and height of pscreen is fullscreen enabled + vscr->win = SDL_CreateWindow("ACRN_DM", + vscr->org_x, vscr->org_y, + vscr->width, vscr->height, win_flags); - if (vdpy.dpy_win == NULL) { - pr_err("Failed to Create SDL_Window\n"); - goto sdl_fail; - } - pr_info("SDL display bind to screen %d: [%d,%d,%d,%d].\n", vdpy.pscreen_id, - vdpy.org_x, vdpy.org_y, vdpy.width, vdpy.height); + if (vscr->win == NULL) { + pr_err("Failed to Create SDL_Window\n"); + goto sdl_fail; + } + pr_info("SDL display bind to screen %d: [%d,%d,%d,%d].\n", vscr->pscreen_id, + vscr->org_x, vscr->org_y, vscr->width, vscr->height); - vdpy.dpy_renderer = SDL_CreateRenderer(vdpy.dpy_win, -1, 0); - if (vdpy.dpy_renderer == NULL) { - pr_err("Failed to Create GL_Renderer \n"); - goto sdl_fail; + vscr->renderer = SDL_CreateRenderer(vscr->win, -1, 0); + if (vscr->renderer == NULL) { + pr_err("Failed to Create GL_Renderer \n"); + goto sdl_fail; + } + clock_gettime(CLOCK_MONOTONIC, &vscr->last_time); } sdl_gl_display_init(); pthread_mutex_init(&vdpy.vdisplay_mutex, NULL); @@ -972,7 +1048,6 @@ vdpy_sdl_display_thread(void *data) vdpy.ui_timer_bh.task_cb = vdpy_sdl_ui_refresh; vdpy.ui_timer_bh.data = &vdpy; - clock_gettime(CLOCK_MONOTONIC, &vdpy.last_time); vdpy.ui_timer.clockid = CLOCK_MONOTONIC; acrn_timer_init(&vdpy.ui_timer, vdpy_sdl_ui_timer, &vdpy); ui_timer_spec.it_interval.tv_sec = 0; @@ -1020,34 +1095,40 @@ vdpy_sdl_display_thread(void *data) /* SDL display_thread will exit because of DM request */ pthread_mutex_destroy(&vdpy.vdisplay_mutex); pthread_cond_destroy(&vdpy.vdisplay_signal); - if (vdpy.dpy_img) { - pixman_image_unref(vdpy.dpy_img); - vdpy.dpy_img = NULL; - } - /* Continue to thread cleanup */ - if (vdpy.dpy_texture) { - SDL_DestroyTexture(vdpy.dpy_texture); - vdpy.dpy_texture = NULL; - } - if (vdpy.cursor_tex) { - SDL_DestroyTexture(vdpy.cursor_tex); - vdpy.cursor_tex = NULL; - } - - if (vdpy.egl_dmabuf_supported && (vdpy.cur_egl_img != EGL_NO_IMAGE_KHR)) - vdpy.gl_ops.eglDestroyImageKHR(vdpy.eglDisplay, - vdpy.cur_egl_img); + for (i = 0; i < vdpy.vscrs_num; i++) { + vscr = vdpy.vscrs + i; + if (vscr->img) { + pixman_image_unref(vscr->img); + vscr->img = NULL; + } + /* Continue to thread cleanup */ -sdl_fail: + if (vscr->surf_tex) { + SDL_DestroyTexture(vscr->surf_tex); + vscr->surf_tex = NULL; + } + if (vscr->cur_tex) { + SDL_DestroyTexture(vscr->cur_tex); + vscr->cur_tex = NULL; + } - if (vdpy.dpy_renderer) { - SDL_DestroyRenderer(vdpy.dpy_renderer); - vdpy.dpy_renderer = NULL; + if (vdpy.egl_dmabuf_supported && (vscr->egl_img != EGL_NO_IMAGE_KHR)) + vdpy.gl_ops.eglDestroyImageKHR(vdpy.eglDisplay, + vscr->egl_img); } - if (vdpy.dpy_win) { - SDL_DestroyWindow(vdpy.dpy_win); - vdpy.dpy_win = NULL; + +sdl_fail: + for (i = 0; i < vdpy.vscrs_num; i++) { + vscr = vdpy.vscrs + i; + if (vscr->renderer) { + SDL_DestroyRenderer(vscr->renderer); + vscr->renderer = NULL; + } + if (vscr->win) { + SDL_DestroyWindow(vscr->win); + vscr->win = NULL; + } } /* This is used to workaround the TLS issue of libEGL + libGLdispatch @@ -1114,7 +1195,7 @@ vdpy_init(int *supported_wins) vdpy.s.n_connect++; if (supported_wins) - *supported_wins = 1; + *supported_wins = vdpy.vscrs_num; return vdpy.s.n_connect; } @@ -1148,6 +1229,8 @@ gfx_ui_init() { SDL_SysWMinfo info; int num_pscreen; + struct vscreen *vscr; + int i; setenv("SDL_VIDEO_X11_FORCE_EGL", "1", 1); setenv("SDL_OPENGL_ES_DRIVER", "1", 1); @@ -1160,21 +1243,25 @@ gfx_ui_init() } num_pscreen = SDL_GetNumVideoDisplays(); - if (vdpy.pscreen_id >= num_pscreen) { - pr_err("Monitor id %d is out of avalble range [0~%d].\n", - vdpy.pscreen_id, num_pscreen); - SDL_Quit(); - return -1; - } - SDL_GetDisplayBounds(vdpy.pscreen_id, &vdpy.pscreen_rect); + for (i = 0; i < vdpy.vscrs_num; i++) { + vscr = vdpy.vscrs + i; + if (vscr->pscreen_id >= num_pscreen) { + pr_err("Monitor id %d is out of avalble range [0~%d].\n", + vscr->pscreen_id, num_pscreen); + SDL_Quit(); + return -1; + } - if (vdpy.pscreen_rect.w < VDPY_MIN_WIDTH || - vdpy.pscreen_rect.h < VDPY_MIN_HEIGHT) { - pr_err("Too small resolutions. Please check the " - " graphics system\n"); - SDL_Quit(); - return -1; + SDL_GetDisplayBounds(vscr->pscreen_id, &vscr->pscreen_rect); + + if (vscr->pscreen_rect.w < VDPY_MIN_WIDTH || + vscr->pscreen_rect.h < VDPY_MIN_HEIGHT) { + pr_err("Too small resolutions. Please check the " + " graphics system\n"); + SDL_Quit(); + return -1; + } } SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "1"); @@ -1206,6 +1293,7 @@ gfx_ui_deinit() return; } + free(vdpy.vscrs); SDL_Quit(); pr_info("SDL_Quit\r\n"); } @@ -1214,35 +1302,41 @@ int vdpy_parse_cmd_option(const char *opts) { char *str; int snum, error; + struct vscreen *vscr; error = 0; + vdpy.vscrs = calloc(VSCREEN_MAX_NUM, sizeof(struct vscreen)); + vdpy.vscrs_num = 0; str = strcasestr(opts, "geometry="); + vscr = vdpy.vscrs + vdpy.vscrs_num; if (opts && strcasestr(opts, "geometry=fullscreen")) { - snum = sscanf(str, "geometry=fullscreen:%d", &vdpy.pscreen_id); + snum = sscanf(str, "geometry=fullscreen:%d", &vscr->pscreen_id); if (snum != 1) { - vdpy.pscreen_id = 0; + vscr->pscreen_id = 0; } - vdpy.width = VDPY_MAX_WIDTH; - vdpy.height = VDPY_MAX_HEIGHT; - vdpy.s.is_fullscreen = true; + vscr->width = VDPY_MAX_WIDTH; + vscr->height = VDPY_MAX_HEIGHT; + vscr->is_fullscreen = true; + vdpy.vscrs_num++; pr_info("virtual display: fullscreen.\n"); } else if (opts && strcasestr(opts, "geometry=")) { snum = sscanf(str, "geometry=%dx%d+%d+%d", - &vdpy.width, &vdpy.height, - &vdpy.org_x, &vdpy.org_y); + &vscr->width, &vscr->height, + &vscr->org_x, &vscr->org_y); if (snum != 4) { pr_err("incorrect geometry option. Should be" " WxH+x+y\n"); error = -1; } - vdpy.s.is_fullscreen = false; + vscr->is_fullscreen = false; + vdpy.vscrs_num++; pr_info("virtual display: windowed.\n"); } - vdpy.info.xoff = 0; - vdpy.info.yoff = 0; - vdpy.info.width = vdpy.width; - vdpy.info.height = vdpy.height; + vscr->info.xoff = 0; + vscr->info.yoff = 0; + vscr->info.width = vdpy.vscrs->width; + vscr->info.height = vdpy.vscrs->height; return error; } -- 2.25.1 |
|
[PATCH v2 2/2] dm: vdisplay: multi-vdisplay support.
Sun, Peng
From: Sun Peng <peng.p.sun@...>
Allow one VM have more than 1 virtual display for output. Till now, the max virtual display number is 2. So guest VM can use dual display for mirror and extend desktop mode. To specify multi-vdisplay, need use acrn-dm parameters like this: For fullscreen mode: virtio-gpu,geometry=fullscreen:monitor_id1,geometry=fullscreen:monitor_id2 For window mode: virtio-gpu,geometry=<width>x<height>+<x_off>+<y_off>,geometry=<width>x<height>+<x_off>+<y_off> Signed-off-by: Sun Peng <peng.p.sun@...> --- devicemodel/hw/vdisplay_sdl.c | 69 +++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/devicemodel/hw/vdisplay_sdl.c b/devicemodel/hw/vdisplay_sdl.c index e7cabb184..be5ac3a30 100644 --- a/devicemodel/hw/vdisplay_sdl.c +++ b/devicemodel/hw/vdisplay_sdl.c @@ -32,7 +32,7 @@ #define VDPY_MIN_WIDTH 640 #define VDPY_MIN_HEIGHT 480 #define transto_10bits(color) (uint16_t)(color * 1024 + 0.5) -#define VSCREEN_MAX_NUM 1 +#define VSCREEN_MAX_NUM 2 static unsigned char default_raw_argb[VDPY_DEFAULT_WIDTH * VDPY_DEFAULT_HEIGHT * 4]; @@ -1300,7 +1300,7 @@ gfx_ui_deinit() int vdpy_parse_cmd_option(const char *opts) { - char *str; + char *str, *stropts, *tmp; int snum, error; struct vscreen *vscr; @@ -1308,35 +1308,50 @@ int vdpy_parse_cmd_option(const char *opts) vdpy.vscrs = calloc(VSCREEN_MAX_NUM, sizeof(struct vscreen)); vdpy.vscrs_num = 0; - str = strcasestr(opts, "geometry="); - vscr = vdpy.vscrs + vdpy.vscrs_num; - if (opts && strcasestr(opts, "geometry=fullscreen")) { - snum = sscanf(str, "geometry=fullscreen:%d", &vscr->pscreen_id); - if (snum != 1) { + stropts = strdup(opts); + while ((str = strsep(&stropts, ",")) != NULL) { + vscr = vdpy.vscrs + vdpy.vscrs_num; + tmp = strcasestr(str, "geometry="); + if (str && strcasestr(str, "geometry=fullscreen")) { + snum = sscanf(tmp, "geometry=fullscreen:%d", &vscr->pscreen_id); + if (snum != 1) { + vscr->pscreen_id = 0; + } + vscr->width = VDPY_MAX_WIDTH; + vscr->height = VDPY_MAX_HEIGHT; + vscr->is_fullscreen = true; + pr_info("virtual display: fullscreen on monitor %d.\n", + vscr->pscreen_id); + vscr->info.xoff = vscr->org_x; + vscr->info.yoff = vscr->org_y; + vscr->info.width = vscr->width; + vscr->info.height = vscr->height; + vdpy.vscrs_num++; + } else if (str && strcasestr(str, "geometry=")) { + snum = sscanf(tmp, "geometry=%dx%d+%d+%d", + &vscr->width, &vscr->height, + &vscr->org_x, &vscr->org_y); + if (snum != 4) { + pr_err("incorrect geometry option. Should be" + " WxH+x+y\n"); + error = -1; + } + vscr->is_fullscreen = false; vscr->pscreen_id = 0; + pr_info("virtual display: windowed on monitor %d.\n", + vscr->pscreen_id); + vscr->info.xoff = vscr->org_x; + vscr->info.yoff = vscr->org_y; + vscr->info.width = vscr->width; + vscr->info.height = vscr->height; + vdpy.vscrs_num++; } - vscr->width = VDPY_MAX_WIDTH; - vscr->height = VDPY_MAX_HEIGHT; - vscr->is_fullscreen = true; - vdpy.vscrs_num++; - pr_info("virtual display: fullscreen.\n"); - } else if (opts && strcasestr(opts, "geometry=")) { - snum = sscanf(str, "geometry=%dx%d+%d+%d", - &vscr->width, &vscr->height, - &vscr->org_x, &vscr->org_y); - if (snum != 4) { - pr_err("incorrect geometry option. Should be" - " WxH+x+y\n"); - error = -1; + if (vdpy.vscrs_num > VSCREEN_MAX_NUM) { + pr_err("%d virtual displays are too many that acrn-dm can't support!\n"); + break; } - vscr->is_fullscreen = false; - vdpy.vscrs_num++; - pr_info("virtual display: windowed.\n"); } + free(stropts); - vscr->info.xoff = 0; - vscr->info.yoff = 0; - vscr->info.width = vdpy.vscrs->width; - vscr->info.height = vdpy.vscrs->height; return error; } -- 2.25.1 |
|
[PATCH v2 2/2] dm: vdisplay: Add physical monitor id check.
Sun, Peng
From: Sun Peng <peng.p.sun@...>
vdisplay use physical monitor id(pscreen index) to locate the monitor. The max index value always is the physical monitor number - 1. For example, there are 4 physical monitors connected. The monitor id should be 0, 1, 2 and 3. We need check monitor id that user inputs and make sure it is in a correct range. Signed-off-by: Sun Peng <peng.p.sun@...> --- devicemodel/hw/vdisplay_sdl.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/devicemodel/hw/vdisplay_sdl.c b/devicemodel/hw/vdisplay_sdl.c index 568892e7b..4b0ec69e5 100644 --- a/devicemodel/hw/vdisplay_sdl.c +++ b/devicemodel/hw/vdisplay_sdl.c @@ -1147,6 +1147,7 @@ int gfx_ui_init() { SDL_SysWMinfo info; + int num_pscreen; setenv("SDL_VIDEO_X11_FORCE_EGL", "1", 1); setenv("SDL_OPENGL_ES_DRIVER", "1", 1); @@ -1158,6 +1159,14 @@ gfx_ui_init() return -1; } + num_pscreen = SDL_GetNumVideoDisplays(); + if (vdpy.pscreen_id >= num_pscreen) { + pr_err("Monitor id %d is out of avalble range [0~%d].\n", + vdpy.pscreen_id, num_pscreen); + SDL_Quit(); + return -1; + } + SDL_GetDisplayBounds(vdpy.pscreen_id, &vdpy.pscreen_rect); if (vdpy.pscreen_rect.w < VDPY_MIN_WIDTH || -- 2.25.1 |
|
[PATCH v2 1/2] dm: vdisplay: multi-local-mornitor support.
Sun, Peng
From: Sun Peng <peng.p.sun@...>
To support full screen mode on one of multi-local-mornitor which connected to SOS by monitor ID that customer specify. The monitor ID is specified in acrn-dm's parameter like this: virtio-gpu,geometry=fullscreen:monitor_id For window mode, the vdisplay window always be shown on monitor 0, because the customer can drag the window to anyone monitor. Besides, the customer can set the monitor by x_off and y_off parameter like this: virtio-gpu,geometry=<width>x<height>+<x_off>+<y_off> Signed-off-by: Sun Peng <peng.p.sun@...> --- devicemodel/hw/vdisplay_sdl.c | 44 ++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/devicemodel/hw/vdisplay_sdl.c b/devicemodel/hw/vdisplay_sdl.c index 65fd78d93..568892e7b 100644 --- a/devicemodel/hw/vdisplay_sdl.c +++ b/devicemodel/hw/vdisplay_sdl.c @@ -52,6 +52,8 @@ struct egl_display_ops { }; static struct display { + int pscreen_id; + SDL_Rect pscreen_rect; struct display_info info; struct state s; SDL_Texture *dpy_texture; @@ -62,7 +64,6 @@ static struct display { int width, height; // Width/height of dpy_win int org_x, org_y; int guest_width, guest_height; - int screen; struct surface surf; struct cursor cur; SDL_Texture *cursor_tex; @@ -908,17 +909,23 @@ vdpy_sdl_display_thread(void *data) uint32_t win_flags; struct vdpy_display_bh *bh; struct itimerspec ui_timer_spec; + int max_width, max_height; + int min_width, min_height; + max_width = MIN(vdpy.pscreen_rect.w, VDPY_MAX_WIDTH); + max_height = MIN(vdpy.pscreen_rect.h, VDPY_MAX_HEIGHT); + min_width = MAX(vdpy.pscreen_rect.w, VDPY_MIN_WIDTH); + min_height = MAX(vdpy.pscreen_rect.h, VDPY_MIN_HEIGHT); if (vdpy.width && vdpy.height) { /* clip the region between (640x480) and (1920x1080) */ - if (vdpy.width < VDPY_MIN_WIDTH) - vdpy.width = VDPY_MIN_WIDTH; - if (vdpy.width > VDPY_MAX_WIDTH) - vdpy.width = VDPY_MAX_WIDTH; - if (vdpy.height < VDPY_MIN_HEIGHT) - vdpy.height = VDPY_MIN_HEIGHT; - if (vdpy.height > VDPY_MAX_HEIGHT) - vdpy.height = VDPY_MAX_HEIGHT; + if (vdpy.width < min_width) + vdpy.width = min_width; + if (vdpy.width > max_width) + vdpy.width = max_width; + if (vdpy.height < min_height) + vdpy.height = min_height; + if (vdpy.height > max_height) + vdpy.height = max_height; } else { /* the default window(1280x720) is created with undefined pos * when no geometry info is passed @@ -933,11 +940,14 @@ vdpy_sdl_display_thread(void *data) SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_SHOWN; if (vdpy.s.is_fullscreen) { - win_flags |= SDL_WINDOW_FULLSCREEN; + win_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; } vdpy.dpy_win = NULL; vdpy.dpy_renderer = NULL; vdpy.dpy_img = NULL; + vdpy.org_x = vdpy.pscreen_rect.x; + vdpy.org_y = vdpy.pscreen_rect.y; + // Zoom to width and height of pscreen is fullscreen enabled vdpy.dpy_win = SDL_CreateWindow("ACRN_DM", vdpy.org_x, vdpy.org_y, vdpy.width, vdpy.height, @@ -946,6 +956,9 @@ vdpy_sdl_display_thread(void *data) pr_err("Failed to Create SDL_Window\n"); goto sdl_fail; } + pr_info("SDL display bind to screen %d: [%d,%d,%d,%d].\n", vdpy.pscreen_id, + vdpy.org_x, vdpy.org_y, vdpy.width, vdpy.height); + vdpy.dpy_renderer = SDL_CreateRenderer(vdpy.dpy_win, -1, 0); if (vdpy.dpy_renderer == NULL) { pr_err("Failed to Create GL_Renderer \n"); @@ -1134,7 +1147,6 @@ int gfx_ui_init() { SDL_SysWMinfo info; - SDL_Rect disp_rect; setenv("SDL_VIDEO_X11_FORCE_EGL", "1", 1); setenv("SDL_OPENGL_ES_DRIVER", "1", 1); @@ -1146,10 +1158,10 @@ gfx_ui_init() return -1; } - SDL_GetDisplayBounds(0, &disp_rect); + SDL_GetDisplayBounds(vdpy.pscreen_id, &vdpy.pscreen_rect); - if (disp_rect.w < VDPY_MIN_WIDTH || - disp_rect.h < VDPY_MIN_HEIGHT) { + if (vdpy.pscreen_rect.w < VDPY_MIN_WIDTH || + vdpy.pscreen_rect.h < VDPY_MIN_HEIGHT) { pr_err("Too small resolutions. Please check the " " graphics system\n"); SDL_Quit(); @@ -1198,9 +1210,9 @@ int vdpy_parse_cmd_option(const char *opts) str = strcasestr(opts, "geometry="); if (opts && strcasestr(opts, "geometry=fullscreen")) { - snum = sscanf(str, "geometry=fullscreen:%d", &vdpy.screen); + snum = sscanf(str, "geometry=fullscreen:%d", &vdpy.pscreen_id); if (snum != 1) { - vdpy.screen = 0; + vdpy.pscreen_id = 0; } vdpy.width = VDPY_MAX_WIDTH; vdpy.height = VDPY_MAX_HEIGHT; -- 2.25.1 |
|
Re: [PATCH v2] config_tool-Instruction-missing-for-L2-only-users
Junjie Mao
"Junjie Mao" <junjie.mao@...> writes:
Chuang Ke <chuangx.ke@...> writes:Fine with me then.v1-->v2:From the code changes it seems you want to show the instruction once for Reviewed-by: Junjie Mao <junjie.mao@...> |
|
Re: [PATCH v1 1/3] dm: vdisplay: multi-local-mornitor support.
Sun, Peng
On Tue, 2022-08-09 at 13:59 +0800, Zhao, Yakui wrote:
[Sun, Peng] - SDL_WINDOW_FULLSCREEN, for "real" fullscreen with a videomode change - SDL_WINDOW_FULLSCREEN_DESKTOP for "fake" fullscreen that takes the size of the desktop We should not chage the video mode because this behavior will impect other VM and get some bad sideffect. --vdpy.dpy_win = NULL; Sun Peng <peng.p.sun@...> SSE/ACRN Upstream |
|
Re: [PATCH v2] config_tool-Instruction-missing-for-L2-only-users
Chuang Ke
Yes, exactly my intention
toggle quoted message
Show quoted text
Best Regards, Chuang Ke -----Original Message-----
From: Mao, Junjie <junjie.mao@...> Sent: 2022年8月9日 23:22 To: Ke, ChuangX <chuangx.ke@...> Cc: acrn-dev@...; Xie, Nanlin <nanlin.xie@...> Subject: Re: [PATCH v2] config_tool-Instruction-missing-for-L2-only-users Chuang Ke <chuangx.ke@...> writes: v1-->v2:From the code changes it seems you want to show the instruction once for L2 (if there is any L2 cache supporting CAT) AND once for L3 (if there is any L3 cache supporting CAT). In other words, you'll show the instruction twice if both L2 and L3 supports CAT. Is that the intended? -- Best Regards Junjie Mao Signed-off-by: Chuang-Ke <chuangx.ke@...> |
|
Re: [PATCH v2] config_tool-Instruction-missing-for-L2-only-users
Junjie Mao
Chuang Ke <chuangx.ke@...> writes:
v1-->v2:From the code changes it seems you want to show the instruction once for L2 (if there is any L2 cache supporting CAT) AND once for L3 (if there is any L3 cache supporting CAT). In other words, you'll show the instruction twice if both L2 and L3 supports CAT. Is that the intended? -- Best Regards Junjie Mao Signed-off-by: Chuang-Ke <chuangx.ke@...> |
|
Re: [PATCH v1 1/3] dm: vdisplay: multi-local-mornitor support.
Zhao, Yakui
On 2022/8/8 13:36, peng.p.sun@... wrote:
From: Sun Peng <peng.p.sun@...>What is the difference about the FULLSCREEN/FULLSCREEN_DESKTOP? Is it really required? vdpy.dpy_win = NULL; |
|
Re: [PATCH v1 1/3] dm: vdisplay: multi-local-mornitor support.
Zhao, Yakui
On 2022/8/8 13:36, peng.p.sun@... wrote:
From: Sun Peng <peng.p.sun@...>It seems that this patch mainly handles the issue of multi monitors. It will be better that this is submitted as the separate patch set. virtio-gpu,geometry=fullscreen:monitor_idThe vdpy.width/height is clipped if the region of phys monitor is 3840x2160. Can we add different definitions to describe the width/height for guest? @@ -946,6 +955,9 @@ vdpy_sdl_display_thread(void *data)It will be better to add another patch that will check whether the input pscreen_id is valid. vdpy.width = VDPY_MAX_WIDTH; |
|
Re: [PATCH] dm: bugfix for iothread
Conghui Chen
toggle quoted message
Show quoted text
-----Original Message-----Thanks for your comment, will change the commit message. Regards, Conghui.
|
|
Re: [PATCH] dm: bugfix for iothread
Zhao, Yakui
On 2022/8/9 12:29, Conghui Chen wrote:
As the type of pthread_t is unsigned long, so the init value for itIt will be better to describe the issue. For example: if the tid is -1, it will continue to call pthread_kill/pthread_join. This is incorrect. LGTM except minor commit log. Add: Reviewed-by: Zhao Yakui <yakui.zhao@...> Signed-off-by: Conghui <conghui.chen@...> |
|
[PATCH] dm: bugfix for iothread
Conghui Chen
As the type of pthread_t is unsigned long, so the init value for it
should not be '-1', change it to 0. Signed-off-by: Conghui <conghui.chen@...> --- devicemodel/core/iothread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devicemodel/core/iothread.c b/devicemodel/core/iothread.c index 0f56ea60d..238ecb375 100644 --- a/devicemodel/core/iothread.c +++ b/devicemodel/core/iothread.c @@ -145,7 +145,7 @@ iothread_init(void) pthread_mutex_init(&ioctx.mtx, &attr); pthread_mutexattr_destroy(&attr); - ioctx.tid = -1; + ioctx.tid = 0; ioctx.started = false; ioctx.epfd = epoll_create1(0); -- 2.25.1 |
|
Re: [PATCH v1 3/3] dm: vdisplay: multi-vdisplay support.
Sun, Peng
On Mon, 2022-08-08 at 16:52 +0800, Zhao, Yakui wrote:
[Sun, Peng] vscr_id will be printed in next version. -- Sun Peng <peng.p.sun@...> SSE/ACRN Upstream |
|
Re: [PATCH v1 2/3] dm: vdisplay: refine vdisplay core concept abstractions
Sun, Peng
On Mon, 2022-08-08 at 16:42 +0800, Zhao, Yakui wrote:
[Sun, Peng] Will remove this check in next version. [Sun, Peng] These changes are for one vscreen data struct, not for+Can this split into another patch? multi-vscreen parse. 3/3 patch is for to parse 2 vscreen. --error = 0; Sun Peng <peng.p.sun@...> SSE/ACRN Upstream |
|