Re: [PATCH v14 00/14] Support blob memory and venus on qemu
On 6/21/24 11:59, Alex Bennée wrote: > Dmitry Osipenko writes: > >> On 6/19/24 20:37, Alex Bennée wrote: >>> So I've been experimenting with Aarch64 TCG with an Intel backend like >>> this: >>> >>> ./qemu-system-aarch64 \ >>>-M virt -cpu cortex-a76 \ >>>-device virtio-net-pci,netdev=unet \ >>>-netdev user,id=unet,hostfwd=tcp::-:22 \ >>>-m 8192 \ >>>-object memory-backend-memfd,id=mem,size=8G,share=on \ >>>-serial mon:stdio \ >>>-kernel >>> ~/lsrc/linux.git/builds/arm64.initramfs/arch/arm64/boot/Image \ >>>-append "console=ttyAMA0" \ >>>-device qemu-xhci -device usb-kbd -device usb-tablet \ >>>-device virtio-gpu-gl-pci,blob=true,venus=true,hostmem=4G \ >>>-display sdl,gl=on -d >>> plugin,guest_errors,trace:virtio_gpu_cmd_res_create_blob,trace:virtio_gpu_cmd_res_back_\*,trace:virtio_gpu_cmd_res_xfer_toh_3d,trace:virtio_gpu_cmd_res_xfer_fromh_3d,trace:address_space_map >>> >>> >>> And I've noticed a couple of things. First trying to launch vkmark to >>> run a KMS mode test fails with: >>> >> ... >>> virgl_render_server[1875931]: vkr: failed to import resource: invalid >>> res_id 5 >>> virgl_render_server[1875931]: vkr: vkAllocateMemory resulted in CS error >>> virgl_render_server[1875931]: vkr: ring_submit_cmd: vn_dispatch_command >>> failed >>> >>> More interestingly when shutting stuff down we see weirdness like: >>> >>> address_space_map as:0x561b48ec48c0 addr 0x1008ac4b0:18 write:1 attrs:0x1 >>> >>> >>> virgl_render_server[1875931]: vkr: destroying context 3 (vkmark) with a >>> valid instance >>> >>> virgl_render_server[1875931]: vkr: destroying device with valid objects >>> >>> >>> vkr_context_remove_object: -7438602987017907480 >>> >>> >>> vkr_context_remove_object: 7 >>> >>> >>> vkr_context_remove_object: 5 >>> >>> which indicates something has gone very wrong. I'm not super familiar >>> with the memory allocation patterns but should stuff that is done as >>> virtio_gpu_cmd_res_back_attach() be find-able in the list of resources? >> >> This is expected to fail. Vkmark creates shmem virgl GBM FB BO on guest >> that isn't exportable on host. AFAICT, more code changes should be >> needed to support this case. > > There are a lot of acronyms there. If this is pure guest memory why > isn't it exportable to the host? Or should the underlying mesa library > be making sure the allocation happens from the shared region? > > Is vkmark particularly special here? Actually, you could get it to work to a some degree if you'll compile virglrenderer with -Dminigbm_allocation=true. On host use GTK/Wayland display. Vkmark isn't special. It's virglrenderer that has a room for improvement. ChromeOS doesn't use KMS in VMs, proper KMS support was never a priority for Venus. >> Note that "destroying device with valid objects" msg is fine, won't hurt >> to silence it in Venus to avoid confusion. It will happen every time >> guest application is closed without explicitly releasing every VK >> object. > > I was more concerned with: > >>> vkr_context_remove_object: -7438602987017907480 >>> >>> > > which looks like a corruption of the object ids (or maybe an offby one) At first this appeared to be a valid value, otherwise venus should've crashed Qemu with a debug-assert if ID was invalid. But I never see such odd IDs with my testing. >>> I tried running under RR to further debug but weirdly I can't get >>> working graphics with that. I did try running under threadsan which >>> complained about a potential data race: >>> >>> vkr_context
Re: [PATCH v14 00/14] Support blob memory and venus on qemu
On 6/19/24 20:37, Alex Bennée wrote: > So I've been experimenting with Aarch64 TCG with an Intel backend like > this: > > ./qemu-system-aarch64 \ >-M virt -cpu cortex-a76 \ >-device virtio-net-pci,netdev=unet \ >-netdev user,id=unet,hostfwd=tcp::-:22 \ >-m 8192 \ >-object memory-backend-memfd,id=mem,size=8G,share=on \ >-serial mon:stdio \ >-kernel > ~/lsrc/linux.git/builds/arm64.initramfs/arch/arm64/boot/Image \ >-append "console=ttyAMA0" \ >-device qemu-xhci -device usb-kbd -device usb-tablet \ >-device virtio-gpu-gl-pci,blob=true,venus=true,hostmem=4G \ >-display sdl,gl=on -d > plugin,guest_errors,trace:virtio_gpu_cmd_res_create_blob,trace:virtio_gpu_cmd_res_back_\*,trace:virtio_gpu_cmd_res_xfer_toh_3d,trace:virtio_gpu_cmd_res_xfer_fromh_3d,trace:address_space_map > > > And I've noticed a couple of things. First trying to launch vkmark to > run a KMS mode test fails with: > ... > virgl_render_server[1875931]: vkr: failed to import resource: invalid > res_id 5 > virgl_render_server[1875931]: vkr: vkAllocateMemory resulted in CS error > virgl_render_server[1875931]: vkr: ring_submit_cmd: vn_dispatch_command > failed > > More interestingly when shutting stuff down we see weirdness like: > > address_space_map as:0x561b48ec48c0 addr 0x1008ac4b0:18 write:1 attrs:0x1 > > > virgl_render_server[1875931]: vkr: destroying context 3 (vkmark) with a > valid instance > > virgl_render_server[1875931]: vkr: destroying device with valid objects > > > vkr_context_remove_object: -7438602987017907480 > > > vkr_context_remove_object: 7 > > > vkr_context_remove_object: 5 > > which indicates something has gone very wrong. I'm not super familiar > with the memory allocation patterns but should stuff that is done as > virtio_gpu_cmd_res_back_attach() be find-able in the list of resources? This is expected to fail. Vkmark creates shmem virgl GBM FB BO on guest that isn't exportable on host. AFAICT, more code changes should be needed to support this case. Note that "destroying device with valid objects" msg is fine, won't hurt to silence it in Venus to avoid confusion. It will happen every time guest application is closed without explicitly releasing every VK object. > I tried running under RR to further debug but weirdly I can't get > working graphics with that. I did try running under threadsan which > complained about a potential data race: > > vkr_context_add_object: 1 -> 0x7b2c0288 > vkr_context_add_object: 2 -> 0x7b2c0270 > vkr_context_add_object: 3 -> 0x7b387f28 > vkr_context_add_object: 4 -> 0x7b387fa0 > vkr_context_add_object: 5 -> 0x7b48000103f8 > vkr_context_add_object: 6 -> 0x7b48000104a0 > vkr_context_add_object: 7 -> 0x7b4800010440 > virtio_gpu_cmd_res_back_attach res 0x5 > virtio_gpu_cmd_res_back_attach res 0x6 > vkr_context_add_object: 8 -> 0x7b48000103e0 > virgl_render_server[1751430]: vkr: failed to import resource: invalid > res_id 5 > virgl_render_server[1751430]: vkr: vkAllocateMemory resulted in CS error > virgl_render_server[1751430]: vkr: ring_submit_cmd: vn_dispatch_command > failed > == > WARNING: ThreadSanitizer: data race (pid=1751256) > Read of size 8 at 0x7f7fa0ea9138 by main thread (mutexes: write M0): > #0 memcpy (qemu-system-aarch64+0x41fede) (BuildId: > 0bab171e77cb6782341ee3407e44af7267974025) .. > == > SUMMARY: ThreadSanitizer: data race > (/home/alex/lsrc/qemu.git/builds/system.threadsan/qemu-system-aarch64+0x41fede) > (BuildId: 0bab171e77cb6782341ee3407e44af7267974025) in __interceptor_memcpy > > This could be a false positive or it could be a race between the guest > kernel clearing memory while we are still doing > virtio_gpu_ctrl_response. > > What do you think? The memcpy warning looks a bit suspicion, but likely is harmless. I don't see such warning with TSAN and x86 VM. -- Best regards, Dmitry
Re: [PATCH v14 12/14] virtio-gpu: Handle resource blob commands
16.06.2024 12:23, Akihiko Odaki пишет: ... >> #endif >> +#if VIRGL_VERSION_MAJOR >= 1 >> +typedef enum { >> + HOSTMEM_MR_MAPPED, > > HOSTMEM_MR_MAPPED is no longer used. Good catch -- Best regards, Dmitry
Re: [PATCH v14 12/14] virtio-gpu: Handle resource blob commands
19.06.2024 18:27, Alex Bennée пишет: > Dmitry Osipenko writes: > >> From: Antonio Caggiano >> >> Support BLOB resources creation, mapping and unmapping by calling the >> new stable virglrenderer 0.10 interface. Only enabled when available and >> via the blob config. E.g. -device virtio-vga-gl,blob=true >> > >> >> #if VIRGL_VERSION_MAJOR >= 1 >> +static void virgl_cmd_resource_create_blob(VirtIOGPU *g, >> + struct virtio_gpu_ctrl_command >> *cmd) >> +{ >> +struct virgl_renderer_resource_create_blob_args virgl_args = { 0 }; >> +g_autofree struct virtio_gpu_virgl_resource *res; > > Newer compilers rightly complain that g_free may be called on an > uninitialised value (if we early return). Setting to NULL should be > enough here. Good catch! GCC 13 doesn't detect it -- Best regards, Dmitry
[PATCH v14 01/14] virtio-gpu: Use trace events for tracking number of in-flight fences
Replace printf's used for tracking of in-flight fence inc/dec events with tracing, for consistency with the rest of virtio-gpu code that uses tracing. Suggested-by: Marc-André Lureau Signed-off-by: Dmitry Osipenko --- hw/display/trace-events | 2 ++ hw/display/virtio-gpu-virgl.c | 2 +- hw/display/virtio-gpu.c | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/display/trace-events b/hw/display/trace-events index 781f8a33203b..e212710284ae 100644 --- a/hw/display/trace-events +++ b/hw/display/trace-events @@ -53,6 +53,8 @@ virtio_gpu_cmd_ctx_submit(uint32_t ctx, uint32_t size) "ctx 0x%x, size %d" virtio_gpu_update_cursor(uint32_t scanout, uint32_t x, uint32_t y, const char *type, uint32_t res) "scanout %d, x %d, y %d, %s, res 0x%x" virtio_gpu_fence_ctrl(uint64_t fence, uint32_t type) "fence 0x%" PRIx64 ", type 0x%x" virtio_gpu_fence_resp(uint64_t fence) "fence 0x%" PRIx64 +virtio_gpu_inc_inflight_fences(uint32_t inflight) "in-flight+ %u" +virtio_gpu_dec_inflight_fences(uint32_t inflight) "in-flight- %u" # qxl.c disable qxl_io_write_vga(int qid, const char *mode, uint32_t addr, uint32_t val) "%d %s addr=%u val=%u" diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 9f34d0e6619c..14091b191ec0 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -525,7 +525,7 @@ static void virgl_write_fence(void *opaque, uint32_t fence) g_free(cmd); g->inflight--; if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { -fprintf(stderr, "inflight: %3d (-)\r", g->inflight); +trace_virtio_gpu_dec_inflight_fences(g->inflight); } } } diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index d60b1b2973af..602952a7041b 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1066,7 +1066,7 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) if (g->stats.max_inflight < g->inflight) { g->stats.max_inflight = g->inflight; } -fprintf(stderr, "inflight: %3d (+)\r", g->inflight); +trace_virtio_gpu_inc_inflight_fences(g->inflight); } } else { g_free(cmd); @@ -1086,7 +1086,7 @@ static void virtio_gpu_process_fenceq(VirtIOGPU *g) g_free(cmd); g->inflight--; if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { -fprintf(stderr, "inflight: %3d (-)\r", g->inflight); +trace_virtio_gpu_dec_inflight_fences(g->inflight); } } } -- 2.44.0
[PATCH v14 08/14] virtio-gpu: Don't require udmabuf when blobs and virgl are enabled
The udmabuf usage is mandatory when virgl is disabled and blobs feature enabled in the Qemu machine configuration. If virgl and blobs are enabled, then udmabuf requirement is optional. Since udmabuf isn't widely supported by a popular Linux distros today, let's relax the udmabuf requirement for blobs=on,virgl=on. Now, a full-featured virtio-gpu acceleration is available to Qemu users without a need to have udmabuf available in the system. Reviewed-by: Antonio Caggiano Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Reviewed-by: Marc-André Lureau Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 602952a7041b..40a9d089710c 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1485,6 +1485,7 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) if (virtio_gpu_blob_enabled(g->parent_obj.conf)) { if (!virtio_gpu_rutabaga_enabled(g->parent_obj.conf) && +!virtio_gpu_virgl_enabled(g->parent_obj.conf) && !virtio_gpu_have_udmabuf()) { error_setg(errp, "need rutabaga or udmabuf for blob resources"); return; -- 2.44.0
[PATCH v14 13/14] virtio-gpu: Register capsets dynamically
From: Pierre-Eric Pelloux-Prayer virtio_gpu_virgl_get_num_capsets will return "num_capsets", but we can't assume that capset_index 1 is always VIRGL2 once we'll support more capsets, like Venus and DRM capsets. Register capsets dynamically to avoid that problem. Reviewed-by: Manos Pitsidianakis Signed-off-by: Pierre-Eric Pelloux-Prayer Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 6 -- hw/display/virtio-gpu-virgl.c | 33 + include/hw/virtio/virtio-gpu.h | 4 +++- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 5f27568d3ec8..20a7c316bb23 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -138,8 +138,8 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) } g->parent_obj.conf.flags |= (1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED); -VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = -virtio_gpu_virgl_get_num_capsets(g); +g->capset_ids = virtio_gpu_virgl_get_capsets(g); +VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = g->capset_ids->len; #if VIRGL_VERSION_MAJOR >= 1 g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED; @@ -171,6 +171,8 @@ static void virtio_gpu_gl_device_unrealize(DeviceState *qdev) } gl->renderer_state = RS_START; + +g_array_unref(g->capset_ids); } static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index fed3e27b2fc9..8f3920800517 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -630,19 +630,13 @@ static void virgl_cmd_get_capset_info(VirtIOGPU *g, VIRTIO_GPU_FILL_CMD(info); memset(, 0, sizeof(resp)); -if (info.capset_index == 0) { -resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL; -virgl_renderer_get_cap_set(resp.capset_id, - _max_version, - _max_size); -} else if (info.capset_index == 1) { -resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL2; + +if (info.capset_index < g->capset_ids->len) { +resp.capset_id = g_array_index(g->capset_ids, uint32_t, + info.capset_index); virgl_renderer_get_cap_set(resp.capset_id, _max_version, _max_size); -} else { -resp.capset_max_version = 0; -resp.capset_max_size = 0; } resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO; virtio_gpu_ctrl_response(g, cmd, , sizeof(resp)); @@ -1164,12 +1158,27 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) return 0; } -int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g) +static void virtio_gpu_virgl_add_capset(GArray *capset_ids, uint32_t capset_id) +{ +g_array_append_val(capset_ids, capset_id); +} + +GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g) { uint32_t capset2_max_ver, capset2_max_size; +GArray *capset_ids; + +capset_ids = g_array_new(false, false, sizeof(uint32_t)); + +/* VIRGL is always supported. */ +virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL); + virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VIRGL2, _max_ver, _max_size); +if (capset2_max_ver) { +virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL2); +} -return capset2_max_ver ? 2 : 1; +return capset_ids; } diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 775005abb337..83232f4b4bfa 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -209,6 +209,8 @@ struct VirtIOGPU { QTAILQ_HEAD(, VGPUDMABuf) bufs; VGPUDMABuf *primary[VIRTIO_GPU_MAX_SCANOUTS]; } dmabuf; + +GArray *capset_ids; }; struct VirtIOGPUClass { @@ -354,6 +356,6 @@ void virtio_gpu_virgl_fence_poll(VirtIOGPU *g); void virtio_gpu_virgl_reset_scanout(VirtIOGPU *g); void virtio_gpu_virgl_reset(VirtIOGPU *g); int virtio_gpu_virgl_init(VirtIOGPU *g); -int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g); +GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g); #endif -- 2.44.0
[PATCH v14 07/14] virtio-gpu: Support context-init feature with virglrenderer
From: Huang Rui Patch "virtio-gpu: CONTEXT_INIT feature" has added the context_init feature flags. Expose this feature and support creating virglrenderer context with flags using context_id if libvirglrenderer is new enough. Originally-by: Antonio Caggiano Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c| 4 hw/display/virtio-gpu-virgl.c | 20 ++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 0109244276fc..4fe9e6a0c21c 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -141,6 +141,10 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = virtio_gpu_virgl_get_num_capsets(g); +#if VIRGL_VERSION_MAJOR >= 1 +g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED; +#endif + virtio_gpu_device_realize(qdev, errp); } diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index ca6f4d6cbb58..b3aa444bcfa5 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -106,8 +106,24 @@ static void virgl_cmd_context_create(VirtIOGPU *g, trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id, cc.debug_name); -virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen, - cc.debug_name); +if (cc.context_init) { +if (!virtio_gpu_context_init_enabled(g->parent_obj.conf)) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: context_init disabled", + __func__); +cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; +return; +} + +#if VIRGL_VERSION_MAJOR >= 1 +virgl_renderer_context_create_with_flags(cc.hdr.ctx_id, + cc.context_init, + cc.nlen, + cc.debug_name); +return; +#endif +} + +virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen, cc.debug_name); } static void virgl_cmd_context_destroy(VirtIOGPU *g, -- 2.44.0
[PATCH v14 04/14] virtio-gpu: Handle virtio_gpu_virgl_init() failure
virtio_gpu_virgl_init() may fail, leading to a further Qemu crash because Qemu assumes it never fails. Check virtio_gpu_virgl_init() return code and don't execute virtio commands on error. Failed virtio_gpu_virgl_init() will result in a timed out virtio commands for a guest OS. Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 30 ++ include/hw/virtio/virtio-gpu.h | 11 +-- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index e06be60dfbfc..21a1e9a05c5d 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -29,9 +29,14 @@ static void virtio_gpu_gl_update_cursor_data(VirtIOGPU *g, struct virtio_gpu_scanout *s, uint32_t resource_id) { +VirtIOGPUGL *gl = VIRTIO_GPU_GL(g); uint32_t width, height; uint32_t pixels, *data; +if (gl->renderer_state != RS_INITED) { +return; +} + data = virgl_renderer_get_cursor_data(resource_id, , ); if (!data) { return; @@ -65,13 +70,22 @@ static void virtio_gpu_gl_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) return; } -if (!gl->renderer_inited) { -virtio_gpu_virgl_init(g); -gl->renderer_inited = true; -} -if (gl->renderer_reset) { -gl->renderer_reset = false; +switch (gl->renderer_state) { +case RS_RESET: virtio_gpu_virgl_reset(g); +/* fallthrough */ +case RS_START: +if (virtio_gpu_virgl_init(g)) { +gl->renderer_state = RS_INIT_FAILED; +return; +} + +gl->renderer_state = RS_INITED; +break; +case RS_INIT_FAILED: +return; +case RS_INITED: +break; } cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); @@ -98,9 +112,9 @@ static void virtio_gpu_gl_reset(VirtIODevice *vdev) * GL functions must be called with the associated GL context in main * thread, and when the renderer is unblocked. */ -if (gl->renderer_inited && !gl->renderer_reset) { +if (gl->renderer_state == RS_INITED) { virtio_gpu_virgl_reset_scanout(g); -gl->renderer_reset = true; +gl->renderer_state = RS_RESET; } } diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 7ff989a45a5c..6e71d799e5da 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -224,11 +224,18 @@ struct VirtIOGPUClass { Error **errp); }; +/* VirtIOGPUGL renderer states */ +typedef enum { +RS_START, /* starting state */ +RS_INIT_FAILED, /* failed initialisation */ +RS_INITED, /* initialised and working */ +RS_RESET, /* inited and reset pending, moves to start after reset */ +} RenderState; + struct VirtIOGPUGL { struct VirtIOGPU parent_obj; -bool renderer_inited; -bool renderer_reset; +RenderState renderer_state; QEMUTimer *fence_poll; QEMUTimer *print_stats; -- 2.44.0
[PATCH v14 00/14] Support blob memory and venus on qemu
lidate owner of memory region to avoid slowing down DMA. - Use memory_region_init_ram_ptr() instead of memory_region_init_ram_device_ptr(). - Adjust sequence to allocate gpu resource before virglrender resource creation - Add virtio migration handling for uuid. - Send kernel patch to define VIRTIO_GPU_CAPSET_VENUS. https://lore.kernel.org/lkml/20230915105918.3763061-1-ray.hu...@amd.com/ - Add meson check to make sure unstable APIs defined from 0.9.0. Changes from V1 to V2 (virtio gpu V4) - Remove unused #include "hw/virtio/virtio-iommu.h" - Add a local function, called virgl_resource_destroy(), that is used to release a vgpu resource on error paths and in resource_unref. - Remove virtio_gpu_virgl_resource_unmap from virtio_gpu_cleanup_mapping(), since this function won't be called on blob resources and also because blob resources are unmapped via virgl_cmd_resource_unmap_blob(). - In virgl_cmd_resource_create_blob(), do proper cleanup in error paths and move QTAILQ_INSERT_HEAD(>reslist, res, next) after the resource has been fully initialized. - Memory region has a different life-cycle from virtio gpu resources i.e. cannot be released synchronously along with the vgpu resource. So, here the field "region" was changed to a pointer and is allocated dynamically when the blob is mapped. Also, since the pointer can be used to indicate whether the blob is mapped, the explicite field "mapped" was removed. - In virgl_cmd_resource_map_blob(), add check on the value of res->region, to prevent beeing called twice on the same resource. - Add a patch to enable automatic deallocation of memory regions to resolve use-after-free memory corruption with a reference. Antonio Caggiano (2): virtio-gpu: Handle resource blob commands virtio-gpu: Support Venus context Dmitry Osipenko (8): virtio-gpu: Use trace events for tracking number of in-flight fences virtio-gpu: Move fence_poll timer to VirtIOGPUGL virtio-gpu: Move print_stats timer to VirtIOGPUGL virtio-gpu: Handle virtio_gpu_virgl_init() failure virtio-gpu: Unrealize GL device virtio-gpu: Use pkgconfig version to decide which virgl features are available virtio-gpu: Don't require udmabuf when blobs and virgl are enabled virtio-gpu: Support suspension of commands processing Huang Rui (2): virtio-gpu: Support context-init feature with virglrenderer virtio-gpu: Add virgl resource management Pierre-Eric Pelloux-Prayer (1): virtio-gpu: Register capsets dynamically Robert Beckett (1): virtio-gpu: Support blob scanout using dmabuf fd hw/display/trace-events| 3 + hw/display/virtio-gpu-gl.c | 62 +++- hw/display/virtio-gpu-virgl.c | 589 +++-- hw/display/virtio-gpu.c| 44 ++- include/hw/virtio/virtio-gpu.h | 32 +- meson.build| 5 +- 6 files changed, 678 insertions(+), 57 deletions(-) -- 2.44.0
[PATCH v14 06/14] virtio-gpu: Use pkgconfig version to decide which virgl features are available
New virglrerenderer features were stabilized with release of v1.0.0. Presence of symbols in virglrenderer.h doesn't guarantee ABI compatibility with pre-release development versions of libvirglerender. Use virglrenderer version to decide reliably which virgl features are available. Reviewed-by: Alex Bennée Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 2 +- meson.build | 5 + 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index a63d1f540f04..ca6f4d6cbb58 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -171,7 +171,7 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g, struct virgl_renderer_resource_info info; void *d3d_tex2d = NULL; -#ifdef HAVE_VIRGL_D3D_INFO_EXT +#if VIRGL_VERSION_MAJOR >= 1 struct virgl_renderer_resource_info_ext ext; memset(, 0, sizeof(ext)); ret = virgl_renderer_resource_get_info_ext(ss.resource_id, ); diff --git a/meson.build b/meson.build index 97e00d6f59b8..838d08ef0f9b 100644 --- a/meson.build +++ b/meson.build @@ -2329,10 +2329,7 @@ config_host_data.set('CONFIG_VNC', vnc.found()) config_host_data.set('CONFIG_VNC_JPEG', jpeg.found()) config_host_data.set('CONFIG_VNC_SASL', sasl.found()) if virgl.found() - config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', - cc.has_member('struct virgl_renderer_resource_info_ext', 'd3d_tex2d', - prefix: '#include ', - dependencies: virgl)) + config_host_data.set('VIRGL_VERSION_MAJOR', virgl.version().split('.')[0]) endif config_host_data.set('CONFIG_VIRTFS', have_virtfs) config_host_data.set('CONFIG_VTE', vte.found()) -- 2.44.0
[PATCH v14 14/14] virtio-gpu: Support Venus context
From: Antonio Caggiano Request Venus when initializing VirGL and if venus=true flag is set for virtio-gpu-gl device. Signed-off-by: Antonio Caggiano Signed-off-by: Huang Rui Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 2 ++ hw/display/virtio-gpu-virgl.c | 22 ++ hw/display/virtio-gpu.c| 15 +++ include/hw/virtio/virtio-gpu.h | 3 +++ 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 20a7c316bb23..9be452547322 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -151,6 +151,8 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) static Property virtio_gpu_gl_properties[] = { DEFINE_PROP_BIT("stats", VirtIOGPU, parent_obj.conf.flags, VIRTIO_GPU_FLAG_STATS_ENABLED, false), +DEFINE_PROP_BIT("venus", VirtIOGPU, parent_obj.conf.flags, +VIRTIO_GPU_FLAG_VENUS_ENABLED, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 8f3920800517..ec923cf36ef7 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -1132,6 +1132,11 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) flags |= VIRGL_RENDERER_D3D11_SHARE_TEXTURE; } #endif +#if VIRGL_VERSION_MAJOR >= 1 +if (virtio_gpu_venus_enabled(g->parent_obj.conf)) { +flags |= VIRGL_RENDERER_VENUS | VIRGL_RENDERER_RENDER_SERVER; +} +#endif ret = virgl_renderer_init(g, flags, _gpu_3d_cbs); if (ret != 0) { @@ -1165,7 +1170,7 @@ static void virtio_gpu_virgl_add_capset(GArray *capset_ids, uint32_t capset_id) GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g) { -uint32_t capset2_max_ver, capset2_max_size; +uint32_t capset_max_ver, capset_max_size; GArray *capset_ids; capset_ids = g_array_new(false, false, sizeof(uint32_t)); @@ -1174,11 +1179,20 @@ GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g) virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL); virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VIRGL2, - _max_ver, - _max_size); -if (capset2_max_ver) { + _max_ver, + _max_size); +if (capset_max_ver) { virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL2); } +if (virtio_gpu_venus_enabled(g->parent_obj.conf)) { +virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VENUS, + _max_ver, + _max_size); +if (capset_max_size) { +virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VENUS); +} +} + return capset_ids; } diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index a5db2256a4bb..50b5634af13f 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1507,6 +1507,21 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) #endif } +if (virtio_gpu_venus_enabled(g->parent_obj.conf)) { +#ifdef VIRGL_VERSION_MAJOR +#if VIRGL_VERSION_MAJOR >= 1 +if (!virtio_gpu_blob_enabled(g->parent_obj.conf) || +!virtio_gpu_hostmem_enabled(g->parent_obj.conf)) { +error_setg(errp, "venus requires enabled blob and hostmem options"); +return; +} +#else +error_setg(errp, "old virglrenderer, venus unsupported"); +return; +#endif +#endif +} + if (!virtio_gpu_base_device_realize(qdev, virtio_gpu_handle_ctrl_cb, virtio_gpu_handle_cursor_cb, diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 83232f4b4bfa..230fa0c4ee0a 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -99,6 +99,7 @@ enum virtio_gpu_base_conf_flags { VIRTIO_GPU_FLAG_BLOB_ENABLED, VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED, VIRTIO_GPU_FLAG_RUTABAGA_ENABLED, +VIRTIO_GPU_FLAG_VENUS_ENABLED, }; #define virtio_gpu_virgl_enabled(_cfg) \ @@ -117,6 +118,8 @@ enum virtio_gpu_base_conf_flags { (_cfg.flags & (1 << VIRTIO_GPU_FLAG_RUTABAGA_ENABLED)) #define virtio_gpu_hostmem_enabled(_cfg) \ (_cfg.hostmem > 0) +#define virtio_gpu_venus_enabled(_cfg) \ +(_cfg.flags & (1 << VIRTIO_GPU_FLAG_VENUS_ENABLED)) struct virtio_gpu_base_conf { uint32_t max_outputs; -- 2.44.0
[PATCH v14 02/14] virtio-gpu: Move fence_poll timer to VirtIOGPUGL
Move fence_poll timer to VirtIOGPUGL for consistency with cmdq_resume_bh that are used only by GL device. Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 8 +--- include/hw/virtio/virtio-gpu.h | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 14091b191ec0..91dce90f9176 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -594,11 +594,12 @@ static void virtio_gpu_print_stats(void *opaque) static void virtio_gpu_fence_poll(void *opaque) { VirtIOGPU *g = opaque; +VirtIOGPUGL *gl = VIRTIO_GPU_GL(g); virgl_renderer_poll(); virtio_gpu_process_cmdq(g); if (!QTAILQ_EMPTY(>cmdq) || !QTAILQ_EMPTY(>fenceq)) { -timer_mod(g->fence_poll, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 10); +timer_mod(gl->fence_poll, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 10); } } @@ -626,6 +627,7 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) { int ret; uint32_t flags = 0; +VirtIOGPUGL *gl = VIRTIO_GPU_GL(g); #if VIRGL_RENDERER_CALLBACKS_VERSION >= 4 if (qemu_egl_display) { @@ -645,8 +647,8 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) return ret; } -g->fence_poll = timer_new_ms(QEMU_CLOCK_VIRTUAL, - virtio_gpu_fence_poll, g); +gl->fence_poll = timer_new_ms(QEMU_CLOCK_VIRTUAL, + virtio_gpu_fence_poll, g); if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { g->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL, diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 7a59379f5a7a..bc69fd78a440 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -196,7 +196,6 @@ struct VirtIOGPU { uint64_t hostmem; bool processing_cmdq; -QEMUTimer *fence_poll; QEMUTimer *print_stats; uint32_t inflight; @@ -231,6 +230,8 @@ struct VirtIOGPUGL { bool renderer_inited; bool renderer_reset; + +QEMUTimer *fence_poll; }; struct VhostUserGPU { -- 2.44.0
[PATCH v14 05/14] virtio-gpu: Unrealize GL device
Even though GL GPU doesn't support hotplugging today, free virgl resources when GL device is unrealized. For consistency. Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 17 + 1 file changed, 17 insertions(+) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 21a1e9a05c5d..0109244276fc 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -150,6 +150,22 @@ static Property virtio_gpu_gl_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static void virtio_gpu_gl_device_unrealize(DeviceState *qdev) +{ +VirtIOGPU *g = VIRTIO_GPU(qdev); +VirtIOGPUGL *gl = VIRTIO_GPU_GL(qdev); + +if (gl->renderer_state >= RS_INITED) { +if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { +timer_free(gl->print_stats); +} +timer_free(gl->fence_poll); +virgl_renderer_cleanup(NULL); +} + +gl->renderer_state = RS_START; +} + static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -163,6 +179,7 @@ static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) vgc->update_cursor_data = virtio_gpu_gl_update_cursor_data; vdc->realize = virtio_gpu_gl_device_realize; +vdc->unrealize = virtio_gpu_gl_device_unrealize; vdc->reset = virtio_gpu_gl_reset; device_class_set_props(dc, virtio_gpu_gl_properties); } -- 2.44.0
[PATCH v14 03/14] virtio-gpu: Move print_stats timer to VirtIOGPUGL
Move print_stats timer to VirtIOGPUGL for consistency with cmdq_resume_bh and fence_poll that are used only by GL device. Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 10 ++ include/hw/virtio/virtio-gpu.h | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 91dce90f9176..a63d1f540f04 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -574,6 +574,7 @@ static struct virgl_renderer_callbacks virtio_gpu_3d_cbs = { static void virtio_gpu_print_stats(void *opaque) { VirtIOGPU *g = opaque; +VirtIOGPUGL *gl = VIRTIO_GPU_GL(g); if (g->stats.requests) { fprintf(stderr, "stats: vq req %4d, %3d -- 3D %4d (%5d)\n", @@ -588,7 +589,7 @@ static void virtio_gpu_print_stats(void *opaque) } else { fprintf(stderr, "stats: idle\r"); } -timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000); +timer_mod(gl->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000); } static void virtio_gpu_fence_poll(void *opaque) @@ -651,9 +652,10 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) virtio_gpu_fence_poll, g); if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { -g->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL, - virtio_gpu_print_stats, g); -timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000); +gl->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL, + virtio_gpu_print_stats, g); +timer_mod(gl->print_stats, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000); } return 0; } diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index bc69fd78a440..7ff989a45a5c 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -196,7 +196,6 @@ struct VirtIOGPU { uint64_t hostmem; bool processing_cmdq; -QEMUTimer *print_stats; uint32_t inflight; struct { @@ -232,6 +231,7 @@ struct VirtIOGPUGL { bool renderer_reset; QEMUTimer *fence_poll; +QEMUTimer *print_stats; }; struct VhostUserGPU { -- 2.44.0
[PATCH v14 09/14] virtio-gpu: Add virgl resource management
From: Huang Rui In a preparation to adding host blobs support to virtio-gpu, add virgl resource management that allows to retrieve resource based on its ID and virgl resource wrapper on top of simple resource that will be contain fields specific to virgl. Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 76 +++ 1 file changed, 76 insertions(+) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index b3aa444bcfa5..3ffea478e723 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -22,6 +22,23 @@ #include +struct virtio_gpu_virgl_resource { +struct virtio_gpu_simple_resource base; +}; + +static struct virtio_gpu_virgl_resource * +virtio_gpu_virgl_find_resource(VirtIOGPU *g, uint32_t resource_id) +{ +struct virtio_gpu_simple_resource *res; + +res = virtio_gpu_find_resource(g, resource_id); +if (!res) { +return NULL; +} + +return container_of(res, struct virtio_gpu_virgl_resource, base); +} + #if VIRGL_RENDERER_CALLBACKS_VERSION >= 4 static void * virgl_get_egl_display(G_GNUC_UNUSED void *cookie) @@ -35,11 +52,34 @@ static void virgl_cmd_create_resource_2d(VirtIOGPU *g, { struct virtio_gpu_resource_create_2d c2d; struct virgl_renderer_resource_create_args args; +struct virtio_gpu_virgl_resource *res; VIRTIO_GPU_FILL_CMD(c2d); trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format, c2d.width, c2d.height); +if (c2d.resource_id == 0) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n", + __func__); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = virtio_gpu_virgl_find_resource(g, c2d.resource_id); +if (res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n", + __func__, c2d.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = g_new0(struct virtio_gpu_virgl_resource, 1); +res->base.width = c2d.width; +res->base.height = c2d.height; +res->base.format = c2d.format; +res->base.resource_id = c2d.resource_id; +QTAILQ_INSERT_HEAD(>reslist, >base, next); + args.handle = c2d.resource_id; args.target = 2; args.format = c2d.format; @@ -59,11 +99,34 @@ static void virgl_cmd_create_resource_3d(VirtIOGPU *g, { struct virtio_gpu_resource_create_3d c3d; struct virgl_renderer_resource_create_args args; +struct virtio_gpu_virgl_resource *res; VIRTIO_GPU_FILL_CMD(c3d); trace_virtio_gpu_cmd_res_create_3d(c3d.resource_id, c3d.format, c3d.width, c3d.height, c3d.depth); +if (c3d.resource_id == 0) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n", + __func__); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = virtio_gpu_virgl_find_resource(g, c3d.resource_id); +if (res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n", + __func__, c3d.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = g_new0(struct virtio_gpu_virgl_resource, 1); +res->base.width = c3d.width; +res->base.height = c3d.height; +res->base.format = c3d.format; +res->base.resource_id = c3d.resource_id; +QTAILQ_INSERT_HEAD(>reslist, >base, next); + args.handle = c3d.resource_id; args.target = c3d.target; args.format = c3d.format; @@ -82,12 +145,21 @@ static void virgl_cmd_resource_unref(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { struct virtio_gpu_resource_unref unref; +struct virtio_gpu_virgl_resource *res; struct iovec *res_iovs = NULL; int num_iovs = 0; VIRTIO_GPU_FILL_CMD(unref); trace_virtio_gpu_cmd_res_unref(unref.resource_id); +res = virtio_gpu_virgl_find_resource(g, unref.resource_id); +if (!res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n", + __func__, unref.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + virgl_renderer_resource_detach_iov(unref.resource_id, _iovs, _iovs); @@ -95,6 +167,10 @@ static void virgl_cmd_resource_unref(VirtIOGPU *g, virtio_gpu_cleanup_mapping_iov(g, res_iovs, num_iovs); } virgl_renderer_resource_unref(unref.resource_id); + +QTAILQ_REMOVE(>reslist, >base, next); + +g_free(res); } static void virgl_cmd_context_create(VirtIOGPU *g, -- 2.44.0
[PATCH v14 12/14] virtio-gpu: Handle resource blob commands
From: Antonio Caggiano Support BLOB resources creation, mapping and unmapping by calling the new stable virglrenderer 0.10 interface. Only enabled when available and via the blob config. E.g. -device virtio-vga-gl,blob=true Signed-off-by: Antonio Caggiano Signed-off-by: Xenia Ragiadakou Signed-off-by: Huang Rui Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 3 + hw/display/virtio-gpu-virgl.c | 309 - hw/display/virtio-gpu.c| 6 +- include/hw/virtio/virtio-gpu.h | 2 + 4 files changed, 316 insertions(+), 4 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 4fe9e6a0c21c..5f27568d3ec8 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -160,6 +160,9 @@ static void virtio_gpu_gl_device_unrealize(DeviceState *qdev) VirtIOGPUGL *gl = VIRTIO_GPU_GL(qdev); if (gl->renderer_state >= RS_INITED) { +#if VIRGL_VERSION_MAJOR >= 1 +qemu_bh_delete(gl->cmdq_resume_bh); +#endif if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { timer_free(gl->print_stats); } diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 60befab7efc2..fed3e27b2fc9 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -26,6 +26,7 @@ struct virtio_gpu_virgl_resource { struct virtio_gpu_simple_resource base; +MemoryRegion *mr; }; static struct virtio_gpu_virgl_resource * @@ -49,6 +50,153 @@ virgl_get_egl_display(G_GNUC_UNUSED void *cookie) } #endif +#if VIRGL_VERSION_MAJOR >= 1 +typedef enum { +HOSTMEM_MR_MAPPED, +HOSTMEM_MR_UNMAPPING, +HOSTMEM_MR_FINISH_UNMAPPING, +} HostmemMRState; + +struct virtio_gpu_virgl_hostmem_region { +MemoryRegion mr; +struct VirtIOGPU *g; +HostmemMRState state; +}; + +static struct virtio_gpu_virgl_hostmem_region * +to_hostmem_region(MemoryRegion *mr) +{ +return container_of(mr, struct virtio_gpu_virgl_hostmem_region, mr); +} + +static void virtio_gpu_virgl_resume_cmdq_bh(void *opaque) +{ +VirtIOGPU *g = opaque; + +virtio_gpu_process_cmdq(g); +} + +static void virtio_gpu_virgl_hostmem_region_free(void *obj) +{ +MemoryRegion *mr = MEMORY_REGION(obj); +struct virtio_gpu_virgl_hostmem_region *vmr; +VirtIOGPUBase *b; +VirtIOGPUGL *gl; + +vmr = to_hostmem_region(mr); +vmr->state = HOSTMEM_MR_FINISH_UNMAPPING; + +b = VIRTIO_GPU_BASE(vmr->g); +b->renderer_blocked--; + +/* + * memory_region_unref() is executed from RCU thread context, while + * virglrenderer works only on the main-loop thread that's holding GL + * context. + */ +gl = VIRTIO_GPU_GL(vmr->g); +qemu_bh_schedule(gl->cmdq_resume_bh); +} + +static int +virtio_gpu_virgl_map_resource_blob(VirtIOGPU *g, + struct virtio_gpu_virgl_resource *res, + uint64_t offset) +{ +struct virtio_gpu_virgl_hostmem_region *vmr; +VirtIOGPUBase *b = VIRTIO_GPU_BASE(g); +MemoryRegion *mr; +uint64_t size; +void *data; +int ret; + +if (!virtio_gpu_hostmem_enabled(b->conf)) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: hostmem disabled\n", __func__); +return -EOPNOTSUPP; +} + +ret = virgl_renderer_resource_map(res->base.resource_id, , ); +if (ret) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map virgl resource: %s\n", + __func__, strerror(-ret)); +return ret; +} + +vmr = g_new0(struct virtio_gpu_virgl_hostmem_region, 1); +vmr->g = g; + +mr = >mr; +memory_region_init_ram_ptr(mr, OBJECT(mr), "blob", size, data); +memory_region_add_subregion(>hostmem, offset, mr); +memory_region_set_enabled(mr, true); + +/* + * MR could outlive the resource if MR's reference is held outside of + * virtio-gpu. In order to prevent unmapping resource while MR is alive, + * and thus, making the data pointer invalid, we will block virtio-gpu + * command processing until MR is fully unreferenced and freed. + */ +OBJECT(mr)->free = virtio_gpu_virgl_hostmem_region_free; + +res->mr = mr; + +return 0; +} + +static int +virtio_gpu_virgl_unmap_resource_blob(VirtIOGPU *g, + struct virtio_gpu_virgl_resource *res, + bool *cmd_suspended) +{ +struct virtio_gpu_virgl_hostmem_region *vmr; +VirtIOGPUBase *b = VIRTIO_GPU_BASE(g); +MemoryRegion *mr = res->mr; +int ret; + +if (!mr) { +return 0; +} + +vmr = to_hostmem_region(res->mr); + +/* + * Perform async unmapping in 3 steps: + * + * 1. Begin async unmapping with memory_region_del_subregion() + *and suspend/block cmd processing. + * 2. Wait for res->mr to be freed and cmd processin
[PATCH v14 10/14] virtio-gpu: Support blob scanout using dmabuf fd
From: Robert Beckett Support displaying blob resources by handling SET_SCANOUT_BLOB command. Signed-by: Antonio Caggiano Signed-off-by: Robert Beckett Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 109 + hw/display/virtio-gpu.c| 12 ++-- include/hw/virtio/virtio-gpu.h | 7 +++ 3 files changed, 122 insertions(+), 6 deletions(-) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 3ffea478e723..60befab7efc2 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -17,6 +17,8 @@ #include "trace.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-gpu.h" +#include "hw/virtio/virtio-gpu-bswap.h" +#include "hw/virtio/virtio-gpu-pixman.h" #include "ui/egl-helpers.h" @@ -78,6 +80,7 @@ static void virgl_cmd_create_resource_2d(VirtIOGPU *g, res->base.height = c2d.height; res->base.format = c2d.format; res->base.resource_id = c2d.resource_id; +res->base.dmabuf_fd = -1; QTAILQ_INSERT_HEAD(>reslist, >base, next); args.handle = c2d.resource_id; @@ -125,6 +128,7 @@ static void virgl_cmd_create_resource_3d(VirtIOGPU *g, res->base.height = c3d.height; res->base.format = c3d.format; res->base.resource_id = c3d.resource_id; +res->base.dmabuf_fd = -1; QTAILQ_INSERT_HEAD(>reslist, >base, next); args.handle = c3d.resource_id; @@ -509,6 +513,106 @@ static void virgl_cmd_get_capset(VirtIOGPU *g, g_free(resp); } +#if VIRGL_VERSION_MAJOR >= 1 +static void virgl_cmd_set_scanout_blob(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ +struct virtio_gpu_framebuffer fb = { 0 }; +struct virgl_renderer_resource_info info; +struct virtio_gpu_virgl_resource *res; +struct virtio_gpu_set_scanout_blob ss; +uint64_t fbend; + +VIRTIO_GPU_FILL_CMD(ss); +virtio_gpu_scanout_blob_bswap(); +trace_virtio_gpu_cmd_set_scanout_blob(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; +} + +if (ss.resource_id == 0) { +virtio_gpu_disable_scanout(g, ss.scanout_id); +return; +} + +if (ss.width < 16 || +ss.height < 16 || +ss.r.x + ss.r.width > ss.width || +ss.r.y + ss.r.height > ss.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__, ss.scanout_id, ss.resource_id, + ss.r.x, ss.r.y, ss.r.width, ss.r.height, + ss.width, ss.height); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; +return; +} + +res = virtio_gpu_virgl_find_resource(g, ss.resource_id); +if (!res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n", + __func__, ss.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} +if (virgl_renderer_resource_get_info(ss.resource_id, )) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not have info %d\n", + __func__, ss.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} +if (res->base.dmabuf_fd < 0) { +res->base.dmabuf_fd = info.fd; +} +if (res->base.dmabuf_fd < 0) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource not backed by dmabuf %d\n", + __func__, ss.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +fb.format = virtio_gpu_get_pixman_format(ss.format); +if (!fb.format) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: pixel format not supported %d\n", + __func__, ss.format); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; +return; +} + +fb.bytes_pp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(fb.format), 8); +fb.width = ss.width; +fb.height = ss.height; +fb.stride = ss.strides[0]; +fb.offset = ss.offsets[0] + ss.r.x * fb.bytes_pp + ss.r.y * fb.stride; + +fbend = fb.offset; +fbend += fb.stride * (ss.r.height - 1); +fbend += fb.bytes_pp * ss.r.width; +if (fbend > res->base.blob_size) { +qemu_log_mask(LOG_GUE
[PATCH v14 11/14] virtio-gpu: Support suspension of commands processing
Check whether command processing has been finished; otherwise, stop processing commands and retry the command again next time. This allows us to support asynchronous execution of non-fenced commands needed for unmapping host blobs safely. Suggested-by: Akihiko Odaki Signed-off-by: Dmitry Osipenko --- hw/display/trace-events | 1 + hw/display/virtio-gpu.c | 6 ++ 2 files changed, 7 insertions(+) diff --git a/hw/display/trace-events b/hw/display/trace-events index e212710284ae..d26d663f9638 100644 --- a/hw/display/trace-events +++ b/hw/display/trace-events @@ -55,6 +55,7 @@ virtio_gpu_fence_ctrl(uint64_t fence, uint32_t type) "fence 0x%" PRIx64 ", type virtio_gpu_fence_resp(uint64_t fence) "fence 0x%" PRIx64 virtio_gpu_inc_inflight_fences(uint32_t inflight) "in-flight+ %u" virtio_gpu_dec_inflight_fences(uint32_t inflight) "in-flight- %u" +virtio_gpu_cmd_suspended(uint32_t cmd) "cmd 0x%x" # qxl.c disable qxl_io_write_vga(int qid, const char *mode, uint32_t addr, uint32_t val) "%d %s addr=%u val=%u" diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 95091c4b7924..1c6e97fb6931 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1054,6 +1054,12 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) /* process command */ vgc->process_cmd(g, cmd); +/* command suspended */ +if (!cmd->finished && !(cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE)) { +trace_virtio_gpu_cmd_suspended(cmd->cmd_hdr.type); +break; +} + QTAILQ_REMOVE(>cmdq, cmd, next); if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { g->stats.requests++; -- 2.44.0
Re: [PATCH v13 03/13] virtio-gpu: Handle virtio_gpu_virgl_init() failure
On 6/10/24 06:38, Akihiko Odaki wrote: > On 2024/06/10 4:02, Dmitry Osipenko wrote: >> On 6/3/24 08:44, Akihiko Odaki wrote: >>> On 2024/06/03 14:26, Dmitry Osipenko wrote: >>>> On 6/2/24 08:34, Akihiko Odaki wrote: >>>>>> +typedef enum { >>>>>> + RS_START, /* starting state */ >>>>>> + RS_INIT_FAILED, /* failed initialisation */ >>>>> >>>>> Is the distinction between RS_START and RS_INIT_FAILED really >>>>> necessary? >>>> >>>> The state stays in RS_INIT_FAILED once was failed until virtio-gpu is >>>> reset, re-initializing virglrenderer isn't allowed in this state. >>> >>> Can you elaborate more? Why isn't re-initializing allowed? >> >> In practice, if virglrenderer initialization failed once, it will fail >> second time. Otherwise we will be retrying to init endlessly because >> guest won't stop sending virgl commands even if they all are timing out. >> Each initialization failure produces a error msg. >> > I see. > > A better solution is to add a new function to GraphicHwOps to call back > after initializating the displays and before starting the guest. You can > do virgl initialization in such a function, and exit(1) if the > initialization fails because the guest has not started yet, saving this > enum. I don't require you to make such a change however; this is not a > regression of your patches so you have no obligation to fix it. I'll keep this idea for a follow up patch, thanks! It will take me some extra time to look through the display code, making sure that callback is added properly and nothing is missed. -- Best regards, Dmitry
Re: [PATCH v13 03/13] virtio-gpu: Handle virtio_gpu_virgl_init() failure
On 6/4/24 17:21, Marc-André Lureau wrote: >> @@ -65,13 +70,21 @@ static void virtio_gpu_gl_handle_ctrl(VirtIODevice >> *vdev, VirtQueue *vq) >> return; >> } >> >> -if (!gl->renderer_inited) { >> -virtio_gpu_virgl_init(g); >> -gl->renderer_inited = true; >> -} >> -if (gl->renderer_reset) { >> -gl->renderer_reset = false; >> +switch (gl->renderer_state) { >> +case RS_RESET: >> virtio_gpu_virgl_reset(g); >> +/* fallthrough */ >> +case RS_START: >> +if (virtio_gpu_virgl_init(g)) { >> +gl->renderer_state = RS_INIT_FAILED; >> +} else { >> +gl->renderer_state = RS_INITED; >> +} >> +break; >> +case RS_INIT_FAILED: >> +return; >> +case RS_INITED: >> +break; >> } >> >> > This still lets it go through the cmd processing after setting > gl->renderer_state = RS_INIT_FAILED, the first time. Good catch, thanks! -- Best regards, Dmitry
Re: [PATCH v13 03/13] virtio-gpu: Handle virtio_gpu_virgl_init() failure
On 6/3/24 08:44, Akihiko Odaki wrote: > On 2024/06/03 14:26, Dmitry Osipenko wrote: >> On 6/2/24 08:34, Akihiko Odaki wrote: >>>> +typedef enum { >>>> + RS_START, /* starting state */ >>>> + RS_INIT_FAILED, /* failed initialisation */ >>> >>> Is the distinction between RS_START and RS_INIT_FAILED really necessary? >> >> The state stays in RS_INIT_FAILED once was failed until virtio-gpu is >> reset, re-initializing virglrenderer isn't allowed in this state. > > Can you elaborate more? Why isn't re-initializing allowed? In practice, if virglrenderer initialization failed once, it will fail second time. Otherwise we will be retrying to init endlessly because guest won't stop sending virgl commands even if they all are timing out. Each initialization failure produces a error msg. -- Best regards, Dmitry
Re: [PATCH v12 00/13] Support blob memory and venus on qemu
On 6/5/24 17:47, Alex Bennée wrote: > I'm guessing some sort of resource leak, if I run vkcube-wayland in the > guest it complains about being stuck on a fence with the iterator going > up. However on the host I see: > > virtio_gpu_fence_ctrl fence 0x13f1, type 0x207 > virtio_gpu_fence_ctrl fence 0x13f2, type 0x207 > virtio_gpu_fence_resp fence 0x13f1 > virtio_gpu_fence_resp fence 0x13f2 > virtio_gpu_fence_ctrl fence 0x13f3, type 0x207 > virtio_gpu_fence_ctrl fence 0x13f4, type 0x207 > virtio_gpu_fence_resp fence 0x13f3 > virtio_gpu_fence_resp fence 0x13f4 > virtio_gpu_fence_ctrl fence 0x13f5, type 0x207 > virtio_gpu_fence_ctrl fence 0x13f6, type 0x207 > virtio_gpu_fence_resp fence 0x13f5 > virtio_gpu_fence_resp fence 0x13f6 > virtio_gpu_fence_ctrl fence 0x13f7, type 0x207 > virtio_gpu_fence_ctrl fence 0x13f8, type 0x207 > virtio_gpu_fence_resp fence 0x13f7 > virtio_gpu_fence_resp fence 0x13f8 > virtio_gpu_fence_ctrl fence 0x13f9, type 0x204 > virtio_gpu_fence_resp fence 0x13f9 > > which looks like its going ok. However when I git Ctrl-C in the guest it > kills QEMU: > > virtio_gpu_fence_ctrl fence 0x13fc, type 0x207 > virtio_gpu_fence_ctrl fence 0x13fd, type 0x207 > virtio_gpu_fence_ctrl fence 0x13fe, type 0x204 > virtio_gpu_fence_ctrl fence 0x13ff, type 0x207 > virtio_gpu_fence_ctrl fence 0x1400, type 0x207 > virtio_gpu_fence_resp fence 0x13fc > virtio_gpu_fence_resp fence 0x13fd > virtio_gpu_fence_resp fence 0x13fe > virtio_gpu_fence_resp fence 0x13ff > virtio_gpu_fence_resp fence 0x1400 > qemu-system-aarch64: > ../../subprojects/virglrenderer/src/virglrenderer.c:1282: > virgl_renderer_resource_unmap: Assertion `!ret' failed. > fish: Job 1, './qemu-system-aarch64 \' terminated by signal -machine > type=virt,virtuali… (-cpu neoverse-n1 \) > fish: Job -smp 4 \, '-accel tcg \' terminated by signal -device > virtio-net-pci,netd… (-device virtio-scsi-pci \) > fish: Job -device scsi-hd,drive=hd \, '-netdev > user,id=unet,hostfw…' terminated by signal -blockdev driver=raw,node-n… ( >-serial mon:stdio \) > fish: Job -blockdev node-name=rom,dri…, '-blockdev > node-name=efivars…' terminated by signal -m 8192 \ (-object > memory-backend-memf…) > fish: Job -device virtio-gpu-gl-pci,h…, '-display > sdl,gl=on,show-cur…' terminated by signal -device qemu-xhci -device u… ( > -kernel /home/alex/lsrc/lin…) > fish: Job -d guest_errors,unimp,trace…, 'SIGABRT' terminated by signal > Abort () > > The backtrace (and the 18G size of the core file!) indicates a leak: The unmap debug-assert tells that BO wasn't mapped because mapping failed, likely due to OOM. You won't hit this abort with a release build of libvirglrenderer. The leak likely happens due to unsignalled fence. Please try to run vkcube with disabled fence-feedback feature: # VN_PERF_NO_FENCE_FEEDBACK=1 vkcube-wayland It fixes hang for me. We had problems with combination of this Venus optimization feature + Intel ANV driver for a long time and hoped that it's fixed by now, apparently the issue was only masked. -- Best regards, Dmitry
Re: [PATCH v13 11/13] virtio-gpu: Handle resource blob commands
On 6/2/24 08:45, Akihiko Odaki wrote: ... >> + case HOSTMEM_MR_FINISH_UNMAPPING: >> + ret = virgl_renderer_resource_unmap(res->base.resource_id); >> + if (ret) { >> + qemu_log_mask(LOG_GUEST_ERROR, >> + "%s: failed to unmap virgl resource: %s\n", >> + __func__, strerror(-ret)); >> + return ret; >> + } >> + res->mr = NULL; >> + g_free(vmr); >> + break; >> + case HOSTMEM_MR_UNMAPPING: >> + *cmd_suspended = true; > > This code path should be unreachable since the command processing is > blocked while unmapping. Will change to abort() >> + if (cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) { >> + ret = virtio_gpu_create_mapping_iov(g, cblob.nr_entries, >> sizeof(cblob), >> + cmd, >base.addrs, >> + >base.iov, >> >base.iov_cnt); >> + if (!ret) { >> + g_free(res); > > As noted for an earlier version: >> Use g_autofree instead of writing duplicate g_free() calls. See >> docs/devel/style.rst for details. The g_autofree isn't appropriate for this code. It's intended to be used if you allocate a tmp variable that should be freed in all code paths. This is not the case here, the res variable isn't temporal and shall not be freed on success. -- Best regards, Dmitry
Re: [PATCH v13 03/13] virtio-gpu: Handle virtio_gpu_virgl_init() failure
On 6/2/24 08:34, Akihiko Odaki wrote: >> +typedef enum { >> + RS_START, /* starting state */ >> + RS_INIT_FAILED, /* failed initialisation */ > > Is the distinction between RS_START and RS_INIT_FAILED really necessary? The state stays in RS_INIT_FAILED once was failed until virtio-gpu is reset, re-initializing virglrenderer isn't allowed in this state. The RS_START state allows to initialize virglrenderer and moves to either RS_INITED or RS_INIT_FAILED state after initialization. The distinction is necessary -- Best regards, Dmitry
[PATCH v13 11/13] virtio-gpu: Handle resource blob commands
From: Antonio Caggiano Support BLOB resources creation, mapping and unmapping by calling the new stable virglrenderer 0.10 interface. Only enabled when available and via the blob config. E.g. -device virtio-vga-gl,blob=true Signed-off-by: Antonio Caggiano Signed-off-by: Xenia Ragiadakou Signed-off-by: Huang Rui Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 320 - hw/display/virtio-gpu.c| 4 +- include/hw/virtio/virtio-gpu.h | 2 + 3 files changed, 322 insertions(+), 4 deletions(-) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 7f45b4fa5fd7..0c73d9ba65f9 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -26,6 +26,7 @@ struct virtio_gpu_virgl_resource { struct virtio_gpu_simple_resource base; +MemoryRegion *mr; }; static struct virtio_gpu_virgl_resource * @@ -49,6 +50,159 @@ virgl_get_egl_display(G_GNUC_UNUSED void *cookie) } #endif +#ifdef HAVE_VIRGL_RESOURCE_BLOB +typedef enum { +HOSTMEM_MR_MAPPED, +HOSTMEM_MR_UNMAPPING, +HOSTMEM_MR_FINISH_UNMAPPING, +} HostmemMRState; + +struct virtio_gpu_virgl_hostmem_region { +MemoryRegion mr; +struct VirtIOGPU *g; +HostmemMRState state; +}; + +static struct virtio_gpu_virgl_hostmem_region * +to_hostmem_region(MemoryRegion *mr) +{ +return container_of(mr, struct virtio_gpu_virgl_hostmem_region, mr); +} + +static void virtio_gpu_virgl_resume_cmdq_bh(void *opaque) +{ +VirtIOGPU *g = opaque; + +virtio_gpu_process_cmdq(g); +} + +static void virtio_gpu_virgl_hostmem_region_free(void *obj) +{ +MemoryRegion *mr = MEMORY_REGION(obj); +struct virtio_gpu_virgl_hostmem_region *vmr; +VirtIOGPUBase *b; +VirtIOGPUGL *gl; + +vmr = to_hostmem_region(mr); +vmr->state = HOSTMEM_MR_FINISH_UNMAPPING; + +b = VIRTIO_GPU_BASE(vmr->g); +b->renderer_blocked--; + +/* + * memory_region_unref() is executed from RCU thread context, while + * virglrenderer works only on the main-loop thread that's holding GL + * context. + */ +gl = VIRTIO_GPU_GL(vmr->g); +qemu_bh_schedule(gl->cmdq_resume_bh); +} + +static int +virtio_gpu_virgl_map_resource_blob(VirtIOGPU *g, + struct virtio_gpu_virgl_resource *res, + uint64_t offset) +{ +struct virtio_gpu_virgl_hostmem_region *vmr; +VirtIOGPUBase *b = VIRTIO_GPU_BASE(g); +MemoryRegion *mr; +uint64_t size; +void *data; +int ret; + +if (!virtio_gpu_hostmem_enabled(b->conf)) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: hostmem disabled\n", __func__); +return -EOPNOTSUPP; +} + +ret = virgl_renderer_resource_map(res->base.resource_id, , ); +if (ret) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map virgl resource: %s\n", + __func__, strerror(-ret)); +return ret; +} + +vmr = g_new0(struct virtio_gpu_virgl_hostmem_region, 1); +vmr->g = g; + +mr = >mr; +memory_region_init_ram_ptr(mr, OBJECT(mr), "blob", size, data); +memory_region_add_subregion(>hostmem, offset, mr); +memory_region_set_enabled(mr, true); + +/* + * MR could outlive the resource if MR's reference is held outside of + * virtio-gpu. In order to prevent unmapping resource while MR is alive, + * and thus, making the data pointer invalid, we will block virtio-gpu + * command processing until MR is fully unreferenced and freed. + */ +OBJECT(mr)->free = virtio_gpu_virgl_hostmem_region_free; + +res->mr = mr; + +return 0; +} + +static int +virtio_gpu_virgl_unmap_resource_blob(VirtIOGPU *g, + struct virtio_gpu_virgl_resource *res, + bool *cmd_suspended) +{ +struct virtio_gpu_virgl_hostmem_region *vmr; +VirtIOGPUBase *b = VIRTIO_GPU_BASE(g); +MemoryRegion *mr = res->mr; +int ret; + +if (!mr) { +return 0; +} + +vmr = to_hostmem_region(res->mr); + +/* + * Perform async unmapping in 3 steps: + * + * 1. Begin async unmapping with memory_region_del_subregion() + *and suspend/block cmd processing. + * 2. Wait for res->mr to be freed and cmd processing resumed + *asynchronously by virtio_gpu_virgl_hostmem_region_free(). + * 3. Finish the unmapping with final virgl_renderer_resource_unmap(). + */ + +switch (vmr->state) { +case HOSTMEM_MR_MAPPED: +vmr->state = HOSTMEM_MR_UNMAPPING; + +*cmd_suspended = true; + +/* render will be unblocked once MR is freed */ +b->renderer_blocked++; + +/* memory region owns self res->mr object and frees it by itself */ +memory_region_set_enabled(mr, false); +memory_region_del_subregion(>hostmem, mr); +object
[PATCH v13 02/13] virtio-gpu: Move print_stats timer to VirtIOGPUGL
Move print_stats timer to VirtIOGPUGL for consistency with cmdq_resume_bh and fence_poll that are used only by GL device. Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 10 ++ include/hw/virtio/virtio-gpu.h | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 7239a9f8e066..fa0da8f5c7f1 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -574,6 +574,7 @@ static struct virgl_renderer_callbacks virtio_gpu_3d_cbs = { static void virtio_gpu_print_stats(void *opaque) { VirtIOGPU *g = opaque; +VirtIOGPUGL *gl = VIRTIO_GPU_GL(g); if (g->stats.requests) { fprintf(stderr, "stats: vq req %4d, %3d -- 3D %4d (%5d)\n", @@ -588,7 +589,7 @@ static void virtio_gpu_print_stats(void *opaque) } else { fprintf(stderr, "stats: idle\r"); } -timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000); +timer_mod(gl->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000); } static void virtio_gpu_fence_poll(void *opaque) @@ -651,9 +652,10 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) virtio_gpu_fence_poll, g); if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { -g->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL, - virtio_gpu_print_stats, g); -timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000); +gl->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL, + virtio_gpu_print_stats, g); +timer_mod(gl->print_stats, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000); } return 0; } diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index bc69fd78a440..7ff989a45a5c 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -196,7 +196,6 @@ struct VirtIOGPU { uint64_t hostmem; bool processing_cmdq; -QEMUTimer *print_stats; uint32_t inflight; struct { @@ -232,6 +231,7 @@ struct VirtIOGPUGL { bool renderer_reset; QEMUTimer *fence_poll; +QEMUTimer *print_stats; }; struct VhostUserGPU { -- 2.44.0
[PATCH v13 07/13] virtio-gpu: Don't require udmabuf when blobs and virgl are enabled
The udmabuf usage is mandatory when virgl is disabled and blobs feature enabled in the Qemu machine configuration. If virgl and blobs are enabled, then udmabuf requirement is optional. Since udmabuf isn't widely supported by a popular Linux distros today, let's relax the udmabuf requirement for blobs=on,virgl=on. Now, a full-featured virtio-gpu acceleration is available to Qemu users without a need to have udmabuf available in the system. Reviewed-by: Antonio Caggiano Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Reviewed-by: Marc-André Lureau Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index d60b1b2973af..672279e57f3f 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1485,6 +1485,7 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) if (virtio_gpu_blob_enabled(g->parent_obj.conf)) { if (!virtio_gpu_rutabaga_enabled(g->parent_obj.conf) && +!virtio_gpu_virgl_enabled(g->parent_obj.conf) && !virtio_gpu_have_udmabuf()) { error_setg(errp, "need rutabaga or udmabuf for blob resources"); return; -- 2.44.0
[PATCH v13 12/13] virtio-gpu: Register capsets dynamically
From: Pierre-Eric Pelloux-Prayer virtio_gpu_virgl_get_num_capsets will return "num_capsets", but we can't assume that capset_index 1 is always VIRGL2 once we'll support more capsets, like Venus and DRM capsets. Register capsets dynamically to avoid that problem. Reviewed-by: Manos Pitsidianakis Signed-off-by: Pierre-Eric Pelloux-Prayer Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 6 -- hw/display/virtio-gpu-virgl.c | 33 + include/hw/virtio/virtio-gpu.h | 4 +++- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 9822d79c5e81..34a2bd2fa426 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -137,8 +137,8 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) } g->parent_obj.conf.flags |= (1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED); -VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = -virtio_gpu_virgl_get_num_capsets(g); +g->capset_ids = virtio_gpu_virgl_get_capsets(g); +VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = g->capset_ids->len; #ifdef HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED; @@ -163,6 +163,8 @@ static void virtio_gpu_gl_device_unrealize(DeviceState *qdev) } gl->renderer_state = RS_START; + +g_array_unref(g->capset_ids); } static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 0c73d9ba65f9..d3ae3e3d4e24 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -636,19 +636,13 @@ static void virgl_cmd_get_capset_info(VirtIOGPU *g, VIRTIO_GPU_FILL_CMD(info); memset(, 0, sizeof(resp)); -if (info.capset_index == 0) { -resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL; -virgl_renderer_get_cap_set(resp.capset_id, - _max_version, - _max_size); -} else if (info.capset_index == 1) { -resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL2; + +if (info.capset_index < g->capset_ids->len) { +resp.capset_id = g_array_index(g->capset_ids, uint32_t, + info.capset_index); virgl_renderer_get_cap_set(resp.capset_id, _max_version, _max_size); -} else { -resp.capset_max_version = 0; -resp.capset_max_size = 0; } resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO; virtio_gpu_ctrl_response(g, cmd, , sizeof(resp)); @@ -1171,14 +1165,29 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) return 0; } -int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g) +static void virtio_gpu_virgl_add_capset(GArray *capset_ids, uint32_t capset_id) +{ +g_array_append_val(capset_ids, capset_id); +} + +GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g) { uint32_t capset2_max_ver, capset2_max_size; +GArray *capset_ids; + +capset_ids = g_array_new(false, false, sizeof(uint32_t)); + +/* VIRGL is always supported. */ +virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL); + virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VIRGL2, _max_ver, _max_size); +if (capset2_max_ver) { +virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL2); +} -return capset2_max_ver ? 2 : 1; +return capset_ids; } void virtio_gpu_virgl_deinit(VirtIOGPU *g) diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 368f96a813c9..b9de761fd673 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -209,6 +209,8 @@ struct VirtIOGPU { QTAILQ_HEAD(, VGPUDMABuf) bufs; VGPUDMABuf *primary[VIRTIO_GPU_MAX_SCANOUTS]; } dmabuf; + +GArray *capset_ids; }; struct VirtIOGPUClass { @@ -355,6 +357,6 @@ void virtio_gpu_virgl_reset_scanout(VirtIOGPU *g); void virtio_gpu_virgl_reset(VirtIOGPU *g); int virtio_gpu_virgl_init(VirtIOGPU *g); void virtio_gpu_virgl_deinit(VirtIOGPU *g); -int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g); +GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g); #endif -- 2.44.0
[PATCH v13 13/13] virtio-gpu: Support Venus context
From: Antonio Caggiano Request Venus when initializing VirGL and if venus=true flag is set for virtio-gpu-gl device. Signed-off-by: Antonio Caggiano Signed-off-by: Huang Rui Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 2 ++ hw/display/virtio-gpu-virgl.c | 22 ++ hw/display/virtio-gpu.c| 13 + include/hw/virtio/virtio-gpu.h | 3 +++ meson.build| 1 + 5 files changed, 37 insertions(+), 4 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 34a2bd2fa426..50292826e7cf 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -150,6 +150,8 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) static Property virtio_gpu_gl_properties[] = { DEFINE_PROP_BIT("stats", VirtIOGPU, parent_obj.conf.flags, VIRTIO_GPU_FLAG_STATS_ENABLED, false), +DEFINE_PROP_BIT("venus", VirtIOGPU, parent_obj.conf.flags, +VIRTIO_GPU_FLAG_VENUS_ENABLED, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index d3ae3e3d4e24..c9d20a8a60d0 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -1139,6 +1139,11 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) flags |= VIRGL_RENDERER_D3D11_SHARE_TEXTURE; } #endif +#ifdef VIRGL_RENDERER_VENUS +if (virtio_gpu_venus_enabled(g->parent_obj.conf)) { +flags |= VIRGL_RENDERER_VENUS | VIRGL_RENDERER_RENDER_SERVER; +} +#endif ret = virgl_renderer_init(g, flags, _gpu_3d_cbs); if (ret != 0) { @@ -1172,7 +1177,7 @@ static void virtio_gpu_virgl_add_capset(GArray *capset_ids, uint32_t capset_id) GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g) { -uint32_t capset2_max_ver, capset2_max_size; +uint32_t capset_max_ver, capset_max_size; GArray *capset_ids; capset_ids = g_array_new(false, false, sizeof(uint32_t)); @@ -1181,12 +1186,21 @@ GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g) virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL); virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VIRGL2, - _max_ver, - _max_size); -if (capset2_max_ver) { + _max_ver, + _max_size); +if (capset_max_ver) { virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL2); } +if (virtio_gpu_venus_enabled(g->parent_obj.conf)) { +virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VENUS, + _max_ver, + _max_size); +if (capset_max_size) { +virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VENUS); +} +} + return capset_ids; } diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index d423bc9a7bf5..0618801715a6 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1504,6 +1504,19 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) #endif } +if (virtio_gpu_venus_enabled(g->parent_obj.conf)) { +#ifdef HAVE_VIRGL_VENUS +if (!virtio_gpu_blob_enabled(g->parent_obj.conf) || +!virtio_gpu_hostmem_enabled(g->parent_obj.conf)) { +error_setg(errp, "venus requires enabled blob and hostmem options"); +return; +} +#else +error_setg(errp, "old virglrenderer, venus unsupported"); +return; +#endif +} + if (!virtio_gpu_base_device_realize(qdev, virtio_gpu_handle_ctrl_cb, virtio_gpu_handle_cursor_cb, diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index b9de761fd673..910c5c3bcd45 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -99,6 +99,7 @@ enum virtio_gpu_base_conf_flags { VIRTIO_GPU_FLAG_BLOB_ENABLED, VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED, VIRTIO_GPU_FLAG_RUTABAGA_ENABLED, +VIRTIO_GPU_FLAG_VENUS_ENABLED, }; #define virtio_gpu_virgl_enabled(_cfg) \ @@ -117,6 +118,8 @@ enum virtio_gpu_base_conf_flags { (_cfg.flags & (1 << VIRTIO_GPU_FLAG_RUTABAGA_ENABLED)) #define virtio_gpu_hostmem_enabled(_cfg) \ (_cfg.hostmem > 0) +#define virtio_gpu_venus_enabled(_cfg) \ +(_cfg.flags & (1 << VIRTIO_GPU_FLAG_VENUS_ENABLED)) struct virtio_gpu_base_conf { uint32_t max_outputs; diff --git a/meson.build b/meson.build index e753da4c76c3..1d7346b70311 100644 --- a/meson.build +++ b/meson.build @@ -2312,6 +2312,7 @@ if virgl.version().version_compare('>=1.0.0') config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', 1) config_host_data.set('HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS', 1) config_host_data.set('HA
[PATCH v13 10/13] virtio-gpu: Support suspension of commands processing
Check whether command processing has been finished; otherwise, stop processing commands and retry the command again next time. This allows us to support asynchronous execution of non-fenced commands needed for unmapping host blobs safely. Suggested-by: Akihiko Odaki Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu.c | 5 + 1 file changed, 5 insertions(+) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index f3d2def9a49f..8e05a2d0c7c5 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1054,6 +1054,11 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) /* process command */ vgc->process_cmd(g, cmd); +/* command suspended */ +if (!cmd->finished && !(cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE)) { +break; +} + QTAILQ_REMOVE(>cmdq, cmd, next); if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { g->stats.requests++; -- 2.44.0
[PATCH v13 06/13] virtio-gpu: Support context-init feature with virglrenderer
From: Huang Rui Patch "virtio-gpu: CONTEXT_INIT feature" has added the context_init feature flags. Expose this feature and support creating virglrenderer context with flags using context_id if libvirglrenderer is new enough. Originally-by: Antonio Caggiano Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c| 4 hw/display/virtio-gpu-virgl.c | 20 ++-- meson.build | 1 + 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 7978b2985e17..9822d79c5e81 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -140,6 +140,10 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = virtio_gpu_virgl_get_num_capsets(g); +#ifdef HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS +g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED; +#endif + virtio_gpu_device_realize(qdev, errp); } diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 66c4aab9b283..4b2d4a643e30 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -106,8 +106,24 @@ static void virgl_cmd_context_create(VirtIOGPU *g, trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id, cc.debug_name); -virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen, - cc.debug_name); +if (cc.context_init) { +if (!virtio_gpu_context_init_enabled(g->parent_obj.conf)) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: context_init disabled", + __func__); +cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; +return; +} + +#ifdef HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS +virgl_renderer_context_create_with_flags(cc.hdr.ctx_id, + cc.context_init, + cc.nlen, + cc.debug_name); +return; +#endif +} + +virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen, cc.debug_name); } static void virgl_cmd_context_destroy(VirtIOGPU *g, diff --git a/meson.build b/meson.build index de97d2426bde..65fddfbbc3a7 100644 --- a/meson.build +++ b/meson.build @@ -2310,6 +2310,7 @@ config_host_data.set('CONFIG_VNC_JPEG', jpeg.found()) config_host_data.set('CONFIG_VNC_SASL', sasl.found()) if virgl.version().version_compare('>=1.0.0') config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', 1) + config_host_data.set('HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS', 1) endif config_host_data.set('CONFIG_VIRTFS', have_virtfs) config_host_data.set('CONFIG_VTE', vte.found()) -- 2.44.0
[PATCH v13 03/13] virtio-gpu: Handle virtio_gpu_virgl_init() failure
virtio_gpu_virgl_init() may fail, leading to a further Qemu crash because Qemu assumes it never fails. Check virtio_gpu_virgl_init() return code and don't execute virtio commands on error. Failed virtio_gpu_virgl_init() will result in a timed out virtio commands for a guest OS. Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 29 + include/hw/virtio/virtio-gpu.h | 11 +-- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index e06be60dfbfc..38a2b1bd3916 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -29,9 +29,14 @@ static void virtio_gpu_gl_update_cursor_data(VirtIOGPU *g, struct virtio_gpu_scanout *s, uint32_t resource_id) { +VirtIOGPUGL *gl = VIRTIO_GPU_GL(g); uint32_t width, height; uint32_t pixels, *data; +if (gl->renderer_state != RS_INITED) { +return; +} + data = virgl_renderer_get_cursor_data(resource_id, , ); if (!data) { return; @@ -65,13 +70,21 @@ static void virtio_gpu_gl_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) return; } -if (!gl->renderer_inited) { -virtio_gpu_virgl_init(g); -gl->renderer_inited = true; -} -if (gl->renderer_reset) { -gl->renderer_reset = false; +switch (gl->renderer_state) { +case RS_RESET: virtio_gpu_virgl_reset(g); +/* fallthrough */ +case RS_START: +if (virtio_gpu_virgl_init(g)) { +gl->renderer_state = RS_INIT_FAILED; +} else { +gl->renderer_state = RS_INITED; +} +break; +case RS_INIT_FAILED: +return; +case RS_INITED: +break; } cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); @@ -98,9 +111,9 @@ static void virtio_gpu_gl_reset(VirtIODevice *vdev) * GL functions must be called with the associated GL context in main * thread, and when the renderer is unblocked. */ -if (gl->renderer_inited && !gl->renderer_reset) { +if (gl->renderer_state == RS_INITED) { virtio_gpu_virgl_reset_scanout(g); -gl->renderer_reset = true; +gl->renderer_state = RS_RESET; } } diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 7ff989a45a5c..6e71d799e5da 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -224,11 +224,18 @@ struct VirtIOGPUClass { Error **errp); }; +/* VirtIOGPUGL renderer states */ +typedef enum { +RS_START, /* starting state */ +RS_INIT_FAILED, /* failed initialisation */ +RS_INITED, /* initialised and working */ +RS_RESET, /* inited and reset pending, moves to start after reset */ +} RenderState; + struct VirtIOGPUGL { struct VirtIOGPU parent_obj; -bool renderer_inited; -bool renderer_reset; +RenderState renderer_state; QEMUTimer *fence_poll; QEMUTimer *print_stats; -- 2.44.0
[PATCH v13 09/13] virtio-gpu: Support blob scanout using dmabuf fd
From: Robert Beckett Support displaying blob resources by handling SET_SCANOUT_BLOB command. Signed-by: Antonio Caggiano Signed-off-by: Robert Beckett Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 109 + hw/display/virtio-gpu.c| 12 ++-- include/hw/virtio/virtio-gpu.h | 7 +++ meson.build| 1 + 4 files changed, 123 insertions(+), 6 deletions(-) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 8392d0fde984..7f45b4fa5fd7 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -17,6 +17,8 @@ #include "trace.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-gpu.h" +#include "hw/virtio/virtio-gpu-bswap.h" +#include "hw/virtio/virtio-gpu-pixman.h" #include "ui/egl-helpers.h" @@ -78,6 +80,7 @@ static void virgl_cmd_create_resource_2d(VirtIOGPU *g, res->base.height = c2d.height; res->base.format = c2d.format; res->base.resource_id = c2d.resource_id; +res->base.dmabuf_fd = -1; QTAILQ_INSERT_HEAD(>reslist, >base, next); args.handle = c2d.resource_id; @@ -125,6 +128,7 @@ static void virgl_cmd_create_resource_3d(VirtIOGPU *g, res->base.height = c3d.height; res->base.format = c3d.format; res->base.resource_id = c3d.resource_id; +res->base.dmabuf_fd = -1; QTAILQ_INSERT_HEAD(>reslist, >base, next); args.handle = c3d.resource_id; @@ -509,6 +513,106 @@ static void virgl_cmd_get_capset(VirtIOGPU *g, g_free(resp); } +#ifdef HAVE_VIRGL_RESOURCE_BLOB +static void virgl_cmd_set_scanout_blob(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ +struct virtio_gpu_framebuffer fb = { 0 }; +struct virgl_renderer_resource_info info; +struct virtio_gpu_virgl_resource *res; +struct virtio_gpu_set_scanout_blob ss; +uint64_t fbend; + +VIRTIO_GPU_FILL_CMD(ss); +virtio_gpu_scanout_blob_bswap(); +trace_virtio_gpu_cmd_set_scanout_blob(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; +} + +if (ss.resource_id == 0) { +virtio_gpu_disable_scanout(g, ss.scanout_id); +return; +} + +if (ss.width < 16 || +ss.height < 16 || +ss.r.x + ss.r.width > ss.width || +ss.r.y + ss.r.height > ss.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__, ss.scanout_id, ss.resource_id, + ss.r.x, ss.r.y, ss.r.width, ss.r.height, + ss.width, ss.height); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; +return; +} + +res = virtio_gpu_virgl_find_resource(g, ss.resource_id); +if (!res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n", + __func__, ss.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} +if (virgl_renderer_resource_get_info(ss.resource_id, )) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not have info %d\n", + __func__, ss.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} +if (res->base.dmabuf_fd < 0) { +res->base.dmabuf_fd = info.fd; +} +if (res->base.dmabuf_fd < 0) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource not backed by dmabuf %d\n", + __func__, ss.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +fb.format = virtio_gpu_get_pixman_format(ss.format); +if (!fb.format) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: pixel format not supported %d\n", + __func__, ss.format); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; +return; +} + +fb.bytes_pp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(fb.format), 8); +fb.width = ss.width; +fb.height = ss.height; +fb.stride = ss.strides[0]; +fb.offset = ss.offsets[0] + ss.r.x * fb.bytes_pp + ss.r.y * fb.stride; + +fbend = fb.offset; +fbend += fb.stride * (ss.r.height - 1); +fbend += fb.bytes_pp * ss.r.width; +if (fbend > res->base.blob_
[PATCH v13 00/13] Support blob memory and venus on qemu
ecause blob resources are unmapped via virgl_cmd_resource_unmap_blob(). - In virgl_cmd_resource_create_blob(), do proper cleanup in error paths and move QTAILQ_INSERT_HEAD(>reslist, res, next) after the resource has been fully initialized. - Memory region has a different life-cycle from virtio gpu resources i.e. cannot be released synchronously along with the vgpu resource. So, here the field "region" was changed to a pointer and is allocated dynamically when the blob is mapped. Also, since the pointer can be used to indicate whether the blob is mapped, the explicite field "mapped" was removed. - In virgl_cmd_resource_map_blob(), add check on the value of res->region, to prevent beeing called twice on the same resource. - Add a patch to enable automatic deallocation of memory regions to resolve use-after-free memory corruption with a reference. Antonio Caggiano (2): virtio-gpu: Handle resource blob commands virtio-gpu: Support Venus context Dmitry Osipenko (7): virtio-gpu: Move fence_poll timer to VirtIOGPUGL virtio-gpu: Move print_stats timer to VirtIOGPUGL virtio-gpu: Handle virtio_gpu_virgl_init() failure virtio-gpu: Unrealize GL device virtio-gpu: Use pkgconfig version to decide which virgl features are available virtio-gpu: Don't require udmabuf when blobs and virgl are enabled virtio-gpu: Support suspension of commands processing Huang Rui (2): virtio-gpu: Support context-init feature with virglrenderer virtio-gpu: Add virgl resource management Pierre-Eric Pelloux-Prayer (1): virtio-gpu: Register capsets dynamically Robert Beckett (1): virtio-gpu: Support blob scanout using dmabuf fd hw/display/virtio-gpu-gl.c | 54 ++- hw/display/virtio-gpu-virgl.c | 607 +++-- hw/display/virtio-gpu.c| 35 +- include/hw/virtio/virtio-gpu.h | 33 +- meson.build| 10 +- 5 files changed, 685 insertions(+), 54 deletions(-) -- 2.44.0
[PATCH v13 05/13] virtio-gpu: Use pkgconfig version to decide which virgl features are available
New virglrerenderer features were stabilized with release of v1.0.0. Presence of symbols in virglrenderer.h doesn't guarantee ABI compatibility with pre-release development versions of libvirglerender. Use virglrenderer version to decide reliably which virgl features are available. Reviewed-by: Alex Bennée Signed-off-by: Dmitry Osipenko --- meson.build | 7 ++- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index 638660714455..de97d2426bde 100644 --- a/meson.build +++ b/meson.build @@ -2308,11 +2308,8 @@ config_host_data.set('CONFIG_PNG', png.found()) config_host_data.set('CONFIG_VNC', vnc.found()) config_host_data.set('CONFIG_VNC_JPEG', jpeg.found()) config_host_data.set('CONFIG_VNC_SASL', sasl.found()) -if virgl.found() - config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', - cc.has_member('struct virgl_renderer_resource_info_ext', 'd3d_tex2d', - prefix: '#include ', - dependencies: virgl)) +if virgl.version().version_compare('>=1.0.0') + config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', 1) endif config_host_data.set('CONFIG_VIRTFS', have_virtfs) config_host_data.set('CONFIG_VTE', vte.found()) -- 2.44.0
[PATCH v13 04/13] virtio-gpu: Unrealize GL device
Even though GL GPU doesn't support hotplugging today, free virgl resources when GL device is unrealized. For consistency. Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 13 + hw/display/virtio-gpu-virgl.c | 11 +++ include/hw/virtio/virtio-gpu.h | 1 + 3 files changed, 25 insertions(+) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 38a2b1bd3916..7978b2985e17 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -149,6 +149,18 @@ static Property virtio_gpu_gl_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static void virtio_gpu_gl_device_unrealize(DeviceState *qdev) +{ +VirtIOGPU *g = VIRTIO_GPU(qdev); +VirtIOGPUGL *gl = VIRTIO_GPU_GL(qdev); + +if (gl->renderer_state >= RS_INITED) { +virtio_gpu_virgl_deinit(g); +} + +gl->renderer_state = RS_START; +} + static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -162,6 +174,7 @@ static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) vgc->update_cursor_data = virtio_gpu_gl_update_cursor_data; vdc->realize = virtio_gpu_gl_device_realize; +vdc->unrealize = virtio_gpu_gl_device_unrealize; vdc->reset = virtio_gpu_gl_reset; device_class_set_props(dc, virtio_gpu_gl_properties); } diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index fa0da8f5c7f1..66c4aab9b283 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -669,3 +669,14 @@ int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g) return capset2_max_ver ? 2 : 1; } + +void virtio_gpu_virgl_deinit(VirtIOGPU *g) +{ +VirtIOGPUGL *gl = VIRTIO_GPU_GL(g); + +if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { +timer_free(gl->print_stats); +} +timer_free(gl->fence_poll); +virgl_renderer_cleanup(NULL); +} diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 6e71d799e5da..2faeda6f6abe 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -345,6 +345,7 @@ void virtio_gpu_virgl_fence_poll(VirtIOGPU *g); void virtio_gpu_virgl_reset_scanout(VirtIOGPU *g); void virtio_gpu_virgl_reset(VirtIOGPU *g); int virtio_gpu_virgl_init(VirtIOGPU *g); +void virtio_gpu_virgl_deinit(VirtIOGPU *g); int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g); #endif -- 2.44.0
[PATCH v13 08/13] virtio-gpu: Add virgl resource management
From: Huang Rui In a preparation to adding host blobs support to virtio-gpu, add virgl resource management that allows to retrieve resource based on its ID and virgl resource wrapper on top of simple resource that will be contain fields specific to virgl. Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 76 +++ 1 file changed, 76 insertions(+) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 4b2d4a643e30..8392d0fde984 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -22,6 +22,23 @@ #include +struct virtio_gpu_virgl_resource { +struct virtio_gpu_simple_resource base; +}; + +static struct virtio_gpu_virgl_resource * +virtio_gpu_virgl_find_resource(VirtIOGPU *g, uint32_t resource_id) +{ +struct virtio_gpu_simple_resource *res; + +res = virtio_gpu_find_resource(g, resource_id); +if (!res) { +return NULL; +} + +return container_of(res, struct virtio_gpu_virgl_resource, base); +} + #if VIRGL_RENDERER_CALLBACKS_VERSION >= 4 static void * virgl_get_egl_display(G_GNUC_UNUSED void *cookie) @@ -35,11 +52,34 @@ static void virgl_cmd_create_resource_2d(VirtIOGPU *g, { struct virtio_gpu_resource_create_2d c2d; struct virgl_renderer_resource_create_args args; +struct virtio_gpu_virgl_resource *res; VIRTIO_GPU_FILL_CMD(c2d); trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format, c2d.width, c2d.height); +if (c2d.resource_id == 0) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n", + __func__); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = virtio_gpu_virgl_find_resource(g, c2d.resource_id); +if (res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n", + __func__, c2d.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = g_new0(struct virtio_gpu_virgl_resource, 1); +res->base.width = c2d.width; +res->base.height = c2d.height; +res->base.format = c2d.format; +res->base.resource_id = c2d.resource_id; +QTAILQ_INSERT_HEAD(>reslist, >base, next); + args.handle = c2d.resource_id; args.target = 2; args.format = c2d.format; @@ -59,11 +99,34 @@ static void virgl_cmd_create_resource_3d(VirtIOGPU *g, { struct virtio_gpu_resource_create_3d c3d; struct virgl_renderer_resource_create_args args; +struct virtio_gpu_virgl_resource *res; VIRTIO_GPU_FILL_CMD(c3d); trace_virtio_gpu_cmd_res_create_3d(c3d.resource_id, c3d.format, c3d.width, c3d.height, c3d.depth); +if (c3d.resource_id == 0) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n", + __func__); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = virtio_gpu_virgl_find_resource(g, c3d.resource_id); +if (res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n", + __func__, c3d.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = g_new0(struct virtio_gpu_virgl_resource, 1); +res->base.width = c3d.width; +res->base.height = c3d.height; +res->base.format = c3d.format; +res->base.resource_id = c3d.resource_id; +QTAILQ_INSERT_HEAD(>reslist, >base, next); + args.handle = c3d.resource_id; args.target = c3d.target; args.format = c3d.format; @@ -82,12 +145,21 @@ static void virgl_cmd_resource_unref(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { struct virtio_gpu_resource_unref unref; +struct virtio_gpu_virgl_resource *res; struct iovec *res_iovs = NULL; int num_iovs = 0; VIRTIO_GPU_FILL_CMD(unref); trace_virtio_gpu_cmd_res_unref(unref.resource_id); +res = virtio_gpu_virgl_find_resource(g, unref.resource_id); +if (!res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n", + __func__, unref.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + virgl_renderer_resource_detach_iov(unref.resource_id, _iovs, _iovs); @@ -95,6 +167,10 @@ static void virgl_cmd_resource_unref(VirtIOGPU *g, virtio_gpu_cleanup_mapping_iov(g, res_iovs, num_iovs); } virgl_renderer_resource_unref(unref.resource_id); + +QTAILQ_REMOVE(>reslist, >base, next); + +g_free(res); } static void virgl_cmd_context_create(VirtIOGPU *g, -- 2.44.0
[PATCH v13 01/13] virtio-gpu: Move fence_poll timer to VirtIOGPUGL
Move fence_poll timer to VirtIOGPUGL for consistency with cmdq_resume_bh that are used only by GL device. Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 8 +--- include/hw/virtio/virtio-gpu.h | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 9f34d0e6619c..7239a9f8e066 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -594,11 +594,12 @@ static void virtio_gpu_print_stats(void *opaque) static void virtio_gpu_fence_poll(void *opaque) { VirtIOGPU *g = opaque; +VirtIOGPUGL *gl = VIRTIO_GPU_GL(g); virgl_renderer_poll(); virtio_gpu_process_cmdq(g); if (!QTAILQ_EMPTY(>cmdq) || !QTAILQ_EMPTY(>fenceq)) { -timer_mod(g->fence_poll, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 10); +timer_mod(gl->fence_poll, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 10); } } @@ -626,6 +627,7 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) { int ret; uint32_t flags = 0; +VirtIOGPUGL *gl = VIRTIO_GPU_GL(g); #if VIRGL_RENDERER_CALLBACKS_VERSION >= 4 if (qemu_egl_display) { @@ -645,8 +647,8 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) return ret; } -g->fence_poll = timer_new_ms(QEMU_CLOCK_VIRTUAL, - virtio_gpu_fence_poll, g); +gl->fence_poll = timer_new_ms(QEMU_CLOCK_VIRTUAL, + virtio_gpu_fence_poll, g); if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { g->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL, diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 7a59379f5a7a..bc69fd78a440 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -196,7 +196,6 @@ struct VirtIOGPU { uint64_t hostmem; bool processing_cmdq; -QEMUTimer *fence_poll; QEMUTimer *print_stats; uint32_t inflight; @@ -231,6 +230,8 @@ struct VirtIOGPUGL { bool renderer_inited; bool renderer_reset; + +QEMUTimer *fence_poll; }; struct VhostUserGPU { -- 2.44.0
Re: [PATCH v12 00/13] Support blob memory and venus on qemu
On 5/27/24 02:46, Dmitry Osipenko wrote: > On 5/22/24 12:00, Alex Bennée wrote: >> Dmitry Osipenko writes: >> >>> On 5/21/24 17:57, Alex Bennée wrote: >>>> Alex Bennée writes: >>>> >>>>> Dmitry Osipenko writes: >>>>> >>>>>> Hello, >>>>>> >>>>>> This series enables Vulkan Venus context support on virtio-gpu. >>>>>> >>>>>> All virglrender and almost all Linux kernel prerequisite changes >>>>>> needed by Venus are already in upstream. For kernel there is a pending >>>>>> KVM patchset that fixes mapping of compound pages needed for DRM drivers >>>>>> using TTM [1], othewrwise hostmem blob mapping will fail with a KVM error >>>>>> from Qemu. >>>>>> >>>>>> [1] >>>>>> https://lore.kernel.org/kvm/20240229025759.1187910-1-steve...@google.com/ >>>>>> >>>>>> You'll need to use recent Mesa version containing patch that removes >>>>>> dependency on cross-device feature from Venus that isn't supported by >>>>>> Qemu [2]. >>>>>> >>>>>> [2] >>>>>> https://gitlab.freedesktop.org/mesa/mesa/-/commit/087e9a96d13155e26987befae78b6ccbb7ae242b >>>>>> >>>>>> Example Qemu cmdline that enables Venus: >>>>>> >>>>>> qemu-system-x86_64 -device >>>>>> virtio-vga-gl,hostmem=4G,blob=true,venus=true \ >>>>>> -machine q35,accel=kvm,memory-backend=mem1 \ >>>>>> -object memory-backend-memfd,id=mem1,size=8G -m 8G >>>>> >>>>> What is the correct device for non-x86 guests? We have virtio-gpu-gl-pci >>>>> but when doing that I get: >>>>> >>>>> -device virtio-gpu-gl-pci,hostmem=4G,blob=true,venus=true >>>>> qemu-system-aarch64: -device >>>>> virtio-gpu-gl-pci,hostmem=4G,blob=true,venus=true: opengl is not available >>>>> >>>>> According to 37f86af087 (virtio-gpu: move virgl realize + properties): >>>>> >>>>> Drop the virgl property, the virtio-gpu-gl-device has virgl enabled no >>>>> matter what. Just use virtio-gpu-device instead if you don't want >>>>> enable virgl and opengl. This simplifies the logic and reduces the test >>>>> matrix. >>>>> >>>>> but that's not a good solution because that needs virtio-mmio and there >>>>> are reasons to have a PCI device (for one thing no ambiguity about >>>>> discovery). >>>> >>>> Oops my mistake forgetting: >>>> >>>> --display gtk,gl=on >>>> >>>> Although I do see a lot of eglMakeContext failures. >>> >>> Please post the full Qemu cmdline you're using >> >> With: >> >> ./qemu-system-aarch64 \ >>-machine type=virt,virtualization=on,pflash0=rom,pflash1=efivars \ >>-cpu neoverse-n1 \ >>-smp 4 \ >>-accel tcg \ >>-device virtio-net-pci,netdev=unet \ >>-device virtio-scsi-pci \ >>-device scsi-hd,drive=hd \ >>-netdev user,id=unet,hostfwd=tcp::-:22 \ >>-blockdev >> driver=raw,node-name=hd,file.driver=host_device,file.filename=/dev/zen-ssd2/trixie-arm64,discard=unmap >> \ >>-serial mon:stdio \ >>-blockdev >> node-name=rom,driver=file,filename=(pwd)/pc-bios/edk2-aarch64-code.fd,read-only=true >> \ >>-blockdev >> node-name=efivars,driver=file,filename=$HOME/images/qemu-arm64-efivars \ >>-m 8192 \ >>-object memory-backend-memfd,id=mem,size=8G,share=on \ >>-device virtio-gpu-gl-pci,hostmem=4G,blob=true,venus=true \ >>-display gtk,gl=on,show-cursor=on -vga none \ >>-device qemu-xhci -device usb-kbd -device usb-tablet >> >> I get a boot up with a lot of: >> >> >> >> >> (qemu:1545322): Gdk-WARNING **: 09:26:09.470: eglMakeCurrent failed >> >> >> >> (qemu:1545322): Gdk-WARNING **:
Re: [PATCH v12 00/13] Support blob memory and venus on qemu
On 5/22/24 12:00, Alex Bennée wrote: > I get a boot up with a lot of: > (qemu:1545322): Gdk-WARNING **: 09:26:09.470: eglMakeCurrent failed > (qemu:1545322): Gdk-WARNING **: 09:26:09.470: eglMakeCurrent failed > (qemu:1545322): Gdk-WARNING **: 09:26:09.470: eglMakeCurrent failed > (qemu:1545322): Gdk-WARNING **: 09:26:09.470: eglMakeCurrent failed Have same problem with GTK and arm64/UEFI. Something is resetting virtio-gpu device during boot (maybe UEFI fw) and it doesn't work properly with GTK. I'd expect x86 should have same issue, but don't recall x86 having it. -- Best regards, Dmitry
Re: [PATCH v12 03/13] virtio-gpu: Use pkgconfig version to decide which virgl features are available
On 5/22/24 15:48, Alex Bennée wrote: >> New virglrerenderer features were stabilized with release of v1.0.0. >> Presence of symbols in virglrenderer.h doesn't guarantee ABI compatibility >> with pre-release development versions of libvirglerender. Use virglrenderer >> version to decide reliably which virgl features are available. > Is the requirement for 087e9a96d13 (venus: make cross-device optional) > on the host or guest side? Because I can't see its in a tagged version. It's required only on guest side. Mesa 24.2 hasn't been tagged yet. -- Best regards, Dmitry
Re: [PATCH v12 00/13] Support blob memory and venus on qemu
On 5/22/24 12:00, Alex Bennée wrote: > Dmitry Osipenko writes: > >> On 5/21/24 17:57, Alex Bennée wrote: >>> Alex Bennée writes: >>> >>>> Dmitry Osipenko writes: >>>> >>>>> Hello, >>>>> >>>>> This series enables Vulkan Venus context support on virtio-gpu. >>>>> >>>>> All virglrender and almost all Linux kernel prerequisite changes >>>>> needed by Venus are already in upstream. For kernel there is a pending >>>>> KVM patchset that fixes mapping of compound pages needed for DRM drivers >>>>> using TTM [1], othewrwise hostmem blob mapping will fail with a KVM error >>>>> from Qemu. >>>>> >>>>> [1] >>>>> https://lore.kernel.org/kvm/20240229025759.1187910-1-steve...@google.com/ >>>>> >>>>> You'll need to use recent Mesa version containing patch that removes >>>>> dependency on cross-device feature from Venus that isn't supported by >>>>> Qemu [2]. >>>>> >>>>> [2] >>>>> https://gitlab.freedesktop.org/mesa/mesa/-/commit/087e9a96d13155e26987befae78b6ccbb7ae242b >>>>> >>>>> Example Qemu cmdline that enables Venus: >>>>> >>>>> qemu-system-x86_64 -device >>>>> virtio-vga-gl,hostmem=4G,blob=true,venus=true \ >>>>> -machine q35,accel=kvm,memory-backend=mem1 \ >>>>> -object memory-backend-memfd,id=mem1,size=8G -m 8G >>>> >>>> What is the correct device for non-x86 guests? We have virtio-gpu-gl-pci >>>> but when doing that I get: >>>> >>>> -device virtio-gpu-gl-pci,hostmem=4G,blob=true,venus=true >>>> qemu-system-aarch64: -device >>>> virtio-gpu-gl-pci,hostmem=4G,blob=true,venus=true: opengl is not available >>>> >>>> According to 37f86af087 (virtio-gpu: move virgl realize + properties): >>>> >>>> Drop the virgl property, the virtio-gpu-gl-device has virgl enabled no >>>> matter what. Just use virtio-gpu-device instead if you don't want >>>> enable virgl and opengl. This simplifies the logic and reduces the test >>>> matrix. >>>> >>>> but that's not a good solution because that needs virtio-mmio and there >>>> are reasons to have a PCI device (for one thing no ambiguity about >>>> discovery). >>> >>> Oops my mistake forgetting: >>> >>> --display gtk,gl=on >>> >>> Although I do see a lot of eglMakeContext failures. >> >> Please post the full Qemu cmdline you're using > > With: > > ./qemu-system-aarch64 \ >-machine type=virt,virtualization=on,pflash0=rom,pflash1=efivars \ >-cpu neoverse-n1 \ >-smp 4 \ >-accel tcg \ >-device virtio-net-pci,netdev=unet \ >-device virtio-scsi-pci \ >-device scsi-hd,drive=hd \ >-netdev user,id=unet,hostfwd=tcp::-:22 \ >-blockdev > driver=raw,node-name=hd,file.driver=host_device,file.filename=/dev/zen-ssd2/trixie-arm64,discard=unmap > \ >-serial mon:stdio \ >-blockdev > node-name=rom,driver=file,filename=(pwd)/pc-bios/edk2-aarch64-code.fd,read-only=true > \ >-blockdev > node-name=efivars,driver=file,filename=$HOME/images/qemu-arm64-efivars \ >-m 8192 \ >-object memory-backend-memfd,id=mem,size=8G,share=on \ >-device virtio-gpu-gl-pci,hostmem=4G,blob=true,venus=true \ >-display gtk,gl=on,show-cursor=on -vga none \ >-device qemu-xhci -device usb-kbd -device usb-tablet > > I get a boot up with a lot of: > > > > > (qemu:1545322): Gdk-WARNING **: 09:26:09.470: eglMakeCurrent failed > > > > (qemu:1545322): Gdk-WARNING **: 09:26:09.470: eglMakeCurrent failed > > > > (qemu:1545322): Gdk-WARNING **: 09:26:09.470: eglMakeCurrent failed > > > > (qemu:1545322): Gdk-WARNING **: 09:26:09.470:
Re: [PATCH v12 13/13] virtio-gpu: Support Venus context
On 5/23/24 10:18, Manos Pitsidianakis wrote: >> #define virtio_gpu_hostmem_enabled(_cfg) \ >> (_cfg.hostmem > 0) >> +#define virtio_gpu_venus_enabled(_cfg) \ >> + (_cfg.flags & (1 << VIRTIO_GPU_FLAG_VENUS_ENABLED)) >> > > Can we have both venus and rutabaga enabled on the same virtio-gpu > device? How would that work? It seems to me they should be mutually > exclusive. virtio-gpu-gl and virtio-gpu-rutabaga are separate device types. You can't enable venus for rutabaga device because it doesn't support venus and vice versa, Qemu will tell you that flag is invalid. -- Best regards, Dmitry
Re: [PATCH v12 10/13] virtio-gpu: Move fence_poll timer to VirtIOGPUGL
On 5/20/24 06:51, Akihiko Odaki wrote: > On 2024/05/20 6:27, Dmitry Osipenko wrote: >> Move fence_poll timer to VirtIOGPUGL for consistency with cmdq_resume_bh >> that are used only by GL device. >> >> Signed-off-by: Dmitry Osipenko > > Thanks for refacotoring. > > Please move this before "[PATCH v12 01/13] virtio-gpu: Unrealize GL > device" so that you don't have to rewrite code introduced by that patch. I'll improve it all in v13, thank you for the review -- Best regards, Dmitry
Re: [PATCH v12 00/13] Support blob memory and venus on qemu
On 5/21/24 17:57, Alex Bennée wrote: > Alex Bennée writes: > >> Dmitry Osipenko writes: >> >>> Hello, >>> >>> This series enables Vulkan Venus context support on virtio-gpu. >>> >>> All virglrender and almost all Linux kernel prerequisite changes >>> needed by Venus are already in upstream. For kernel there is a pending >>> KVM patchset that fixes mapping of compound pages needed for DRM drivers >>> using TTM [1], othewrwise hostmem blob mapping will fail with a KVM error >>> from Qemu. >>> >>> [1] >>> https://lore.kernel.org/kvm/20240229025759.1187910-1-steve...@google.com/ >>> >>> You'll need to use recent Mesa version containing patch that removes >>> dependency on cross-device feature from Venus that isn't supported by >>> Qemu [2]. >>> >>> [2] >>> https://gitlab.freedesktop.org/mesa/mesa/-/commit/087e9a96d13155e26987befae78b6ccbb7ae242b >>> >>> Example Qemu cmdline that enables Venus: >>> >>> qemu-system-x86_64 -device virtio-vga-gl,hostmem=4G,blob=true,venus=true \ >>> -machine q35,accel=kvm,memory-backend=mem1 \ >>> -object memory-backend-memfd,id=mem1,size=8G -m 8G >> >> What is the correct device for non-x86 guests? We have virtio-gpu-gl-pci >> but when doing that I get: >> >> -device virtio-gpu-gl-pci,hostmem=4G,blob=true,venus=true >> qemu-system-aarch64: -device >> virtio-gpu-gl-pci,hostmem=4G,blob=true,venus=true: opengl is not available >> >> According to 37f86af087 (virtio-gpu: move virgl realize + properties): >> >> Drop the virgl property, the virtio-gpu-gl-device has virgl enabled no >> matter what. Just use virtio-gpu-device instead if you don't want >> enable virgl and opengl. This simplifies the logic and reduces the test >> matrix. >> >> but that's not a good solution because that needs virtio-mmio and there >> are reasons to have a PCI device (for one thing no ambiguity about >> discovery). > > Oops my mistake forgetting: > > --display gtk,gl=on > > Although I do see a lot of eglMakeContext failures. Please post the full Qemu cmdline you're using -- Best regards, Dmitry
[PATCH v12 07/13] virtio-gpu: Support blob scanout using dmabuf fd
From: Robert Beckett Support displaying blob resources by handling SET_SCANOUT_BLOB command. Signed-by: Antonio Caggiano Signed-off-by: Robert Beckett Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 109 + hw/display/virtio-gpu.c| 12 ++-- include/hw/virtio/virtio-gpu.h | 7 +++ meson.build| 1 + 4 files changed, 123 insertions(+), 6 deletions(-) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 612fa86e5f34..7d4d2882a5af 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -17,6 +17,8 @@ #include "trace.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-gpu.h" +#include "hw/virtio/virtio-gpu-bswap.h" +#include "hw/virtio/virtio-gpu-pixman.h" #include "ui/egl-helpers.h" @@ -78,6 +80,7 @@ static void virgl_cmd_create_resource_2d(VirtIOGPU *g, res->base.height = c2d.height; res->base.format = c2d.format; res->base.resource_id = c2d.resource_id; +res->base.dmabuf_fd = -1; QTAILQ_INSERT_HEAD(>reslist, >base, next); args.handle = c2d.resource_id; @@ -125,6 +128,7 @@ static void virgl_cmd_create_resource_3d(VirtIOGPU *g, res->base.height = c3d.height; res->base.format = c3d.format; res->base.resource_id = c3d.resource_id; +res->base.dmabuf_fd = -1; QTAILQ_INSERT_HEAD(>reslist, >base, next); args.handle = c3d.resource_id; @@ -509,6 +513,106 @@ static void virgl_cmd_get_capset(VirtIOGPU *g, g_free(resp); } +#ifdef HAVE_VIRGL_RESOURCE_BLOB +static void virgl_cmd_set_scanout_blob(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ +struct virtio_gpu_framebuffer fb = { 0 }; +struct virgl_renderer_resource_info info; +struct virtio_gpu_virgl_resource *res; +struct virtio_gpu_set_scanout_blob ss; +uint64_t fbend; + +VIRTIO_GPU_FILL_CMD(ss); +virtio_gpu_scanout_blob_bswap(); +trace_virtio_gpu_cmd_set_scanout_blob(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; +} + +if (ss.resource_id == 0) { +virtio_gpu_disable_scanout(g, ss.scanout_id); +return; +} + +if (ss.width < 16 || +ss.height < 16 || +ss.r.x + ss.r.width > ss.width || +ss.r.y + ss.r.height > ss.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__, ss.scanout_id, ss.resource_id, + ss.r.x, ss.r.y, ss.r.width, ss.r.height, + ss.width, ss.height); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; +return; +} + +res = virtio_gpu_virgl_find_resource(g, ss.resource_id); +if (!res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n", + __func__, ss.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} +if (virgl_renderer_resource_get_info(ss.resource_id, )) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not have info %d\n", + __func__, ss.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} +if (res->base.dmabuf_fd < 0) { +res->base.dmabuf_fd = info.fd; +} +if (res->base.dmabuf_fd < 0) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource not backed by dmabuf %d\n", + __func__, ss.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +fb.format = virtio_gpu_get_pixman_format(ss.format); +if (!fb.format) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: pixel format not supported %d\n", + __func__, ss.format); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; +return; +} + +fb.bytes_pp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(fb.format), 8); +fb.width = ss.width; +fb.height = ss.height; +fb.stride = ss.strides[0]; +fb.offset = ss.offsets[0] + ss.r.x * fb.bytes_pp + ss.r.y * fb.stride; + +fbend = fb.offset; +fbend += fb.stride * (ss.r.height - 1); +fbend += fb.bytes_pp * ss.r.width; +if (fbend > res->base.blob_
[PATCH v12 11/13] virtio-gpu: Move print_stats timer to VirtIOGPUGL
Move print_stats timer to VirtIOGPUGL for consistency with cmdq_resume_bh and fence_poll that are used only by GL device. Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 12 +++- include/hw/virtio/virtio-gpu.h | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index c8b25a0f5d7c..a41c4f8e1cef 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -1069,6 +1069,7 @@ static struct virgl_renderer_callbacks virtio_gpu_3d_cbs = { static void virtio_gpu_print_stats(void *opaque) { VirtIOGPU *g = opaque; +VirtIOGPUGL *gl = VIRTIO_GPU_GL(g); if (g->stats.requests) { fprintf(stderr, "stats: vq req %4d, %3d -- 3D %4d (%5d)\n", @@ -1083,7 +1084,7 @@ static void virtio_gpu_print_stats(void *opaque) } else { fprintf(stderr, "stats: idle\r"); } -timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000); +timer_mod(gl->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000); } static void virtio_gpu_fence_poll(void *opaque) @@ -1146,9 +1147,10 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) virtio_gpu_fence_poll, g); if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { -g->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL, - virtio_gpu_print_stats, g); -timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000); +gl->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL, + virtio_gpu_print_stats, g); +timer_mod(gl->print_stats, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000); } gl->cmdq_resume_bh = aio_bh_new(qemu_get_aio_context(), @@ -1175,7 +1177,7 @@ void virtio_gpu_virgl_deinit(VirtIOGPU *g) qemu_bh_delete(gl->cmdq_resume_bh); if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { -timer_free(g->print_stats); +timer_free(gl->print_stats); } timer_free(gl->fence_poll); virgl_renderer_cleanup(NULL); diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 529c34481158..aea559cdacc5 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -195,7 +195,6 @@ struct VirtIOGPU { uint64_t hostmem; bool processing_cmdq; -QEMUTimer *print_stats; uint32_t inflight; struct { @@ -233,6 +232,7 @@ struct VirtIOGPUGL { QEMUBH *cmdq_resume_bh; QEMUTimer *fence_poll; +QEMUTimer *print_stats; }; struct VhostUserGPU { -- 2.44.0
[PATCH v12 02/13] virtio-gpu: Handle virtio_gpu_virgl_init() failure
virtio_gpu_virgl_init() may fail, leading to a further Qemu crash because Qemu assumes it never fails. Check virtio_gpu_virgl_init() return code and don't execute virtio commands on error. Failed virtio_gpu_virgl_init() will result in a timed out virtio commands for a guest OS. Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 15 +-- hw/display/virtio-gpu-virgl.c | 3 +++ include/hw/virtio/virtio-gpu.h | 1 + 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 0c0a8d136954..b353c3193afa 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -29,9 +29,14 @@ static void virtio_gpu_gl_update_cursor_data(VirtIOGPU *g, struct virtio_gpu_scanout *s, uint32_t resource_id) { +VirtIOGPUGL *gl = VIRTIO_GPU_GL(g); uint32_t width, height; uint32_t pixels, *data; +if (!gl->renderer_inited) { +return; +} + data = virgl_renderer_get_cursor_data(resource_id, , ); if (!data) { return; @@ -60,13 +65,18 @@ static void virtio_gpu_gl_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) VirtIOGPU *g = VIRTIO_GPU(vdev); VirtIOGPUGL *gl = VIRTIO_GPU_GL(vdev); struct virtio_gpu_ctrl_command *cmd; +int ret; -if (!virtio_queue_ready(vq)) { +if (!virtio_queue_ready(vq) || gl->renderer_init_failed) { return; } if (!gl->renderer_inited) { -virtio_gpu_virgl_init(g); +ret = virtio_gpu_virgl_init(g); +if (ret) { +gl->renderer_init_failed = true; +return; +} gl->renderer_inited = true; } if (gl->renderer_reset) { @@ -101,6 +111,7 @@ static void virtio_gpu_gl_reset(VirtIODevice *vdev) if (gl->renderer_inited && !gl->renderer_reset) { virtio_gpu_virgl_reset_scanout(g); gl->renderer_reset = true; +gl->renderer_init_failed = false; } } diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 6ba4c24fda1d..bfbc6553e879 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -668,6 +668,9 @@ int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g) void virtio_gpu_virgl_deinit(VirtIOGPU *g) { +if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { +timer_free(g->print_stats); +} timer_free(g->fence_poll); virgl_renderer_cleanup(NULL); } diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 8ece1ec2e98b..236daba24dd2 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -230,6 +230,7 @@ struct VirtIOGPUGL { bool renderer_inited; bool renderer_reset; +bool renderer_init_failed; }; struct VhostUserGPU { -- 2.44.0
[PATCH v12 13/13] virtio-gpu: Support Venus context
From: Antonio Caggiano Request Venus when initializing VirGL and if venus=true flag is set for virtio-gpu-gl device. Signed-off-by: Antonio Caggiano Signed-off-by: Huang Rui Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 2 ++ hw/display/virtio-gpu-virgl.c | 22 ++ hw/display/virtio-gpu.c| 13 + include/hw/virtio/virtio-gpu.h | 3 +++ meson.build| 1 + 5 files changed, 37 insertions(+), 4 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index b8f395be8d2d..2078e74050bb 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -148,6 +148,8 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) static Property virtio_gpu_gl_properties[] = { DEFINE_PROP_BIT("stats", VirtIOGPU, parent_obj.conf.flags, VIRTIO_GPU_FLAG_STATS_ENABLED, false), +DEFINE_PROP_BIT("venus", VirtIOGPU, parent_obj.conf.flags, +VIRTIO_GPU_FLAG_VENUS_ENABLED, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 70e2d28ba966..2e9862dd186a 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -1130,6 +1130,11 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) flags |= VIRGL_RENDERER_D3D11_SHARE_TEXTURE; } #endif +#ifdef VIRGL_RENDERER_VENUS +if (virtio_gpu_venus_enabled(g->parent_obj.conf)) { +flags |= VIRGL_RENDERER_VENUS | VIRGL_RENDERER_RENDER_SERVER; +} +#endif ret = virgl_renderer_init(g, flags, _gpu_3d_cbs); if (ret != 0) { @@ -1161,7 +1166,7 @@ static void virtio_gpu_virgl_add_capset(GArray *capset_ids, uint32_t capset_id) GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g) { -uint32_t capset2_max_ver, capset2_max_size; +uint32_t capset_max_ver, capset_max_size; GArray *capset_ids; capset_ids = g_array_new(false, false, sizeof(uint32_t)); @@ -1170,12 +1175,21 @@ GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g) virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL); virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VIRGL2, - _max_ver, - _max_size); -if (capset2_max_ver) { + _max_ver, + _max_size); +if (capset_max_ver) { virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL2); } +if (virtio_gpu_venus_enabled(g->parent_obj.conf)) { +virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VENUS, + _max_ver, + _max_size); +if (capset_max_size) { +virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VENUS); +} +} + return capset_ids; } diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 052ab493a00b..0518bb858e88 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1491,6 +1491,19 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) #endif } +if (virtio_gpu_venus_enabled(g->parent_obj.conf)) { +#ifdef HAVE_VIRGL_VENUS +if (!virtio_gpu_blob_enabled(g->parent_obj.conf) || +!virtio_gpu_hostmem_enabled(g->parent_obj.conf)) { +error_setg(errp, "venus requires enabled blob and hostmem options"); +return; +} +#else +error_setg(errp, "old virglrenderer, venus unsupported"); +return; +#endif +} + if (!virtio_gpu_base_device_realize(qdev, virtio_gpu_handle_ctrl_cb, virtio_gpu_handle_cursor_cb, diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 7e1fee836802..ec5d7517f141 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -99,6 +99,7 @@ enum virtio_gpu_base_conf_flags { VIRTIO_GPU_FLAG_BLOB_ENABLED, VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED, VIRTIO_GPU_FLAG_RUTABAGA_ENABLED, +VIRTIO_GPU_FLAG_VENUS_ENABLED, }; #define virtio_gpu_virgl_enabled(_cfg) \ @@ -117,6 +118,8 @@ enum virtio_gpu_base_conf_flags { (_cfg.flags & (1 << VIRTIO_GPU_FLAG_RUTABAGA_ENABLED)) #define virtio_gpu_hostmem_enabled(_cfg) \ (_cfg.hostmem > 0) +#define virtio_gpu_venus_enabled(_cfg) \ +(_cfg.flags & (1 << VIRTIO_GPU_FLAG_VENUS_ENABLED)) struct virtio_gpu_base_conf { uint32_t max_outputs; diff --git a/meson.build b/meson.build index 503a7736eda0..5a2b7b660c67 100644 --- a/meson.build +++ b/meson.build @@ -2305,6 +2305,7 @@ if virgl.version().version_compare('>=1.0.0') config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', 1) config_host_data.set('HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS', 1) config_host_data.set('HA
[PATCH v12 08/13] virtio-gpu: Support suspension of commands processing
Check whether command processing has been finished; otherwise, stop processing commands and retry the command again next time. This allows us to support asynchronous execution of non-fenced commands needed for unmapping host blobs safely. Suggested-by: Akihiko Odaki Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu.c | 5 + 1 file changed, 5 insertions(+) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 1e57a53d346c..6c8c7213bafa 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1054,6 +1054,11 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) /* process command */ vgc->process_cmd(g, cmd); +/* command suspended */ +if (!cmd->finished && !(cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE)) { +break; +} + QTAILQ_REMOVE(>cmdq, cmd, next); if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { g->stats.requests++; -- 2.44.0
[PATCH v12 09/13] virtio-gpu: Handle resource blob commands
From: Antonio Caggiano Support BLOB resources creation, mapping and unmapping by calling the new stable virglrenderer 0.10 interface. Only enabled when available and via the blob config. E.g. -device virtio-vga-gl,blob=true Signed-off-by: Antonio Caggiano Signed-off-by: Xenia Ragiadakou Signed-off-by: Huang Rui Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 310 - hw/display/virtio-gpu.c| 4 +- include/hw/virtio/virtio-gpu.h | 2 + 3 files changed, 312 insertions(+), 4 deletions(-) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 7d4d2882a5af..63a5a983aad6 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -26,6 +26,18 @@ struct virtio_gpu_virgl_resource { struct virtio_gpu_simple_resource base; +MemoryRegion *mr; + +/* + * Used by virgl_cmd_resource_unref() to know whether async + * unmapping has been started. Blob can be both mapped/unmapped + * on unref and we shouldn't unmap blob that wasn't mapped in the + * first place because it's a error condition. This flag prevents + * performing step 3 of the async unmapping process described in the + * comment to virtio_gpu_virgl_async_unmap_resource_blob() if blob + * wasn't mapped in the first place on unref. + */ +bool async_unmap_in_progress; }; static struct virtio_gpu_virgl_resource * @@ -49,6 +61,128 @@ virgl_get_egl_display(G_GNUC_UNUSED void *cookie) } #endif +#ifdef HAVE_VIRGL_RESOURCE_BLOB +struct virtio_gpu_virgl_hostmem_region { +MemoryRegion mr; +struct VirtIOGPU *g; +struct virtio_gpu_virgl_resource *res; +}; + +static void virtio_gpu_virgl_resume_cmdq_bh(void *opaque) +{ +VirtIOGPU *g = opaque; + +virtio_gpu_process_cmdq(g); +} + +static void virtio_gpu_virgl_hostmem_region_free(void *obj) +{ +MemoryRegion *mr = MEMORY_REGION(obj); +struct virtio_gpu_virgl_hostmem_region *vmr; +VirtIOGPUBase *b; +VirtIOGPUGL *gl; + +vmr = container_of(mr, struct virtio_gpu_virgl_hostmem_region, mr); +vmr->res->mr = NULL; + +b = VIRTIO_GPU_BASE(vmr->g); +b->renderer_blocked--; + +/* + * memory_region_unref() is executed from RCU thread context, while + * virglrenderer works only on the main-loop thread that's holding GL + * context. + */ +gl = VIRTIO_GPU_GL(vmr->g); +qemu_bh_schedule(gl->cmdq_resume_bh); +g_free(vmr); +} + +static int +virtio_gpu_virgl_map_resource_blob(VirtIOGPU *g, + struct virtio_gpu_virgl_resource *res, + uint64_t offset) +{ +struct virtio_gpu_virgl_hostmem_region *vmr; +VirtIOGPUBase *b = VIRTIO_GPU_BASE(g); +MemoryRegion *mr; +uint64_t size; +void *data; +int ret; + +if (!virtio_gpu_hostmem_enabled(b->conf)) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: hostmem disabled\n", __func__); +return -EOPNOTSUPP; +} + +ret = virgl_renderer_resource_map(res->base.resource_id, , ); +if (ret) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map virgl resource: %s\n", + __func__, strerror(-ret)); +return ret; +} + +vmr = g_new0(struct virtio_gpu_virgl_hostmem_region, 1); +vmr->res = res; +vmr->g = g; + +mr = >mr; +memory_region_init_ram_ptr(mr, OBJECT(mr), "blob", size, data); +memory_region_add_subregion(>hostmem, offset, mr); +memory_region_set_enabled(mr, true); + +/* + * MR could outlive the resource if MR's reference is held outside of + * virtio-gpu. In order to prevent unmapping resource while MR is alive, + * and thus, making the data pointer invalid, we will block virtio-gpu + * command processing until MR is fully unreferenced and freed. + */ +OBJECT(mr)->free = virtio_gpu_virgl_hostmem_region_free; + +res->mr = mr; + +return 0; +} + +static int +virtio_gpu_virgl_async_unmap_resource_blob(VirtIOGPU *g, + struct virtio_gpu_virgl_resource *res) +{ +VirtIOGPUBase *b = VIRTIO_GPU_BASE(g); +MemoryRegion *mr = res->mr; +int ret; + +/* + * Perform async unmapping in 3 steps: + * + * 1. Begin async unmapping with memory_region_del_subregion() + *and suspend/block cmd processing. + * 2. Wait for res->mr to be freed and cmd processing resumed + *asynchronously by virtio_gpu_virgl_hostmem_region_free(). + * 3. Finish the unmapping with final virgl_renderer_resource_unmap(). + */ +if (mr) { +/* render will be unblocked once MR is freed */ +b->renderer_blocked++; + +/* memory region owns self res->mr object and frees it by itself */ +memory_region_set_enabled(mr, false); +memory_region_del_subregion(>hostmem, mr); +obje
[PATCH v12 06/13] virtio-gpu: Add virgl resource management
From: Huang Rui In a preparation to adding host blobs support to virtio-gpu, add virgl resource management that allows to retrieve resource based on its ID and virgl resource wrapper on top of simple resource that will be contain fields specific to virgl. Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 76 +++ 1 file changed, 76 insertions(+) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index fc667559cc41..612fa86e5f34 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -22,6 +22,23 @@ #include +struct virtio_gpu_virgl_resource { +struct virtio_gpu_simple_resource base; +}; + +static struct virtio_gpu_virgl_resource * +virtio_gpu_virgl_find_resource(VirtIOGPU *g, uint32_t resource_id) +{ +struct virtio_gpu_simple_resource *res; + +res = virtio_gpu_find_resource(g, resource_id); +if (!res) { +return NULL; +} + +return container_of(res, struct virtio_gpu_virgl_resource, base); +} + #if VIRGL_RENDERER_CALLBACKS_VERSION >= 4 static void * virgl_get_egl_display(G_GNUC_UNUSED void *cookie) @@ -35,11 +52,34 @@ static void virgl_cmd_create_resource_2d(VirtIOGPU *g, { struct virtio_gpu_resource_create_2d c2d; struct virgl_renderer_resource_create_args args; +struct virtio_gpu_virgl_resource *res; VIRTIO_GPU_FILL_CMD(c2d); trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format, c2d.width, c2d.height); +if (c2d.resource_id == 0) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n", + __func__); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = virtio_gpu_virgl_find_resource(g, c2d.resource_id); +if (res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n", + __func__, c2d.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = g_new0(struct virtio_gpu_virgl_resource, 1); +res->base.width = c2d.width; +res->base.height = c2d.height; +res->base.format = c2d.format; +res->base.resource_id = c2d.resource_id; +QTAILQ_INSERT_HEAD(>reslist, >base, next); + args.handle = c2d.resource_id; args.target = 2; args.format = c2d.format; @@ -59,11 +99,34 @@ static void virgl_cmd_create_resource_3d(VirtIOGPU *g, { struct virtio_gpu_resource_create_3d c3d; struct virgl_renderer_resource_create_args args; +struct virtio_gpu_virgl_resource *res; VIRTIO_GPU_FILL_CMD(c3d); trace_virtio_gpu_cmd_res_create_3d(c3d.resource_id, c3d.format, c3d.width, c3d.height, c3d.depth); +if (c3d.resource_id == 0) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n", + __func__); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = virtio_gpu_virgl_find_resource(g, c3d.resource_id); +if (res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n", + __func__, c3d.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = g_new0(struct virtio_gpu_virgl_resource, 1); +res->base.width = c3d.width; +res->base.height = c3d.height; +res->base.format = c3d.format; +res->base.resource_id = c3d.resource_id; +QTAILQ_INSERT_HEAD(>reslist, >base, next); + args.handle = c3d.resource_id; args.target = c3d.target; args.format = c3d.format; @@ -82,12 +145,21 @@ static void virgl_cmd_resource_unref(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { struct virtio_gpu_resource_unref unref; +struct virtio_gpu_virgl_resource *res; struct iovec *res_iovs = NULL; int num_iovs = 0; VIRTIO_GPU_FILL_CMD(unref); trace_virtio_gpu_cmd_res_unref(unref.resource_id); +res = virtio_gpu_virgl_find_resource(g, unref.resource_id); +if (!res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n", + __func__, unref.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + virgl_renderer_resource_detach_iov(unref.resource_id, _iovs, _iovs); @@ -95,6 +167,10 @@ static void virgl_cmd_resource_unref(VirtIOGPU *g, virtio_gpu_cleanup_mapping_iov(g, res_iovs, num_iovs); } virgl_renderer_resource_unref(unref.resource_id); + +QTAILQ_REMOVE(>reslist, >base, next); + +g_free(res); } static void virgl_cmd_context_create(VirtIOGPU *g, -- 2.44.0
[PATCH v12 01/13] virtio-gpu: Unrealize GL device
Even though GL GPU doesn't support hotplugging today, free virgl resources when GL device is unrealized. For consistency. Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 11 +++ hw/display/virtio-gpu-virgl.c | 6 ++ include/hw/virtio/virtio-gpu.h | 1 + 3 files changed, 18 insertions(+) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index e06be60dfbfc..0c0a8d136954 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -136,6 +136,16 @@ static Property virtio_gpu_gl_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static void virtio_gpu_gl_device_unrealize(DeviceState *qdev) +{ +VirtIOGPU *g = VIRTIO_GPU(qdev); +VirtIOGPUGL *gl = VIRTIO_GPU_GL(qdev); + +if (gl->renderer_inited) { +virtio_gpu_virgl_deinit(g); +} +} + static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -149,6 +159,7 @@ static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) vgc->update_cursor_data = virtio_gpu_gl_update_cursor_data; vdc->realize = virtio_gpu_gl_device_realize; +vdc->unrealize = virtio_gpu_gl_device_unrealize; vdc->reset = virtio_gpu_gl_reset; device_class_set_props(dc, virtio_gpu_gl_properties); } diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 9f34d0e6619c..6ba4c24fda1d 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -665,3 +665,9 @@ int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g) return capset2_max_ver ? 2 : 1; } + +void virtio_gpu_virgl_deinit(VirtIOGPU *g) +{ +timer_free(g->fence_poll); +virgl_renderer_cleanup(NULL); +} diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 56d6e821bf04..8ece1ec2e98b 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -336,6 +336,7 @@ void virtio_gpu_virgl_fence_poll(VirtIOGPU *g); void virtio_gpu_virgl_reset_scanout(VirtIOGPU *g); void virtio_gpu_virgl_reset(VirtIOGPU *g); int virtio_gpu_virgl_init(VirtIOGPU *g); +void virtio_gpu_virgl_deinit(VirtIOGPU *g); int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g); #endif -- 2.44.0
[PATCH v12 12/13] virtio-gpu: Register capsets dynamically
From: Pierre-Eric Pelloux-Prayer virtio_gpu_virgl_get_num_capsets will return "num_capsets", but we can't assume that capset_index 1 is always VIRGL2 once we'll support more capsets, like Venus and DRM capsets. Register capsets dynamically to avoid that problem. Signed-off-by: Pierre-Eric Pelloux-Prayer Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 6 -- hw/display/virtio-gpu-virgl.c | 33 + include/hw/virtio/virtio-gpu.h | 4 +++- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 4d0a10070ab3..b8f395be8d2d 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -135,8 +135,8 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) } g->parent_obj.conf.flags |= (1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED); -VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = -virtio_gpu_virgl_get_num_capsets(g); +g->capset_ids = virtio_gpu_virgl_get_capsets(g); +VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = g->capset_ids->len; #ifdef HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED; @@ -159,6 +159,8 @@ static void virtio_gpu_gl_device_unrealize(DeviceState *qdev) if (gl->renderer_inited) { virtio_gpu_virgl_deinit(g); } + +g_array_unref(g->capset_ids); } static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index a41c4f8e1cef..70e2d28ba966 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -623,19 +623,13 @@ static void virgl_cmd_get_capset_info(VirtIOGPU *g, VIRTIO_GPU_FILL_CMD(info); memset(, 0, sizeof(resp)); -if (info.capset_index == 0) { -resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL; -virgl_renderer_get_cap_set(resp.capset_id, - _max_version, - _max_size); -} else if (info.capset_index == 1) { -resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL2; + +if (info.capset_index < g->capset_ids->len) { +resp.capset_id = g_array_index(g->capset_ids, uint32_t, + info.capset_index); virgl_renderer_get_cap_set(resp.capset_id, _max_version, _max_size); -} else { -resp.capset_max_version = 0; -resp.capset_max_size = 0; } resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO; virtio_gpu_ctrl_response(g, cmd, , sizeof(resp)); @@ -1160,14 +1154,29 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) return 0; } -int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g) +static void virtio_gpu_virgl_add_capset(GArray *capset_ids, uint32_t capset_id) +{ +g_array_append_val(capset_ids, capset_id); +} + +GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g) { uint32_t capset2_max_ver, capset2_max_size; +GArray *capset_ids; + +capset_ids = g_array_new(false, false, sizeof(uint32_t)); + +/* VIRGL is always supported. */ +virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL); + virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VIRGL2, _max_ver, _max_size); +if (capset2_max_ver) { +virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL2); +} -return capset2_max_ver ? 2 : 1; +return capset_ids; } void virtio_gpu_virgl_deinit(VirtIOGPU *g) diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index aea559cdacc5..7e1fee836802 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -208,6 +208,8 @@ struct VirtIOGPU { QTAILQ_HEAD(, VGPUDMABuf) bufs; VGPUDMABuf *primary[VIRTIO_GPU_MAX_SCANOUTS]; } dmabuf; + +GArray *capset_ids; }; struct VirtIOGPUClass { @@ -347,6 +349,6 @@ void virtio_gpu_virgl_reset_scanout(VirtIOGPU *g); void virtio_gpu_virgl_reset(VirtIOGPU *g); int virtio_gpu_virgl_init(VirtIOGPU *g); void virtio_gpu_virgl_deinit(VirtIOGPU *g); -int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g); +GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g); #endif -- 2.44.0
[PATCH v12 03/13] virtio-gpu: Use pkgconfig version to decide which virgl features are available
New virglrerenderer features were stabilized with release of v1.0.0. Presence of symbols in virglrenderer.h doesn't guarantee ABI compatibility with pre-release development versions of libvirglerender. Use virglrenderer version to decide reliably which virgl features are available. Signed-off-by: Dmitry Osipenko --- meson.build | 7 ++- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index a9de71d45064..413ec5179145 100644 --- a/meson.build +++ b/meson.build @@ -2301,11 +2301,8 @@ config_host_data.set('CONFIG_PNG', png.found()) config_host_data.set('CONFIG_VNC', vnc.found()) config_host_data.set('CONFIG_VNC_JPEG', jpeg.found()) config_host_data.set('CONFIG_VNC_SASL', sasl.found()) -if virgl.found() - config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', - cc.has_member('struct virgl_renderer_resource_info_ext', 'd3d_tex2d', - prefix: '#include ', - dependencies: virgl)) +if virgl.version().version_compare('>=1.0.0') + config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', 1) endif config_host_data.set('CONFIG_VIRTFS', have_virtfs) config_host_data.set('CONFIG_VTE', vte.found()) -- 2.44.0
[PATCH v12 10/13] virtio-gpu: Move fence_poll timer to VirtIOGPUGL
Move fence_poll timer to VirtIOGPUGL for consistency with cmdq_resume_bh that are used only by GL device. Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 9 + include/hw/virtio/virtio-gpu.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 63a5a983aad6..c8b25a0f5d7c 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -1089,11 +1089,12 @@ static void virtio_gpu_print_stats(void *opaque) static void virtio_gpu_fence_poll(void *opaque) { VirtIOGPU *g = opaque; +VirtIOGPUGL *gl = VIRTIO_GPU_GL(g); virgl_renderer_poll(); virtio_gpu_process_cmdq(g); if (!QTAILQ_EMPTY(>cmdq) || !QTAILQ_EMPTY(>fenceq)) { -timer_mod(g->fence_poll, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 10); +timer_mod(gl->fence_poll, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 10); } } @@ -1141,8 +1142,8 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) return ret; } -g->fence_poll = timer_new_ms(QEMU_CLOCK_VIRTUAL, - virtio_gpu_fence_poll, g); +gl->fence_poll = timer_new_ms(QEMU_CLOCK_VIRTUAL, + virtio_gpu_fence_poll, g); if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { g->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL, @@ -1176,6 +1177,6 @@ void virtio_gpu_virgl_deinit(VirtIOGPU *g) if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { timer_free(g->print_stats); } -timer_free(g->fence_poll); +timer_free(gl->fence_poll); virgl_renderer_cleanup(NULL); } diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index f3c8014acc80..529c34481158 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -195,7 +195,6 @@ struct VirtIOGPU { uint64_t hostmem; bool processing_cmdq; -QEMUTimer *fence_poll; QEMUTimer *print_stats; uint32_t inflight; @@ -233,6 +232,7 @@ struct VirtIOGPUGL { bool renderer_init_failed; QEMUBH *cmdq_resume_bh; +QEMUTimer *fence_poll; }; struct VhostUserGPU { -- 2.44.0
[PATCH v12 04/13] virtio-gpu: Support context-init feature with virglrenderer
From: Huang Rui Patch "virtio-gpu: CONTEXT_INIT feature" has added the context_init feature flags. Expose this feature and support creating virglrenderer context with flags using context_id if libvirglrenderer is new enough. Originally-by: Antonio Caggiano Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c| 4 hw/display/virtio-gpu-virgl.c | 20 ++-- meson.build | 1 + 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index b353c3193afa..4d0a10070ab3 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -138,6 +138,10 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = virtio_gpu_virgl_get_num_capsets(g); +#ifdef HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS +g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED; +#endif + virtio_gpu_device_realize(qdev, errp); } diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index bfbc6553e879..fc667559cc41 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -106,8 +106,24 @@ static void virgl_cmd_context_create(VirtIOGPU *g, trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id, cc.debug_name); -virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen, - cc.debug_name); +if (cc.context_init) { +if (!virtio_gpu_context_init_enabled(g->parent_obj.conf)) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: context_init disabled", + __func__); +cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; +return; +} + +#ifdef HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS +virgl_renderer_context_create_with_flags(cc.hdr.ctx_id, + cc.context_init, + cc.nlen, + cc.debug_name); +return; +#endif +} + +virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen, cc.debug_name); } static void virgl_cmd_context_destroy(VirtIOGPU *g, diff --git a/meson.build b/meson.build index 413ec5179145..ba0f067484ca 100644 --- a/meson.build +++ b/meson.build @@ -2303,6 +2303,7 @@ config_host_data.set('CONFIG_VNC_JPEG', jpeg.found()) config_host_data.set('CONFIG_VNC_SASL', sasl.found()) if virgl.version().version_compare('>=1.0.0') config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', 1) + config_host_data.set('HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS', 1) endif config_host_data.set('CONFIG_VIRTFS', have_virtfs) config_host_data.set('CONFIG_VTE', vte.found()) -- 2.44.0
[PATCH v12 00/13] Support blob memory and venus on qemu
ue of res->region, to prevent beeing called twice on the same resource. - Add a patch to enable automatic deallocation of memory regions to resolve use-after-free memory corruption with a reference. Antonio Caggiano (2): virtio-gpu: Handle resource blob commands virtio-gpu: Support Venus context Dmitry Osipenko (7): virtio-gpu: Unrealize GL device virtio-gpu: Handle virtio_gpu_virgl_init() failure virtio-gpu: Use pkgconfig version to decide which virgl features are available virtio-gpu: Don't require udmabuf when blobs and virgl are enabled virtio-gpu: Support suspension of commands processing virtio-gpu: Move fence_poll timer to VirtIOGPUGL virtio-gpu: Move print_stats timer to VirtIOGPUGL Huang Rui (2): virtio-gpu: Support context-init feature with virglrenderer virtio-gpu: Add virgl resource management Pierre-Eric Pelloux-Prayer (1): virtio-gpu: Register capsets dynamically Robert Beckett (1): virtio-gpu: Support blob scanout using dmabuf fd hw/display/virtio-gpu-gl.c | 38 ++- hw/display/virtio-gpu-virgl.c | 594 +++-- hw/display/virtio-gpu.c| 35 +- include/hw/virtio/virtio-gpu.h | 22 +- meson.build| 10 +- 5 files changed, 653 insertions(+), 46 deletions(-) -- 2.44.0
[PATCH v12 05/13] virtio-gpu: Don't require udmabuf when blobs and virgl are enabled
The udmabuf usage is mandatory when virgl is disabled and blobs feature enabled in the Qemu machine configuration. If virgl and blobs are enabled, then udmabuf requirement is optional. Since udmabuf isn't widely supported by a popular Linux distros today, let's relax the udmabuf requirement for blobs=on,virgl=on. Now, a full-featured virtio-gpu acceleration is available to Qemu users without a need to have udmabuf available in the system. Reviewed-by: Antonio Caggiano Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Reviewed-by: Marc-André Lureau Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index ae831b6b3e3e..dac272ecadb1 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1472,6 +1472,7 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) if (virtio_gpu_blob_enabled(g->parent_obj.conf)) { if (!virtio_gpu_rutabaga_enabled(g->parent_obj.conf) && +!virtio_gpu_virgl_enabled(g->parent_obj.conf) && !virtio_gpu_have_udmabuf()) { error_setg(errp, "need rutabaga or udmabuf for blob resources"); return; -- 2.44.0
Re: [PATCH v11 08/10] virtio-gpu: Handle resource blob commands
On 5/15/24 20:04, Akihiko Odaki wrote: >> > > VIRTIO_GPU_CMD_RESOURCE_UNREF should also call > virtio_gpu_virgl_async_unmap_resource_blob(). I guess that's the > original intention of having a function for this instead of inlining the > content of this function to virgl_cmd_resource_unmap_blob(). Correct, previous patchset versions unmapped resource on unref. In v11 I dropped unmapping from unref to avoid adding additional `async_unmap_in_progress` flag because normally map/unmap will be balanced by guest anyways. The virtio-gpu spec doesn't tell that resource have to be implicitly unmapped on unref. In a case of Linux guest, it actually will be a bug to unref a mapped resource because guest will continue to map and use the destroyed resource. -- Best regards, Dmitry
Re: [PATCH v11 08/10] virtio-gpu: Handle resource blob commands
On 5/15/24 19:42, Akihiko Odaki wrote: >>> It may be better to actually implement unmapping instead of returning an >>> error for consistency with the iov operation. Apparently crosvm also >>> unmaps blobs with VIRTIO_GPU_CMD_RESOURCE_UNREF. >> >> Then I'll add back `async_unmap_in_progress` because resource can be >> both mapped/unmapped on unref, and we'll need flag to know whether async >> unmapping has been finished to do the final unmapping of the resource. > > Such a situation should be already handled since unmapping in progress > blocks all commands (not just VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB but > literally all, including VIRTIO_GPU_CMD_RESOURCE_UNREF). The async unmapping consists of 3 parts: 1. begin async unmapping with memory_region_del_subregion() and suspend 2. wait for res->mr to be freed and resume 3. finish the unmapping with final virgl_renderer_resource_unmap() Parts 1 and 3 are handled by virtio_gpu_virgl_async_unmap_resource_blob() The VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB is different because we know that blob is mapped in the first place. Hence we can safely perform the part 3, assuming that parts 1/2 has been completed. In case of VIRTIO_GPU_CMD_RESOURCE_UNREF, blob can be unmapped in the first place and we can't do the part 3 because it will error out for unmapped resource since parts 1/2 were not performed. -- Best regards, Dmitry
Re: [PATCH v11 01/10] virtio-gpu: Unrealize GL device
On 5/15/24 19:22, Akihiko Odaki wrote: > On 2024/05/16 1:18, Dmitry Osipenko wrote: >> On 5/13/24 11:44, Akihiko Odaki wrote: >>> On 2024/05/12 3:22, Dmitry Osipenko wrote: >>>> Even though GL GPU doesn't support hotplugging today, free virgl >>>> resources when GL device is unrealized. For consistency. >>>> >>>> Signed-off-by: Dmitry Osipenko >>>> --- >>>> hw/display/virtio-gpu-gl.c | 11 +++ >>>> hw/display/virtio-gpu-virgl.c | 9 + >>>> include/hw/virtio/virtio-gpu.h | 1 + >>>> 3 files changed, 21 insertions(+) >>>> >>>> diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c >>>> index e06be60dfbfc..0c0a8d136954 100644 >>>> --- a/hw/display/virtio-gpu-gl.c >>>> +++ b/hw/display/virtio-gpu-gl.c >>>> @@ -136,6 +136,16 @@ static Property virtio_gpu_gl_properties[] = { >>>> DEFINE_PROP_END_OF_LIST(), >>>> }; >>>> +static void virtio_gpu_gl_device_unrealize(DeviceState *qdev) >>>> +{ >>>> + VirtIOGPU *g = VIRTIO_GPU(qdev); >>>> + VirtIOGPUGL *gl = VIRTIO_GPU_GL(qdev); >>>> + >>>> + if (gl->renderer_inited) { >>>> + virtio_gpu_virgl_deinit(g); >>>> + } >>>> +} >>>> + >>>> static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) >>>> { >>>> DeviceClass *dc = DEVICE_CLASS(klass); >>>> @@ -149,6 +159,7 @@ static void virtio_gpu_gl_class_init(ObjectClass >>>> *klass, void *data) >>>> vgc->update_cursor_data = virtio_gpu_gl_update_cursor_data; >>>> vdc->realize = virtio_gpu_gl_device_realize; >>>> + vdc->unrealize = virtio_gpu_gl_device_unrealize; >>>> vdc->reset = virtio_gpu_gl_reset; >>>> device_class_set_props(dc, virtio_gpu_gl_properties); >>>> } >>>> diff --git a/hw/display/virtio-gpu-virgl.c >>>> b/hw/display/virtio-gpu-virgl.c >>>> index 9f34d0e6619c..b0500eccf8e0 100644 >>>> --- a/hw/display/virtio-gpu-virgl.c >>>> +++ b/hw/display/virtio-gpu-virgl.c >>>> @@ -665,3 +665,12 @@ int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g) >>>> return capset2_max_ver ? 2 : 1; >>>> } >>>> + >>>> +void virtio_gpu_virgl_deinit(VirtIOGPU *g) >>>> +{ >>>> + if (g->fence_poll) { >>> >>> Isn't g->fence_poll always non-NULL when this function is called? >> >> virtio_gpu_virgl_init() is invoked when first cmd is executed, please >> see virtio_gpu_gl_handle_ctrl() that invokes it. Hence g->fence_poll can >> be NULL. >> > > But it already checks renderer_inited, doesn't it? And I think it's > better to utilize one single flag to represent that virgl is enabled > instead of checking several variables (fence_poll and cmdq_resume_bh in > the future). The virtio_gpu_virgl_init() will have to be changed to do that because virgl_renderer_init() can fail before fence_poll/cmdq_resume_bh are inited. Though, the error returned by virtio_gpu_virgl_init() isn't checked by virtio_gpu_gl_handle_ctrl(), which leads to a further Qemu crash due to fence_poll=NULL. I'll try to improve it all in v12, thanks. -- Best regards, Dmitry
Re: [PATCH v11 08/10] virtio-gpu: Handle resource blob commands
On 5/13/24 12:18, Akihiko Odaki wrote: >> static void virgl_cmd_resource_unref(VirtIOGPU *g, >> - struct virtio_gpu_ctrl_command >> *cmd) >> + struct virtio_gpu_ctrl_command >> *cmd, >> + bool *cmd_suspended) > > This parameter is not used as it returns an error if the resource is > still mapped. Missed to remove it by accident > It may be better to actually implement unmapping instead of returning an > error for consistency with the iov operation. Apparently crosvm also > unmaps blobs with VIRTIO_GPU_CMD_RESOURCE_UNREF. Then I'll add back `async_unmap_in_progress` because resource can be both mapped/unmapped on unref, and we'll need flag to know whether async unmapping has been finished to do the final unmapping of the resource. ... >> + QTAILQ_INSERT_HEAD(>reslist, >base, next); >> + >> + virgl_args.res_handle = cblob.resource_id; >> + virgl_args.ctx_id = cblob.hdr.ctx_id; >> + virgl_args.blob_mem = cblob.blob_mem; >> + virgl_args.blob_id = cblob.blob_id; >> + virgl_args.blob_flags = cblob.blob_flags; >> + virgl_args.size = cblob.size; >> + virgl_args.iovecs = res->base.iov; >> + virgl_args.num_iovs = res->base.iov_cnt; >> + >> + ret = virgl_renderer_resource_create_blob(_args); >> + if (ret) { >> + qemu_log_mask(LOG_GUEST_ERROR, "%s: virgl blob create error: >> %s\n", >> + __func__, strerror(-ret)); >> + cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; > > reslist keeps the stale res even if an error happens. Good catch -- Best regards, Dmitry
Re: [PATCH v11 09/10] virtio-gpu: Register capsets dynamically
On 5/13/24 12:20, Akihiko Odaki wrote: ... >> -int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g) >> +static void virtio_gpu_virgl_add_capset(GArray *capset_ids, uint32_t >> capset_id) >> +{ >> + g_array_append_val(capset_ids, capset_id); >> +} > > Is it worthwhile to have a function for this? It's necessary to have it because g_array_append_val() is actually a macro that takes _id ptr internally. I.e. g_array_append_val(capset_ids, VIRTIO_GPU_CAPSET_VIRGL2) will fail to compile with: /usr/include/glib-2.0/glib/garray.h:66:59: error: lvalue required as unary '&' operand 66 | #define g_array_append_val(a,v) g_array_append_vals (a, &(v), 1) -- Best regards, Dmitry
Re: [PATCH v11 01/10] virtio-gpu: Unrealize GL device
On 5/13/24 11:44, Akihiko Odaki wrote: > On 2024/05/12 3:22, Dmitry Osipenko wrote: >> Even though GL GPU doesn't support hotplugging today, free virgl >> resources when GL device is unrealized. For consistency. >> >> Signed-off-by: Dmitry Osipenko >> --- >> hw/display/virtio-gpu-gl.c | 11 +++ >> hw/display/virtio-gpu-virgl.c | 9 + >> include/hw/virtio/virtio-gpu.h | 1 + >> 3 files changed, 21 insertions(+) >> >> diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c >> index e06be60dfbfc..0c0a8d136954 100644 >> --- a/hw/display/virtio-gpu-gl.c >> +++ b/hw/display/virtio-gpu-gl.c >> @@ -136,6 +136,16 @@ static Property virtio_gpu_gl_properties[] = { >> DEFINE_PROP_END_OF_LIST(), >> }; >> +static void virtio_gpu_gl_device_unrealize(DeviceState *qdev) >> +{ >> + VirtIOGPU *g = VIRTIO_GPU(qdev); >> + VirtIOGPUGL *gl = VIRTIO_GPU_GL(qdev); >> + >> + if (gl->renderer_inited) { >> + virtio_gpu_virgl_deinit(g); >> + } >> +} >> + >> static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) >> { >> DeviceClass *dc = DEVICE_CLASS(klass); >> @@ -149,6 +159,7 @@ static void virtio_gpu_gl_class_init(ObjectClass >> *klass, void *data) >> vgc->update_cursor_data = virtio_gpu_gl_update_cursor_data; >> vdc->realize = virtio_gpu_gl_device_realize; >> + vdc->unrealize = virtio_gpu_gl_device_unrealize; >> vdc->reset = virtio_gpu_gl_reset; >> device_class_set_props(dc, virtio_gpu_gl_properties); >> } >> diff --git a/hw/display/virtio-gpu-virgl.c >> b/hw/display/virtio-gpu-virgl.c >> index 9f34d0e6619c..b0500eccf8e0 100644 >> --- a/hw/display/virtio-gpu-virgl.c >> +++ b/hw/display/virtio-gpu-virgl.c >> @@ -665,3 +665,12 @@ int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g) >> return capset2_max_ver ? 2 : 1; >> } >> + >> +void virtio_gpu_virgl_deinit(VirtIOGPU *g) >> +{ >> + if (g->fence_poll) { > > Isn't g->fence_poll always non-NULL when this function is called? virtio_gpu_virgl_init() is invoked when first cmd is executed, please see virtio_gpu_gl_handle_ctrl() that invokes it. Hence g->fence_poll can be NULL. -- Best regards, Dmitry
[PATCH v11 04/10] virtio-gpu: Don't require udmabuf when blobs and virgl are enabled
The udmabuf usage is mandatory when virgl is disabled and blobs feature enabled in the Qemu machine configuration. If virgl and blobs are enabled, then udmabuf requirement is optional. Since udmabuf isn't widely supported by a popular Linux distros today, let's relax the udmabuf requirement for blobs=on,virgl=on. Now, a full-featured virtio-gpu acceleration is available to Qemu users without a need to have udmabuf available in the system. Reviewed-by: Antonio Caggiano Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Reviewed-by: Marc-André Lureau Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index ae831b6b3e3e..dac272ecadb1 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1472,6 +1472,7 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) if (virtio_gpu_blob_enabled(g->parent_obj.conf)) { if (!virtio_gpu_rutabaga_enabled(g->parent_obj.conf) && +!virtio_gpu_virgl_enabled(g->parent_obj.conf) && !virtio_gpu_have_udmabuf()) { error_setg(errp, "need rutabaga or udmabuf for blob resources"); return; -- 2.44.0
[PATCH v11 02/10] virtio-gpu: Use pkgconfig version to decide which virgl features are available
New virglrerenderer features were stabilized with release of v1.0.0. Presence of symbols in virglrenderer.h doesn't guarantee ABI compatibility with pre-release development versions of libvirglerender. Use virglrenderer version to decide reliably which virgl features are available. Signed-off-by: Dmitry Osipenko --- meson.build | 7 ++- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index 83ae4347c7f9..ca2798dbac37 100644 --- a/meson.build +++ b/meson.build @@ -2286,11 +2286,8 @@ config_host_data.set('CONFIG_PNG', png.found()) config_host_data.set('CONFIG_VNC', vnc.found()) config_host_data.set('CONFIG_VNC_JPEG', jpeg.found()) config_host_data.set('CONFIG_VNC_SASL', sasl.found()) -if virgl.found() - config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', - cc.has_member('struct virgl_renderer_resource_info_ext', 'd3d_tex2d', - prefix: '#include ', - dependencies: virgl)) +if virgl.version().version_compare('>=1.0.0') + config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', 1) endif config_host_data.set('CONFIG_VIRTFS', have_virtfs) config_host_data.set('CONFIG_VTE', vte.found()) -- 2.44.0
[PATCH v11 00/10] Support blob memory and venus on qemu
emory_region_init_ram_ptr() like was suggested by Akihiko Odaki. Incorporated fix suggested by Pierre-Eric to specify the MR name - Dropped the virgl_gpu_resource wrapper, cleaned up and simplified patch that adds blob-cmd support - Fixed improper blob resource removal from resource list on resource_unref that was spotted by Akihiko Odaki - Change order of the blob patches, was suggested by Akihiko Odaki. The cmd_set_scanout_blob support is enabled first - Factored out patch that adds resource management support to virtio-gpu-gl, was requested by Marc-André Lureau - Simplified and improved the UUID support patch, dropped the hash table as we don't need it for now. Moved QemuUUID to virtio_gpu_simple_resource. This all was suggested by Akihiko Odaki and Marc-André Lureau - Dropped console_has_gl() check, suggested by Akihiko Odaki - Reworked Meson cheking of libvirglrender features, made new features available based on virglrender pkgconfig version instead of checking symbols in header. This should fix build error using older virglrender version, reported by Alex Bennée - Made enabling of Venus context configrable via new virtio-gpu device "vulkan=true" flag, suggested by Marc-André Lureau. The flag is disabled by default because it requires blob and hostmem options to be enabled and configured Changes from V5 to V6 - Move macros configurations under virgl.found() and rename HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS. - Handle the case while context_init is disabled. - Enable context_init by default. - Move virtio_gpu_virgl_resource_unmap() into virgl_cmd_resource_unmap_blob(). - Introduce new struct virgl_gpu_resource to store virgl specific members. - Remove erro handling of g_new0, because glib will abort() on OOM. - Set resource uuid as option. - Implement optional subsection of vmstate_virtio_gpu_resource_uuid_state for virtio live migration. - Use g_int_hash/g_int_equal instead of the default - Add scanout_blob function for virtio-gpu-virgl - Resolve the memory leak on virtio-gpu-virgl - Remove the unstable API flags check because virglrenderer is already 1.0 - Squash the render server flag support into "Initialize Venus" Changes from V4 (virtio gpu V4) to V5 - Inverted patch 5 and 6 because we should configure HAVE_VIRGL_CONTEXT_INIT firstly. - Validate owner of memory region to avoid slowing down DMA. - Use memory_region_init_ram_ptr() instead of memory_region_init_ram_device_ptr(). - Adjust sequence to allocate gpu resource before virglrender resource creation - Add virtio migration handling for uuid. - Send kernel patch to define VIRTIO_GPU_CAPSET_VENUS. https://lore.kernel.org/lkml/20230915105918.3763061-1-ray.hu...@amd.com/ - Add meson check to make sure unstable APIs defined from 0.9.0. Changes from V1 to V2 (virtio gpu V4) - Remove unused #include "hw/virtio/virtio-iommu.h" - Add a local function, called virgl_resource_destroy(), that is used to release a vgpu resource on error paths and in resource_unref. - Remove virtio_gpu_virgl_resource_unmap from virtio_gpu_cleanup_mapping(), since this function won't be called on blob resources and also because blob resources are unmapped via virgl_cmd_resource_unmap_blob(). - In virgl_cmd_resource_create_blob(), do proper cleanup in error paths and move QTAILQ_INSERT_HEAD(>reslist, res, next) after the resource has been fully initialized. - Memory region has a different life-cycle from virtio gpu resources i.e. cannot be released synchronously along with the vgpu resource. So, here the field "region" was changed to a pointer and is allocated dynamically when the blob is mapped. Also, since the pointer can be used to indicate whether the blob is mapped, the explicite field "mapped" was removed. - In virgl_cmd_resource_map_blob(), add check on the value of res->region, to prevent beeing called twice on the same resource. - Add a patch to enable automatic deallocation of memory regions to resolve use-after-free memory corruption with a reference. Antonio Caggiano (2): virtio-gpu: Handle resource blob commands virtio-gpu: Support Venus context Dmitry Osipenko (4): virtio-gpu: Unrealize GL device virtio-gpu: Use pkgconfig version to decide which virgl features are available virtio-gpu: Don't require udmabuf when blobs and virgl are enabled virtio-gpu: Support suspension of commands processing Huang Rui (2): virtio-gpu: Support context-init feature with virglrenderer virtio-gpu: Add virgl resource management Pierre-Eric Pelloux-Prayer (1): virtio-gpu: Register capsets dynamically Robert Beckett (1): virtio-gpu: Support blob scanout using dmabuf fd hw/display/virtio-gpu-gl.c | 23 +- hw/display/virtio-gpu-virgl.c | 541 +++-- hw/display/virtio-gpu.c| 35 ++- include/hw/virtio/virtio-gpu.h | 17 +- meson.build| 10 +- 5 files changed, 592 insertions(+), 34 deletions(-) -- 2.44.0
[PATCH v11 06/10] virtio-gpu: Support blob scanout using dmabuf fd
From: Robert Beckett Support displaying blob resources by handling SET_SCANOUT_BLOB command. Signed-by: Antonio Caggiano Signed-off-by: Robert Beckett Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 109 + hw/display/virtio-gpu.c| 12 ++-- include/hw/virtio/virtio-gpu.h | 7 +++ meson.build| 1 + 4 files changed, 123 insertions(+), 6 deletions(-) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index c6c63ca1c373..524f15220b7f 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -17,6 +17,8 @@ #include "trace.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-gpu.h" +#include "hw/virtio/virtio-gpu-bswap.h" +#include "hw/virtio/virtio-gpu-pixman.h" #include "ui/egl-helpers.h" @@ -78,6 +80,7 @@ static void virgl_cmd_create_resource_2d(VirtIOGPU *g, res->base.height = c2d.height; res->base.format = c2d.format; res->base.resource_id = c2d.resource_id; +res->base.dmabuf_fd = -1; QTAILQ_INSERT_HEAD(>reslist, >base, next); args.handle = c2d.resource_id; @@ -125,6 +128,7 @@ static void virgl_cmd_create_resource_3d(VirtIOGPU *g, res->base.height = c3d.height; res->base.format = c3d.format; res->base.resource_id = c3d.resource_id; +res->base.dmabuf_fd = -1; QTAILQ_INSERT_HEAD(>reslist, >base, next); args.handle = c3d.resource_id; @@ -509,6 +513,106 @@ static void virgl_cmd_get_capset(VirtIOGPU *g, g_free(resp); } +#ifdef HAVE_VIRGL_RESOURCE_BLOB +static void virgl_cmd_set_scanout_blob(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ +struct virtio_gpu_framebuffer fb = { 0 }; +struct virgl_renderer_resource_info info; +struct virtio_gpu_virgl_resource *res; +struct virtio_gpu_set_scanout_blob ss; +uint64_t fbend; + +VIRTIO_GPU_FILL_CMD(ss); +virtio_gpu_scanout_blob_bswap(); +trace_virtio_gpu_cmd_set_scanout_blob(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; +} + +if (ss.resource_id == 0) { +virtio_gpu_disable_scanout(g, ss.scanout_id); +return; +} + +if (ss.width < 16 || +ss.height < 16 || +ss.r.x + ss.r.width > ss.width || +ss.r.y + ss.r.height > ss.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__, ss.scanout_id, ss.resource_id, + ss.r.x, ss.r.y, ss.r.width, ss.r.height, + ss.width, ss.height); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; +return; +} + +res = virtio_gpu_virgl_find_resource(g, ss.resource_id); +if (!res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n", + __func__, ss.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} +if (virgl_renderer_resource_get_info(ss.resource_id, )) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not have info %d\n", + __func__, ss.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} +if (res->base.dmabuf_fd < 0) { +res->base.dmabuf_fd = info.fd; +} +if (res->base.dmabuf_fd < 0) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource not backed by dmabuf %d\n", + __func__, ss.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +fb.format = virtio_gpu_get_pixman_format(ss.format); +if (!fb.format) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: pixel format not supported %d\n", + __func__, ss.format); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; +return; +} + +fb.bytes_pp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(fb.format), 8); +fb.width = ss.width; +fb.height = ss.height; +fb.stride = ss.strides[0]; +fb.offset = ss.offsets[0] + ss.r.x * fb.bytes_pp + ss.r.y * fb.stride; + +fbend = fb.offset; +fbend += fb.stride * (ss.r.height - 1); +fbend += fb.bytes_pp * ss.r.width; +if (fbend > res->base.blob_
[PATCH v11 08/10] virtio-gpu: Handle resource blob commands
From: Antonio Caggiano Support BLOB resources creation, mapping and unmapping by calling the new stable virglrenderer 0.10 interface. Only enabled when available and via the blob config. E.g. -device virtio-vga-gl,blob=true Signed-off-by: Antonio Caggiano Signed-off-by: Xenia Ragiadakou Signed-off-by: Huang Rui Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 274 - hw/display/virtio-gpu.c| 4 +- include/hw/virtio/virtio-gpu.h | 2 + 3 files changed, 277 insertions(+), 3 deletions(-) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 524f15220b7f..3f2e406be3a4 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -26,6 +26,7 @@ struct virtio_gpu_virgl_resource { struct virtio_gpu_simple_resource base; +MemoryRegion *mr; }; static struct virtio_gpu_virgl_resource * @@ -49,6 +50,117 @@ virgl_get_egl_display(G_GNUC_UNUSED void *cookie) } #endif +#ifdef HAVE_VIRGL_RESOURCE_BLOB +struct virtio_gpu_virgl_hostmem_region { +MemoryRegion mr; +struct VirtIOGPU *g; +struct virtio_gpu_virgl_resource *res; +}; + +static void virtio_gpu_virgl_resume_cmdq_bh(void *opaque) +{ +VirtIOGPU *g = opaque; + +virtio_gpu_process_cmdq(g); +} + +static void virtio_gpu_virgl_hostmem_region_free(void *obj) +{ +MemoryRegion *mr = MEMORY_REGION(obj); +struct virtio_gpu_virgl_hostmem_region *vmr; +VirtIOGPUBase *b; + +vmr = container_of(mr, struct virtio_gpu_virgl_hostmem_region, mr); +vmr->res->mr = NULL; + +b = VIRTIO_GPU_BASE(vmr->g); +b->renderer_blocked--; + +/* + * memory_region_unref() is executed from RCU thread context, while + * virglrenderer works only on the main-loop thread that's holding GL + * context. + */ +qemu_bh_schedule(vmr->g->cmdq_resume_bh); +g_free(vmr); +} + +static int +virtio_gpu_virgl_map_resource_blob(VirtIOGPU *g, + struct virtio_gpu_virgl_resource *res, + uint64_t offset) +{ +struct virtio_gpu_virgl_hostmem_region *vmr; +VirtIOGPUBase *b = VIRTIO_GPU_BASE(g); +MemoryRegion *mr; +uint64_t size; +void *data; +int ret; + +if (!virtio_gpu_hostmem_enabled(b->conf)) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: hostmem disabled\n", __func__); +return -EOPNOTSUPP; +} + +ret = virgl_renderer_resource_map(res->base.resource_id, , ); +if (ret) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map virgl resource: %s\n", + __func__, strerror(-ret)); +return ret; +} + +vmr = g_new0(struct virtio_gpu_virgl_hostmem_region, 1); +vmr->res = res; +vmr->g = g; + +mr = >mr; +memory_region_init_ram_ptr(mr, OBJECT(mr), "blob", size, data); +memory_region_add_subregion(>hostmem, offset, mr); +memory_region_set_enabled(mr, true); + +/* + * MR could outlive the resource if MR's reference is held outside of + * virtio-gpu. In order to prevent unmapping resource while MR is alive, + * and thus, making the data pointer invalid, we will block virtio-gpu + * command processing until MR is fully unreferenced and freed. + */ +OBJECT(mr)->free = virtio_gpu_virgl_hostmem_region_free; + +res->mr = mr; + +return 0; +} + +static int +virtio_gpu_virgl_async_unmap_resource_blob(VirtIOGPU *g, + struct virtio_gpu_virgl_resource *res) +{ +VirtIOGPUBase *b = VIRTIO_GPU_BASE(g); +MemoryRegion *mr = res->mr; +int ret; + +if (mr) { +/* render will be unblocked once MR is freed */ +b->renderer_blocked++; + +/* memory region owns self res->mr object and frees it by itself */ +memory_region_set_enabled(mr, false); +memory_region_del_subregion(>hostmem, mr); +object_unparent(OBJECT(mr)); +} else { +ret = virgl_renderer_resource_unmap(res->base.resource_id); +if (ret) { +qemu_log_mask(LOG_GUEST_ERROR, + "%s: failed to unmap virgl resource: %s\n", + __func__, strerror(-ret)); +return ret; +} +} + +return 0; +} +#endif /* HAVE_VIRGL_RESOURCE_BLOB */ + static void virgl_cmd_create_resource_2d(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { @@ -146,7 +258,8 @@ static void virgl_cmd_create_resource_3d(VirtIOGPU *g, } static void virgl_cmd_resource_unref(VirtIOGPU *g, - struct virtio_gpu_ctrl_command *cmd) + struct virtio_gpu_ctrl_command *cmd, + bool *cmd_suspended) { struct virtio_gpu_resource_unref unref; struct virtio_gpu_virgl_resou
[PATCH v11 07/10] virtio-gpu: Support suspension of commands processing
Check whether command processing has been finished; otherwise, stop processing commands and retry the command again next time. This allows us to support asynchronous execution of non-fenced commands needed for unmapping host blobs safely. Suggested-by: Akihiko Odaki Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu.c | 5 + 1 file changed, 5 insertions(+) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 1e57a53d346c..6c8c7213bafa 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1054,6 +1054,11 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) /* process command */ vgc->process_cmd(g, cmd); +/* command suspended */ +if (!cmd->finished && !(cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE)) { +break; +} + QTAILQ_REMOVE(>cmdq, cmd, next); if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { g->stats.requests++; -- 2.44.0
[PATCH v11 10/10] virtio-gpu: Support Venus context
From: Antonio Caggiano Request Venus when initializing VirGL and if venus=true flag is set for virtio-gpu-gl device. Signed-off-by: Antonio Caggiano Signed-off-by: Huang Rui Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 2 ++ hw/display/virtio-gpu-virgl.c | 22 ++ hw/display/virtio-gpu.c| 13 + include/hw/virtio/virtio-gpu.h | 3 +++ meson.build| 1 + 5 files changed, 37 insertions(+), 4 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 431fc2881a00..1deb3e64b781 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -137,6 +137,8 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) static Property virtio_gpu_gl_properties[] = { DEFINE_PROP_BIT("stats", VirtIOGPU, parent_obj.conf.flags, VIRTIO_GPU_FLAG_STATS_ENABLED, false), +DEFINE_PROP_BIT("venus", VirtIOGPU, parent_obj.conf.flags, +VIRTIO_GPU_FLAG_VENUS_ENABLED, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 135974431492..f1cad005dd8f 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -1094,6 +1094,11 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) flags |= VIRGL_RENDERER_D3D11_SHARE_TEXTURE; } #endif +#ifdef VIRGL_RENDERER_VENUS +if (virtio_gpu_venus_enabled(g->parent_obj.conf)) { +flags |= VIRGL_RENDERER_VENUS | VIRGL_RENDERER_RENDER_SERVER; +} +#endif ret = virgl_renderer_init(g, flags, _gpu_3d_cbs); if (ret != 0) { @@ -1124,7 +1129,7 @@ static void virtio_gpu_virgl_add_capset(GArray *capset_ids, uint32_t capset_id) GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g) { -uint32_t capset2_max_ver, capset2_max_size; +uint32_t capset_max_ver, capset_max_size; GArray *capset_ids; capset_ids = g_array_new(false, false, sizeof(uint32_t)); @@ -1133,12 +1138,21 @@ GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g) virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL); virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VIRGL2, - _max_ver, - _max_size); -if (capset2_max_ver) { + _max_ver, + _max_size); +if (capset_max_ver) { virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL2); } +if (virtio_gpu_venus_enabled(g->parent_obj.conf)) { +virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VENUS, + _max_ver, + _max_size); +if (capset_max_size) { +virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VENUS); +} +} + return capset_ids; } diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 052ab493a00b..0518bb858e88 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1491,6 +1491,19 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) #endif } +if (virtio_gpu_venus_enabled(g->parent_obj.conf)) { +#ifdef HAVE_VIRGL_VENUS +if (!virtio_gpu_blob_enabled(g->parent_obj.conf) || +!virtio_gpu_hostmem_enabled(g->parent_obj.conf)) { +error_setg(errp, "venus requires enabled blob and hostmem options"); +return; +} +#else +error_setg(errp, "old virglrenderer, venus unsupported"); +return; +#endif +} + if (!virtio_gpu_base_device_realize(qdev, virtio_gpu_handle_ctrl_cb, virtio_gpu_handle_cursor_cb, diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 7bbc6ef268eb..9940bbcbaacc 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -99,6 +99,7 @@ enum virtio_gpu_base_conf_flags { VIRTIO_GPU_FLAG_BLOB_ENABLED, VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED, VIRTIO_GPU_FLAG_RUTABAGA_ENABLED, +VIRTIO_GPU_FLAG_VENUS_ENABLED, }; #define virtio_gpu_virgl_enabled(_cfg) \ @@ -117,6 +118,8 @@ enum virtio_gpu_base_conf_flags { (_cfg.flags & (1 << VIRTIO_GPU_FLAG_RUTABAGA_ENABLED)) #define virtio_gpu_hostmem_enabled(_cfg) \ (_cfg.hostmem > 0) +#define virtio_gpu_venus_enabled(_cfg) \ +(_cfg.flags & (1 << VIRTIO_GPU_FLAG_VENUS_ENABLED)) struct virtio_gpu_base_conf { uint32_t max_outputs; diff --git a/meson.build b/meson.build index 0433ea200dd7..20241931730f 100644 --- a/meson.build +++ b/meson.build @@ -2290,6 +2290,7 @@ if virgl.version().version_compare('>=1.0.0') config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', 1) config_host_data.set('HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS', 1) config_host_data.set('HA
[PATCH v11 05/10] virtio-gpu: Add virgl resource management
From: Huang Rui In a preparation to adding host blobs support to virtio-gpu, add virgl resource management that allows to retrieve resource based on its ID and virgl resource wrapper on top of simple resource that will be contain fields specific to virgl. Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 76 +++ 1 file changed, 76 insertions(+) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 8306961ad502..c6c63ca1c373 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -22,6 +22,23 @@ #include +struct virtio_gpu_virgl_resource { +struct virtio_gpu_simple_resource base; +}; + +static struct virtio_gpu_virgl_resource * +virtio_gpu_virgl_find_resource(VirtIOGPU *g, uint32_t resource_id) +{ +struct virtio_gpu_simple_resource *res; + +res = virtio_gpu_find_resource(g, resource_id); +if (!res) { +return NULL; +} + +return container_of(res, struct virtio_gpu_virgl_resource, base); +} + #if VIRGL_RENDERER_CALLBACKS_VERSION >= 4 static void * virgl_get_egl_display(G_GNUC_UNUSED void *cookie) @@ -35,11 +52,34 @@ static void virgl_cmd_create_resource_2d(VirtIOGPU *g, { struct virtio_gpu_resource_create_2d c2d; struct virgl_renderer_resource_create_args args; +struct virtio_gpu_virgl_resource *res; VIRTIO_GPU_FILL_CMD(c2d); trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format, c2d.width, c2d.height); +if (c2d.resource_id == 0) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n", + __func__); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = virtio_gpu_virgl_find_resource(g, c2d.resource_id); +if (res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n", + __func__, c2d.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = g_new0(struct virtio_gpu_virgl_resource, 1); +res->base.width = c2d.width; +res->base.height = c2d.height; +res->base.format = c2d.format; +res->base.resource_id = c2d.resource_id; +QTAILQ_INSERT_HEAD(>reslist, >base, next); + args.handle = c2d.resource_id; args.target = 2; args.format = c2d.format; @@ -59,11 +99,34 @@ static void virgl_cmd_create_resource_3d(VirtIOGPU *g, { struct virtio_gpu_resource_create_3d c3d; struct virgl_renderer_resource_create_args args; +struct virtio_gpu_virgl_resource *res; VIRTIO_GPU_FILL_CMD(c3d); trace_virtio_gpu_cmd_res_create_3d(c3d.resource_id, c3d.format, c3d.width, c3d.height, c3d.depth); +if (c3d.resource_id == 0) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n", + __func__); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = virtio_gpu_virgl_find_resource(g, c3d.resource_id); +if (res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n", + __func__, c3d.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = g_new0(struct virtio_gpu_virgl_resource, 1); +res->base.width = c3d.width; +res->base.height = c3d.height; +res->base.format = c3d.format; +res->base.resource_id = c3d.resource_id; +QTAILQ_INSERT_HEAD(>reslist, >base, next); + args.handle = c3d.resource_id; args.target = c3d.target; args.format = c3d.format; @@ -82,12 +145,21 @@ static void virgl_cmd_resource_unref(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { struct virtio_gpu_resource_unref unref; +struct virtio_gpu_virgl_resource *res; struct iovec *res_iovs = NULL; int num_iovs = 0; VIRTIO_GPU_FILL_CMD(unref); trace_virtio_gpu_cmd_res_unref(unref.resource_id); +res = virtio_gpu_virgl_find_resource(g, unref.resource_id); +if (!res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n", + __func__, unref.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + virgl_renderer_resource_detach_iov(unref.resource_id, _iovs, _iovs); @@ -95,6 +167,10 @@ static void virgl_cmd_resource_unref(VirtIOGPU *g, virtio_gpu_cleanup_mapping_iov(g, res_iovs, num_iovs); } virgl_renderer_resource_unref(unref.resource_id); + +QTAILQ_REMOVE(>reslist, >base, next); + +g_free(res); } static void virgl_cmd_context_create(VirtIOGPU *g, -- 2.44.0
[PATCH v11 03/10] virtio-gpu: Support context-init feature with virglrenderer
From: Huang Rui Patch "virtio-gpu: CONTEXT_INIT feature" has added the context_init feature flags. Expose this feature and support creating virglrenderer context with flags using context_id if libvirglrenderer is new enough. Originally-by: Antonio Caggiano Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c| 4 hw/display/virtio-gpu-virgl.c | 20 ++-- meson.build | 1 + 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 0c0a8d136954..95806999189e 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -127,6 +127,10 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = virtio_gpu_virgl_get_num_capsets(g); +#ifdef HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS +g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED; +#endif + virtio_gpu_device_realize(qdev, errp); } diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index b0500eccf8e0..8306961ad502 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -106,8 +106,24 @@ static void virgl_cmd_context_create(VirtIOGPU *g, trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id, cc.debug_name); -virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen, - cc.debug_name); +if (cc.context_init) { +if (!virtio_gpu_context_init_enabled(g->parent_obj.conf)) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: context_init disabled", + __func__); +cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; +return; +} + +#ifdef HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS +virgl_renderer_context_create_with_flags(cc.hdr.ctx_id, + cc.context_init, + cc.nlen, + cc.debug_name); +return; +#endif +} + +virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen, cc.debug_name); } static void virgl_cmd_context_destroy(VirtIOGPU *g, diff --git a/meson.build b/meson.build index ca2798dbac37..5448eb17f39b 100644 --- a/meson.build +++ b/meson.build @@ -2288,6 +2288,7 @@ config_host_data.set('CONFIG_VNC_JPEG', jpeg.found()) config_host_data.set('CONFIG_VNC_SASL', sasl.found()) if virgl.version().version_compare('>=1.0.0') config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', 1) + config_host_data.set('HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS', 1) endif config_host_data.set('CONFIG_VIRTFS', have_virtfs) config_host_data.set('CONFIG_VTE', vte.found()) -- 2.44.0
[PATCH v11 09/10] virtio-gpu: Register capsets dynamically
From: Pierre-Eric Pelloux-Prayer virtio_gpu_virgl_get_num_capsets will return "num_capsets", but we can't assume that capset_index 1 is always VIRGL2 once we'll support more capsets, like Venus and DRM capsets. Register capsets dynamically to avoid that problem. Signed-off-by: Pierre-Eric Pelloux-Prayer Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 6 -- hw/display/virtio-gpu-virgl.c | 33 + include/hw/virtio/virtio-gpu.h | 4 +++- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 95806999189e..431fc2881a00 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -124,8 +124,8 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) } g->parent_obj.conf.flags |= (1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED); -VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = -virtio_gpu_virgl_get_num_capsets(g); +g->capset_ids = virtio_gpu_virgl_get_capsets(g); +VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = g->capset_ids->len; #ifdef HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED; @@ -148,6 +148,8 @@ static void virtio_gpu_gl_device_unrealize(DeviceState *qdev) if (gl->renderer_inited) { virtio_gpu_virgl_deinit(g); } + +g_array_unref(g->capset_ids); } static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 3f2e406be3a4..135974431492 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -590,19 +590,13 @@ static void virgl_cmd_get_capset_info(VirtIOGPU *g, VIRTIO_GPU_FILL_CMD(info); memset(, 0, sizeof(resp)); -if (info.capset_index == 0) { -resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL; -virgl_renderer_get_cap_set(resp.capset_id, - _max_version, - _max_size); -} else if (info.capset_index == 1) { -resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL2; + +if (info.capset_index < g->capset_ids->len) { +resp.capset_id = g_array_index(g->capset_ids, uint32_t, + info.capset_index); virgl_renderer_get_cap_set(resp.capset_id, _max_version, _max_size); -} else { -resp.capset_max_version = 0; -resp.capset_max_size = 0; } resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO; virtio_gpu_ctrl_response(g, cmd, , sizeof(resp)); @@ -1123,14 +1117,29 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) return 0; } -int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g) +static void virtio_gpu_virgl_add_capset(GArray *capset_ids, uint32_t capset_id) +{ +g_array_append_val(capset_ids, capset_id); +} + +GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g) { uint32_t capset2_max_ver, capset2_max_size; +GArray *capset_ids; + +capset_ids = g_array_new(false, false, sizeof(uint32_t)); + +/* VIRGL is always supported. */ +virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL); + virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VIRGL2, _max_ver, _max_size); +if (capset2_max_ver) { +virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL2); +} -return capset2_max_ver ? 2 : 1; +return capset_ids; } void virtio_gpu_virgl_deinit(VirtIOGPU *g) diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index c0b0b0eac08b..7bbc6ef268eb 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -212,6 +212,8 @@ struct VirtIOGPU { } dmabuf; QEMUBH *cmdq_resume_bh; + +GArray *capset_ids; }; struct VirtIOGPUClass { @@ -346,6 +348,6 @@ void virtio_gpu_virgl_reset_scanout(VirtIOGPU *g); void virtio_gpu_virgl_reset(VirtIOGPU *g); int virtio_gpu_virgl_init(VirtIOGPU *g); void virtio_gpu_virgl_deinit(VirtIOGPU *g); -int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g); +GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g); #endif -- 2.44.0
[PATCH v11 01/10] virtio-gpu: Unrealize GL device
Even though GL GPU doesn't support hotplugging today, free virgl resources when GL device is unrealized. For consistency. Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 11 +++ hw/display/virtio-gpu-virgl.c | 9 + include/hw/virtio/virtio-gpu.h | 1 + 3 files changed, 21 insertions(+) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index e06be60dfbfc..0c0a8d136954 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -136,6 +136,16 @@ static Property virtio_gpu_gl_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static void virtio_gpu_gl_device_unrealize(DeviceState *qdev) +{ +VirtIOGPU *g = VIRTIO_GPU(qdev); +VirtIOGPUGL *gl = VIRTIO_GPU_GL(qdev); + +if (gl->renderer_inited) { +virtio_gpu_virgl_deinit(g); +} +} + static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -149,6 +159,7 @@ static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) vgc->update_cursor_data = virtio_gpu_gl_update_cursor_data; vdc->realize = virtio_gpu_gl_device_realize; +vdc->unrealize = virtio_gpu_gl_device_unrealize; vdc->reset = virtio_gpu_gl_reset; device_class_set_props(dc, virtio_gpu_gl_properties); } diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 9f34d0e6619c..b0500eccf8e0 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -665,3 +665,12 @@ int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g) return capset2_max_ver ? 2 : 1; } + +void virtio_gpu_virgl_deinit(VirtIOGPU *g) +{ +if (g->fence_poll) { +timer_free(g->fence_poll); +} + +virgl_renderer_cleanup(NULL); +} diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index ed44cdad6b34..b657187159d9 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -336,6 +336,7 @@ void virtio_gpu_virgl_fence_poll(VirtIOGPU *g); void virtio_gpu_virgl_reset_scanout(VirtIOGPU *g); void virtio_gpu_virgl_reset(VirtIOGPU *g); int virtio_gpu_virgl_init(VirtIOGPU *g); +void virtio_gpu_virgl_deinit(VirtIOGPU *g); int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g); #endif -- 2.44.0
Re: [PATCH v8 07/11] virtio-gpu: Support suspension of commands processing
On 5/10/24 19:12, Dmitry Osipenko wrote: > On 5/10/24 13:56, Akihiko Odaki wrote: >> On 2024/05/09 21:39, Dmitry Osipenko wrote: >>> On 5/5/24 09:37, Akihiko Odaki wrote: >>>> On 2024/05/02 4:02, Dmitry Osipenko wrote: >>>>> On 4/27/24 08:48, Akihiko Odaki wrote: >>>>>>> >>>>>>> The VIRTIO_GPU_FILL_CMD() macro returns void and this macro is >>>>>>> used by >>>>>>> every function processing commands. Changing process_cmd() to return >>>>>>> bool will require to change all those functions. Not worthwhile to >>>>>>> change it, IMO. > >>>>>>> The flag reflects the exact command status. The !finished + >>>>>>> !suspended >>>>>>> means that command is fenced, i.e. these flags don't have exactly >>>>>>> same >>>>>>> meaning. >>>>>> >>>>>> It is not necessary to change the signature of process_cmd(). You can >>>>>> just refer to !finished. No need to have the suspended flag. >>>>> >>>>> Not sure what you're meaning. The !finished says that cmd is fenced, >>>>> this fenced command is added to the polling list and the fence is >>>>> checked periodically by the fence_poll timer, meanwhile next virgl >>>>> commands are executed in the same time. >>>>> >>>>> This is completely different from the suspension where whole cmd >>>>> processing is blocked until command is resumed. >>>>> >>>> >>>> !finished means you have not sent a response with >>>> virtio_gpu_ctrl_response(). Currently such a situation only happens when >>>> a fence is requested and virtio_gpu_process_cmdq() exploits the fact, >>>> but we are adding a new case without a fence. >>>> >>>> So we need to add code to check if we are fencing or not in >>>> virtio_gpu_process_cmdq(). This can be achieved by evaluating the >>>> following expression as done in virtio_gpu_virgl_process_cmd(): >>>> cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE >>> >>> This works, but then I'll add back the res->async_unmap_in_progress >>> because we need to know whether unmapping has been started. >>> >> >> Isn't the command processing paused when an unmapping operation is in >> progress? > > The virtio_gpu_process_cmdq() continues to be invoked periodically while > unmapping is paused. Should be console doing that, see > virtio_gpu_handle_gl_flushed(). Though, we're now blocking the render, and thus, virtio_gpu_process_cmdq() won't do anything while cmd is paused. I'll check that nothing else is missed and then won't add `async_unmap_in_progress` in v11, thanks! -- Best regards, Dmitry
Re: [PATCH v8 01/11] linux-headers: Update to Linux v6.9-rc3
On 5/10/24 13:46, Alex Bennée wrote: ... >> cp_portable "$tmpdir/include/asm/kvm_para.h" >> "$output/include/standard-headers/asm-$arch" >> +cp_portable "$tmpdir/include/asm/setup_data.h" >> "$output/include/standard-headers/asm-$arch" > > is there a portable setup_data.h? why is it asm-x86 above? Yes, it shouldn't have been asm-x86 ... >> for header in const.h stddef.h kvm.h vfio.h vfio_ccw.h vfio_zdev.h vhost.h \ >>psci.h psp-sev.h userfaultfd.h memfd.h mman.h nvme_ioctl.h \ >> - vduse.h iommufd.h; do >> + vduse.h iommufd.h bits.h; do > > What do we need bits for here? Some header started to include it The kernel headers were already updated in Qemu and I dropped this patch from v9. No need to review it further, thanks! -- Best regards, Dmitry
Re: [PATCH v8 07/11] virtio-gpu: Support suspension of commands processing
On 5/10/24 13:56, Akihiko Odaki wrote: > On 2024/05/09 21:39, Dmitry Osipenko wrote: >> On 5/5/24 09:37, Akihiko Odaki wrote: >>> On 2024/05/02 4:02, Dmitry Osipenko wrote: >>>> On 4/27/24 08:48, Akihiko Odaki wrote: >>>>>> >>>>>> The VIRTIO_GPU_FILL_CMD() macro returns void and this macro is >>>>>> used by >>>>>> every function processing commands. Changing process_cmd() to return >>>>>> bool will require to change all those functions. Not worthwhile to >>>>>> change it, IMO. > >>>>>> The flag reflects the exact command status. The !finished + >>>>>> !suspended >>>>>> means that command is fenced, i.e. these flags don't have exactly >>>>>> same >>>>>> meaning. >>>>> >>>>> It is not necessary to change the signature of process_cmd(). You can >>>>> just refer to !finished. No need to have the suspended flag. >>>> >>>> Not sure what you're meaning. The !finished says that cmd is fenced, >>>> this fenced command is added to the polling list and the fence is >>>> checked periodically by the fence_poll timer, meanwhile next virgl >>>> commands are executed in the same time. >>>> >>>> This is completely different from the suspension where whole cmd >>>> processing is blocked until command is resumed. >>>> >>> >>> !finished means you have not sent a response with >>> virtio_gpu_ctrl_response(). Currently such a situation only happens when >>> a fence is requested and virtio_gpu_process_cmdq() exploits the fact, >>> but we are adding a new case without a fence. >>> >>> So we need to add code to check if we are fencing or not in >>> virtio_gpu_process_cmdq(). This can be achieved by evaluating the >>> following expression as done in virtio_gpu_virgl_process_cmd(): >>> cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE >> >> This works, but then I'll add back the res->async_unmap_in_progress >> because we need to know whether unmapping has been started. >> > > Isn't the command processing paused when an unmapping operation is in > progress? The virtio_gpu_process_cmdq() continues to be invoked periodically while unmapping is paused. Should be console doing that, see virtio_gpu_handle_gl_flushed(). -- Best regards, Dmitry
Re: [PATCH v8 07/11] virtio-gpu: Support suspension of commands processing
On 5/5/24 09:37, Akihiko Odaki wrote: > On 2024/05/02 4:02, Dmitry Osipenko wrote: >> On 4/27/24 08:48, Akihiko Odaki wrote: >>>> >>>> The VIRTIO_GPU_FILL_CMD() macro returns void and this macro is used by >>>> every function processing commands. Changing process_cmd() to return >>>> bool will require to change all those functions. Not worthwhile to >>>> change it, IMO. > >>>> The flag reflects the exact command status. The !finished + !suspended >>>> means that command is fenced, i.e. these flags don't have exactly same >>>> meaning. >>> >>> It is not necessary to change the signature of process_cmd(). You can >>> just refer to !finished. No need to have the suspended flag. >> >> Not sure what you're meaning. The !finished says that cmd is fenced, >> this fenced command is added to the polling list and the fence is >> checked periodically by the fence_poll timer, meanwhile next virgl >> commands are executed in the same time. >> >> This is completely different from the suspension where whole cmd >> processing is blocked until command is resumed. >> > > !finished means you have not sent a response with > virtio_gpu_ctrl_response(). Currently such a situation only happens when > a fence is requested and virtio_gpu_process_cmdq() exploits the fact, > but we are adding a new case without a fence. > > So we need to add code to check if we are fencing or not in > virtio_gpu_process_cmdq(). This can be achieved by evaluating the > following expression as done in virtio_gpu_virgl_process_cmd(): > cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE This works, but then I'll add back the res->async_unmap_in_progress because we need to know whether unmapping has been started. -- Best regards, Dmitry
Re: [PATCH v8 08/11] virtio-gpu: Handle resource blob commands
On 5/5/24 09:47, Akihiko Odaki wrote: > On 2024/05/02 4:20, Dmitry Osipenko wrote: >> On 4/27/24 08:52, Akihiko Odaki wrote: >>> On 2024/04/24 19:30, Dmitry Osipenko wrote: >>>> On 4/19/24 12:18, Akihiko Odaki wrote: >>>>>> @@ -61,6 +61,10 @@ struct virtio_gpu_simple_resource { >>>>>> int dmabuf_fd; >>>>>> uint8_t *remapped; >>>>>> + MemoryRegion *mr; >>>>>> + bool async_unmap_completed; >>>>>> + bool async_unmap_in_progress; >>>>>> + >>>>> >>>>> Don't add fields to virtio_gpu_simple_resource but instead create a >>>>> struct that embeds virtio_gpu_simple_resource in virtio-gpu-virgl.c. >>>> >>>> Please give a justification. I'd rather rename >>>> virtio_gpu_simple_resource s/_simple//. Simple resource already >>>> supports >>>> blob and the added fields are directly related to the blob. Don't see >>>> why another struct is needed. >>>> >>> >>> Because mapping is only implemented in virtio-gpu-gl while blob itself >>> is implemented also in virtio-gpu. >> >> Rutubaga maps blobs and it should do unmapping blobs asynchronously as >> well, AFAICT. >> > > Right. It makes sense to put mr in struct virtio_gpu_simple_resource in > preparation for such a situation. > > Based on this discussion, I think it is fine to put mr either in struct > virtio_gpu_simple_resource or a distinct struct. However if you put mr > in struct virtio_gpu_simple_resource, the logic that manages > MemoryRegion should also be moved to virtio-gpu.c for consistency. Rutabaga uses static MRs. It will either need a different workaround or will have to move to dynamic MRs. I'll keep using distinct struct for now. AFAICT, its a lesser problem for rutabaga because static MR isn't subjected to the dynamic MR UAF problem that virgl has. On the other hand, rutabaga is re-initing already inited static MR object on each new mapping, that looks like a bug and it will need to move to dynamic MRs. -- Best regards, Dmitry
[PATCH v10 06/10] virtio-gpu: Support blob scanout using dmabuf fd
From: Robert Beckett Support displaying blob resources by handling SET_SCANOUT_BLOB command. Signed-by: Antonio Caggiano Signed-off-by: Robert Beckett Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 109 + hw/display/virtio-gpu.c| 12 ++-- include/hw/virtio/virtio-gpu.h | 7 +++ meson.build| 1 + 4 files changed, 123 insertions(+), 6 deletions(-) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index a040324f5024..2fedccb1fc8d 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -17,6 +17,8 @@ #include "trace.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-gpu.h" +#include "hw/virtio/virtio-gpu-bswap.h" +#include "hw/virtio/virtio-gpu-pixman.h" #include "ui/egl-helpers.h" @@ -78,6 +80,7 @@ static void virgl_cmd_create_resource_2d(VirtIOGPU *g, res->base.height = c2d.height; res->base.format = c2d.format; res->base.resource_id = c2d.resource_id; +res->base.dmabuf_fd = -1; QTAILQ_INSERT_HEAD(>reslist, >base, next); args.handle = c2d.resource_id; @@ -125,6 +128,7 @@ static void virgl_cmd_create_resource_3d(VirtIOGPU *g, res->base.height = c3d.height; res->base.format = c3d.format; res->base.resource_id = c3d.resource_id; +res->base.dmabuf_fd = -1; QTAILQ_INSERT_HEAD(>reslist, >base, next); args.handle = c3d.resource_id; @@ -507,6 +511,106 @@ static void virgl_cmd_get_capset(VirtIOGPU *g, g_free(resp); } +#ifdef HAVE_VIRGL_RESOURCE_BLOB +static void virgl_cmd_set_scanout_blob(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ +struct virtio_gpu_framebuffer fb = { 0 }; +struct virgl_renderer_resource_info info; +struct virtio_gpu_virgl_resource *res; +struct virtio_gpu_set_scanout_blob ss; +uint64_t fbend; + +VIRTIO_GPU_FILL_CMD(ss); +virtio_gpu_scanout_blob_bswap(); +trace_virtio_gpu_cmd_set_scanout_blob(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; +} + +if (ss.resource_id == 0) { +virtio_gpu_disable_scanout(g, ss.scanout_id); +return; +} + +if (ss.width < 16 || +ss.height < 16 || +ss.r.x + ss.r.width > ss.width || +ss.r.y + ss.r.height > ss.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__, ss.scanout_id, ss.resource_id, + ss.r.x, ss.r.y, ss.r.width, ss.r.height, + ss.width, ss.height); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; +return; +} + +res = virtio_gpu_virgl_find_resource(g, ss.resource_id); +if (!res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n", + __func__, ss.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} +if (virgl_renderer_resource_get_info(ss.resource_id, )) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not have info %d\n", + __func__, ss.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} +if (res->base.dmabuf_fd < 0) { +res->base.dmabuf_fd = info.fd; +} +if (res->base.dmabuf_fd < 0) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource not backed by dmabuf %d\n", + __func__, ss.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +fb.format = virtio_gpu_get_pixman_format(ss.format); +if (!fb.format) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: pixel format not supported %d\n", + __func__, ss.format); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; +return; +} + +fb.bytes_pp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(fb.format), 8); +fb.width = ss.width; +fb.height = ss.height; +fb.stride = ss.strides[0]; +fb.offset = ss.offsets[0] + ss.r.x * fb.bytes_pp + ss.r.y * fb.stride; + +fbend = fb.offset; +fbend += fb.stride * (ss.r.height - 1); +fbend += fb.bytes_pp * ss.r.width; +if (fbend > res->base.blob_
[PATCH v10 02/10] virtio-gpu: Use pkgconfig version to decide which virgl features are available
New virglrerenderer features were stabilized with release of v1.0.0. Presence of symbols in virglrenderer.h doesn't guarantee ABI compatibility with pre-release development versions of libvirglerender. Use virglrenderer version to decide reliably which virgl features are available. Signed-off-by: Dmitry Osipenko --- meson.build | 7 ++- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index 5db2dbc12ec7..f4a4d71c1978 100644 --- a/meson.build +++ b/meson.build @@ -2286,11 +2286,8 @@ config_host_data.set('CONFIG_PNG', png.found()) config_host_data.set('CONFIG_VNC', vnc.found()) config_host_data.set('CONFIG_VNC_JPEG', jpeg.found()) config_host_data.set('CONFIG_VNC_SASL', sasl.found()) -if virgl.found() - config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', - cc.has_member('struct virgl_renderer_resource_info_ext', 'd3d_tex2d', - prefix: '#include ', - dependencies: virgl)) +if virgl.version().version_compare('>=1.0.0') + config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', 1) endif config_host_data.set('CONFIG_VIRTFS', have_virtfs) config_host_data.set('CONFIG_VTE', vte.found()) -- 2.44.0
[PATCH v10 04/10] virtio-gpu: Don't require udmabuf when blobs and virgl are enabled
The udmabuf usage is mandatory when virgl is disabled and blobs feature enabled in the Qemu machine configuration. If virgl and blobs are enabled, then udmabuf requirement is optional. Since udmabuf isn't widely supported by a popular Linux distros today, let's relax the udmabuf requirement for blobs=on,virgl=on. Now, a full-featured virtio-gpu acceleration is available to Qemu users without a need to have udmabuf available in the system. Reviewed-by: Antonio Caggiano Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Reviewed-by: Marc-André Lureau Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index ae831b6b3e3e..dac272ecadb1 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1472,6 +1472,7 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) if (virtio_gpu_blob_enabled(g->parent_obj.conf)) { if (!virtio_gpu_rutabaga_enabled(g->parent_obj.conf) && +!virtio_gpu_virgl_enabled(g->parent_obj.conf) && !virtio_gpu_have_udmabuf()) { error_setg(errp, "need rutabaga or udmabuf for blob resources"); return; -- 2.44.0
[PATCH v10 08/10] virtio-gpu: Handle resource blob commands
From: Antonio Caggiano Support BLOB resources creation, mapping and unmapping by calling the new stable virglrenderer 0.10 interface. Only enabled when available and via the blob config. E.g. -device virtio-vga-gl,blob=true Signed-off-by: Antonio Caggiano Signed-off-by: Xenia Ragiadakou Signed-off-by: Huang Rui Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 266 + hw/display/virtio-gpu.c| 4 +- include/hw/virtio/virtio-gpu.h | 2 + 3 files changed, 271 insertions(+), 1 deletion(-) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index dc2b5a496630..d92c58b77865 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -26,6 +26,7 @@ struct virtio_gpu_virgl_resource { struct virtio_gpu_simple_resource base; +MemoryRegion *mr; }; static struct virtio_gpu_virgl_resource * @@ -49,6 +50,114 @@ virgl_get_egl_display(G_GNUC_UNUSED void *cookie) } #endif +#ifdef HAVE_VIRGL_RESOURCE_BLOB +struct virtio_gpu_virgl_hostmem_region { +MemoryRegion mr; +struct VirtIOGPU *g; +struct virtio_gpu_virgl_resource *res; +}; + +static void virtio_gpu_virgl_resume_cmdq_bh(void *opaque) +{ +VirtIOGPU *g = opaque; + +virtio_gpu_process_cmdq(g); +} + +static void virtio_gpu_virgl_hostmem_region_free(void *obj) +{ +MemoryRegion *mr = MEMORY_REGION(obj); +struct virtio_gpu_virgl_hostmem_region *vmr; +VirtIOGPUBase *b; + +vmr = container_of(mr, struct virtio_gpu_virgl_hostmem_region, mr); +vmr->res->mr = NULL; + +b = VIRTIO_GPU_BASE(vmr->g); +b->renderer_blocked--; + +/* + * memory_region_unref() is executed from RCU thread context, while + * virglrenderer works only on the main-loop thread that's holding GL + * context. + */ +qemu_bh_schedule(vmr->g->cmdq_resume_bh); +g_free(vmr); +} + +static int +virtio_gpu_virgl_map_resource_blob(VirtIOGPU *g, + struct virtio_gpu_virgl_resource *res, + uint64_t offset) +{ +struct virtio_gpu_virgl_hostmem_region *vmr; +VirtIOGPUBase *b = VIRTIO_GPU_BASE(g); +MemoryRegion *mr; +uint64_t size; +void *data; +int ret; + +if (!virtio_gpu_hostmem_enabled(b->conf)) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: hostmem disabled\n", __func__); +return -EOPNOTSUPP; +} + +ret = virgl_renderer_resource_map(res->base.resource_id, , ); +if (ret) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map virgl resource: %s\n", + __func__, strerror(-ret)); +return ret; +} + +vmr = g_new0(struct virtio_gpu_virgl_hostmem_region, 1); +vmr->res = res; +vmr->g = g; + +mr = >mr; +memory_region_init_ram_ptr(mr, OBJECT(mr), "blob", size, data); +memory_region_add_subregion(>hostmem, offset, mr); +memory_region_set_enabled(mr, true); + +/* + * Potentially, MR could outlive the resource if MR's reference is held + * outside of virtio-gpu. In order to prevent unmapping resource while + * MR is alive, and thus, making the data pointer invalid, we will block + * virtio-gpu command processing until MR is fully unreferenced and + * released. + */ +OBJECT(mr)->free = virtio_gpu_virgl_hostmem_region_free; + +res->mr = mr; + +return 0; +} + +static void +virtio_gpu_virgl_async_unmap_resource_blob(VirtIOGPU *g, + struct virtio_gpu_virgl_resource *res, + bool *cmd_suspended) +{ +VirtIOGPUBase *b = VIRTIO_GPU_BASE(g); +MemoryRegion *mr = res->mr; + +if (mr && *cmd_suspended == false) { +/* render will be unblocked when MR is freed */ +b->renderer_blocked++; + +/* memory region owns self res->mr object and frees it by itself */ +memory_region_set_enabled(mr, false); +memory_region_del_subregion(>hostmem, mr); +object_unparent(OBJECT(mr)); + +*cmd_suspended = true; +} else if (!mr && *cmd_suspended) { +virgl_renderer_resource_unmap(res->base.resource_id); + +*cmd_suspended = false; +} +} +#endif /* HAVE_VIRGL_RESOURCE_BLOB */ + static void virgl_cmd_create_resource_2d(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { @@ -162,6 +271,13 @@ static void virgl_cmd_resource_unref(VirtIOGPU *g, return; } +if (res->mr || cmd->suspended) { +virtio_gpu_virgl_async_unmap_resource_blob(g, res, >suspended); +if (cmd->suspended) { +return; +} +} + virgl_renderer_resource_detach_iov(unref.resource_id, _iovs, _iovs); @@ -
[PATCH v10 01/10] virtio-gpu: Unrealize GL device
Even though GL GPU doesn't support hotplugging today, free virgl resources when GL device is unrealized. For consistency. Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 11 +++ hw/display/virtio-gpu-virgl.c | 9 + include/hw/virtio/virtio-gpu.h | 1 + 3 files changed, 21 insertions(+) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index e06be60dfbfc..0c0a8d136954 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -136,6 +136,16 @@ static Property virtio_gpu_gl_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static void virtio_gpu_gl_device_unrealize(DeviceState *qdev) +{ +VirtIOGPU *g = VIRTIO_GPU(qdev); +VirtIOGPUGL *gl = VIRTIO_GPU_GL(qdev); + +if (gl->renderer_inited) { +virtio_gpu_virgl_deinit(g); +} +} + static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -149,6 +159,7 @@ static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) vgc->update_cursor_data = virtio_gpu_gl_update_cursor_data; vdc->realize = virtio_gpu_gl_device_realize; +vdc->unrealize = virtio_gpu_gl_device_unrealize; vdc->reset = virtio_gpu_gl_reset; device_class_set_props(dc, virtio_gpu_gl_properties); } diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 9f34d0e6619c..b0500eccf8e0 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -665,3 +665,12 @@ int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g) return capset2_max_ver ? 2 : 1; } + +void virtio_gpu_virgl_deinit(VirtIOGPU *g) +{ +if (g->fence_poll) { +timer_free(g->fence_poll); +} + +virgl_renderer_cleanup(NULL); +} diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index ed44cdad6b34..b657187159d9 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -336,6 +336,7 @@ void virtio_gpu_virgl_fence_poll(VirtIOGPU *g); void virtio_gpu_virgl_reset_scanout(VirtIOGPU *g); void virtio_gpu_virgl_reset(VirtIOGPU *g); int virtio_gpu_virgl_init(VirtIOGPU *g); +void virtio_gpu_virgl_deinit(VirtIOGPU *g); int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g); #endif -- 2.44.0
[PATCH v10 07/10] virtio-gpu: Support suspension of commands processing
Add new "suspended" flag to virtio_gpu_ctrl_command telling cmd processor that it should stop processing commands and retry again next time until flag is unset. Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 1 + hw/display/virtio-gpu-rutabaga.c | 1 + hw/display/virtio-gpu-virgl.c| 3 +++ hw/display/virtio-gpu.c | 5 + include/hw/virtio/virtio-gpu.h | 1 + 5 files changed, 11 insertions(+) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 95806999189e..2a9e549ad2e9 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -79,6 +79,7 @@ static void virtio_gpu_gl_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) cmd->vq = vq; cmd->error = 0; cmd->finished = false; +cmd->suspended = false; QTAILQ_INSERT_TAIL(>cmdq, cmd, next); cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); } diff --git a/hw/display/virtio-gpu-rutabaga.c b/hw/display/virtio-gpu-rutabaga.c index 17bf701a2163..b6e84d436fb2 100644 --- a/hw/display/virtio-gpu-rutabaga.c +++ b/hw/display/virtio-gpu-rutabaga.c @@ -1061,6 +1061,7 @@ static void virtio_gpu_rutabaga_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) cmd->vq = vq; cmd->error = 0; cmd->finished = false; +cmd->suspended = false; QTAILQ_INSERT_TAIL(>cmdq, cmd, next); cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); } diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 2fedccb1fc8d..dc2b5a496630 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -687,6 +687,9 @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g, break; } +if (cmd->suspended) { +return; +} if (cmd->finished) { return; } diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 1e57a53d346c..a1bd4d6914c4 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1054,6 +1054,10 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) /* process command */ vgc->process_cmd(g, cmd); +if (cmd->suspended) { +break; +} + QTAILQ_REMOVE(>cmdq, cmd, next); if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { g->stats.requests++; @@ -1113,6 +1117,7 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) cmd->vq = vq; cmd->error = 0; cmd->finished = false; +cmd->suspended = false; QTAILQ_INSERT_TAIL(>cmdq, cmd, next); cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); } diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index ba36497c477f..0c00c303f41b 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -132,6 +132,7 @@ struct virtio_gpu_ctrl_command { struct virtio_gpu_ctrl_hdr cmd_hdr; uint32_t error; bool finished; +bool suspended; QTAILQ_ENTRY(virtio_gpu_ctrl_command) next; }; -- 2.44.0
[PATCH v10 09/10] virtio-gpu: Register capsets dynamically
From: Pierre-Eric Pelloux-Prayer virtio_gpu_virgl_get_num_capsets will return "num_capsets", but we can't assume that capset_index 1 is always VIRGL2 once we'll support more capsets, like Venus and DRM capsets. Register capsets dynamically to avoid that problem. Signed-off-by: Pierre-Eric Pelloux-Prayer Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 6 -- hw/display/virtio-gpu-virgl.c | 33 + include/hw/virtio/virtio-gpu.h | 4 +++- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 2a9e549ad2e9..cd39e0650862 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -125,8 +125,8 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) } g->parent_obj.conf.flags |= (1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED); -VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = -virtio_gpu_virgl_get_num_capsets(g); +g->capset_ids = virtio_gpu_virgl_get_capsets(g); +VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = g->capset_ids->len; #ifdef HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED; @@ -149,6 +149,8 @@ static void virtio_gpu_gl_device_unrealize(DeviceState *qdev) if (gl->renderer_inited) { virtio_gpu_virgl_deinit(g); } + +g_array_unref(g->capset_ids); } static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index d92c58b77865..1babda4efad5 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -585,19 +585,13 @@ static void virgl_cmd_get_capset_info(VirtIOGPU *g, VIRTIO_GPU_FILL_CMD(info); memset(, 0, sizeof(resp)); -if (info.capset_index == 0) { -resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL; -virgl_renderer_get_cap_set(resp.capset_id, - _max_version, - _max_size); -} else if (info.capset_index == 1) { -resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL2; + +if (info.capset_index < g->capset_ids->len) { +resp.capset_id = g_array_index(g->capset_ids, uint32_t, + info.capset_index); virgl_renderer_get_cap_set(resp.capset_id, _max_version, _max_size); -} else { -resp.capset_max_version = 0; -resp.capset_max_size = 0; } resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO; virtio_gpu_ctrl_response(g, cmd, , sizeof(resp)); @@ -1120,14 +1114,29 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) return 0; } -int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g) +static void virtio_gpu_virgl_add_capset(GArray *capset_ids, uint32_t capset_id) +{ +g_array_append_val(capset_ids, capset_id); +} + +GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g) { uint32_t capset2_max_ver, capset2_max_size; +GArray *capset_ids; + +capset_ids = g_array_new(false, false, sizeof(uint32_t)); + +/* VIRGL is always supported. */ +virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL); + virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VIRGL2, _max_ver, _max_size); +if (capset2_max_ver) { +virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL2); +} -return capset2_max_ver ? 2 : 1; +return capset_ids; } void virtio_gpu_virgl_deinit(VirtIOGPU *g) diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index a98847b88087..105308a36865 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -213,6 +213,8 @@ struct VirtIOGPU { } dmabuf; QEMUBH *cmdq_resume_bh; + +GArray *capset_ids; }; struct VirtIOGPUClass { @@ -347,6 +349,6 @@ void virtio_gpu_virgl_reset_scanout(VirtIOGPU *g); void virtio_gpu_virgl_reset(VirtIOGPU *g); int virtio_gpu_virgl_init(VirtIOGPU *g); void virtio_gpu_virgl_deinit(VirtIOGPU *g); -int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g); +GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g); #endif -- 2.44.0
[PATCH v10 03/10] virtio-gpu: Support context-init feature with virglrenderer
From: Huang Rui Patch "virtio-gpu: CONTEXT_INIT feature" has added the context_init feature flags. Expose this feature and support creating virglrenderer context with flags using context_id if libvirglrenderer is new enough. Originally-by: Antonio Caggiano Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c| 4 hw/display/virtio-gpu-virgl.c | 20 ++-- meson.build | 1 + 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 0c0a8d136954..95806999189e 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -127,6 +127,10 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = virtio_gpu_virgl_get_num_capsets(g); +#ifdef HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS +g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED; +#endif + virtio_gpu_device_realize(qdev, errp); } diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index b0500eccf8e0..8306961ad502 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -106,8 +106,24 @@ static void virgl_cmd_context_create(VirtIOGPU *g, trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id, cc.debug_name); -virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen, - cc.debug_name); +if (cc.context_init) { +if (!virtio_gpu_context_init_enabled(g->parent_obj.conf)) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: context_init disabled", + __func__); +cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; +return; +} + +#ifdef HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS +virgl_renderer_context_create_with_flags(cc.hdr.ctx_id, + cc.context_init, + cc.nlen, + cc.debug_name); +return; +#endif +} + +virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen, cc.debug_name); } static void virgl_cmd_context_destroy(VirtIOGPU *g, diff --git a/meson.build b/meson.build index f4a4d71c1978..513cb2ea6d03 100644 --- a/meson.build +++ b/meson.build @@ -2288,6 +2288,7 @@ config_host_data.set('CONFIG_VNC_JPEG', jpeg.found()) config_host_data.set('CONFIG_VNC_SASL', sasl.found()) if virgl.version().version_compare('>=1.0.0') config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', 1) + config_host_data.set('HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS', 1) endif config_host_data.set('CONFIG_VIRTFS', have_virtfs) config_host_data.set('CONFIG_VTE', vte.found()) -- 2.44.0
[PATCH v10 05/10] virtio-gpu: Add virgl resource management
From: Huang Rui In a preparation to adding host blobs support to virtio-gpu, add virgl resource management that allows to retrieve resource based on its ID and virgl resource wrapper on top of simple resource that will be contain fields specific to virgl. Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-virgl.c | 74 +++ 1 file changed, 74 insertions(+) diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 8306961ad502..a040324f5024 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -22,6 +22,23 @@ #include +struct virtio_gpu_virgl_resource { +struct virtio_gpu_simple_resource base; +}; + +static struct virtio_gpu_virgl_resource * +virtio_gpu_virgl_find_resource(VirtIOGPU *g, uint32_t resource_id) +{ +struct virtio_gpu_simple_resource *res; + +res = virtio_gpu_find_resource(g, resource_id); +if (!res) { +return NULL; +} + +return container_of(res, struct virtio_gpu_virgl_resource, base); +} + #if VIRGL_RENDERER_CALLBACKS_VERSION >= 4 static void * virgl_get_egl_display(G_GNUC_UNUSED void *cookie) @@ -35,11 +52,34 @@ static void virgl_cmd_create_resource_2d(VirtIOGPU *g, { struct virtio_gpu_resource_create_2d c2d; struct virgl_renderer_resource_create_args args; +struct virtio_gpu_virgl_resource *res; VIRTIO_GPU_FILL_CMD(c2d); trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format, c2d.width, c2d.height); +if (c2d.resource_id == 0) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n", + __func__); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = virtio_gpu_virgl_find_resource(g, c2d.resource_id); +if (res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n", + __func__, c2d.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = g_new0(struct virtio_gpu_virgl_resource, 1); +res->base.width = c2d.width; +res->base.height = c2d.height; +res->base.format = c2d.format; +res->base.resource_id = c2d.resource_id; +QTAILQ_INSERT_HEAD(>reslist, >base, next); + args.handle = c2d.resource_id; args.target = 2; args.format = c2d.format; @@ -59,11 +99,34 @@ static void virgl_cmd_create_resource_3d(VirtIOGPU *g, { struct virtio_gpu_resource_create_3d c3d; struct virgl_renderer_resource_create_args args; +struct virtio_gpu_virgl_resource *res; VIRTIO_GPU_FILL_CMD(c3d); trace_virtio_gpu_cmd_res_create_3d(c3d.resource_id, c3d.format, c3d.width, c3d.height, c3d.depth); +if (c3d.resource_id == 0) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n", + __func__); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = virtio_gpu_virgl_find_resource(g, c3d.resource_id); +if (res) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n", + __func__, c3d.resource_id); +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + +res = g_new0(struct virtio_gpu_virgl_resource, 1); +res->base.width = c3d.width; +res->base.height = c3d.height; +res->base.format = c3d.format; +res->base.resource_id = c3d.resource_id; +QTAILQ_INSERT_HEAD(>reslist, >base, next); + args.handle = c3d.resource_id; args.target = c3d.target; args.format = c3d.format; @@ -82,12 +145,19 @@ static void virgl_cmd_resource_unref(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { struct virtio_gpu_resource_unref unref; +struct virtio_gpu_virgl_resource *res; struct iovec *res_iovs = NULL; int num_iovs = 0; VIRTIO_GPU_FILL_CMD(unref); trace_virtio_gpu_cmd_res_unref(unref.resource_id); +res = virtio_gpu_virgl_find_resource(g, unref.resource_id); +if (!res) { +cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; +return; +} + virgl_renderer_resource_detach_iov(unref.resource_id, _iovs, _iovs); @@ -95,6 +165,10 @@ static void virgl_cmd_resource_unref(VirtIOGPU *g, virtio_gpu_cleanup_mapping_iov(g, res_iovs, num_iovs); } virgl_renderer_resource_unref(unref.resource_id); + +QTAILQ_REMOVE(>reslist, >base, next); + +g_free(res); } static void virgl_cmd_context_create(VirtIOGPU *g, -- 2.44.0
[PATCH v10 10/10] virtio-gpu: Support Venus context
From: Antonio Caggiano Request Venus when initializing VirGL and if venus=true flag is set for virtio-gpu-gl device. Signed-off-by: Antonio Caggiano Signed-off-by: Huang Rui Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 2 ++ hw/display/virtio-gpu-virgl.c | 22 ++ hw/display/virtio-gpu.c| 13 + include/hw/virtio/virtio-gpu.h | 3 +++ meson.build| 1 + 5 files changed, 37 insertions(+), 4 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index cd39e0650862..f2e4da56d8c4 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -138,6 +138,8 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) static Property virtio_gpu_gl_properties[] = { DEFINE_PROP_BIT("stats", VirtIOGPU, parent_obj.conf.flags, VIRTIO_GPU_FLAG_STATS_ENABLED, false), +DEFINE_PROP_BIT("venus", VirtIOGPU, parent_obj.conf.flags, +VIRTIO_GPU_FLAG_VENUS_ENABLED, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 1babda4efad5..a0a5e5b7a3de 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -1091,6 +1091,11 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) flags |= VIRGL_RENDERER_D3D11_SHARE_TEXTURE; } #endif +#ifdef VIRGL_RENDERER_VENUS +if (virtio_gpu_venus_enabled(g->parent_obj.conf)) { +flags |= VIRGL_RENDERER_VENUS | VIRGL_RENDERER_RENDER_SERVER; +} +#endif ret = virgl_renderer_init(g, flags, _gpu_3d_cbs); if (ret != 0) { @@ -1121,7 +1126,7 @@ static void virtio_gpu_virgl_add_capset(GArray *capset_ids, uint32_t capset_id) GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g) { -uint32_t capset2_max_ver, capset2_max_size; +uint32_t capset_max_ver, capset_max_size; GArray *capset_ids; capset_ids = g_array_new(false, false, sizeof(uint32_t)); @@ -1130,12 +1135,21 @@ GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g) virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL); virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VIRGL2, - _max_ver, - _max_size); -if (capset2_max_ver) { + _max_ver, + _max_size); +if (capset_max_ver) { virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL2); } +if (virtio_gpu_venus_enabled(g->parent_obj.conf)) { +virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VENUS, + _max_ver, + _max_size); +if (capset_max_size) { +virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VENUS); +} +} + return capset_ids; } diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 45c1f2006712..e86326b25a72 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1491,6 +1491,19 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) #endif } +if (virtio_gpu_venus_enabled(g->parent_obj.conf)) { +#ifdef HAVE_VIRGL_VENUS +if (!virtio_gpu_blob_enabled(g->parent_obj.conf) || +!virtio_gpu_hostmem_enabled(g->parent_obj.conf)) { +error_setg(errp, "venus requires enabled blob and hostmem options"); +return; +} +#else +error_setg(errp, "old virglrenderer, venus unsupported"); +return; +#endif +} + if (!virtio_gpu_base_device_realize(qdev, virtio_gpu_handle_ctrl_cb, virtio_gpu_handle_cursor_cb, diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 105308a36865..8b7bbf853fe8 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -99,6 +99,7 @@ enum virtio_gpu_base_conf_flags { VIRTIO_GPU_FLAG_BLOB_ENABLED, VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED, VIRTIO_GPU_FLAG_RUTABAGA_ENABLED, +VIRTIO_GPU_FLAG_VENUS_ENABLED, }; #define virtio_gpu_virgl_enabled(_cfg) \ @@ -117,6 +118,8 @@ enum virtio_gpu_base_conf_flags { (_cfg.flags & (1 << VIRTIO_GPU_FLAG_RUTABAGA_ENABLED)) #define virtio_gpu_hostmem_enabled(_cfg) \ (_cfg.hostmem > 0) +#define virtio_gpu_venus_enabled(_cfg) \ +(_cfg.flags & (1 << VIRTIO_GPU_FLAG_VENUS_ENABLED)) struct virtio_gpu_base_conf { uint32_t max_outputs; diff --git a/meson.build b/meson.build index 9a00e29a80cf..5e59f031b4b7 100644 --- a/meson.build +++ b/meson.build @@ -2290,6 +2290,7 @@ if virgl.version().version_compare('>=1.0.0') config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', 1) config_host_data.set('HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS', 1) config_host_data.set('HA
[PATCH v10 00/10] Support blob memory and venus on qemu
This should fix build error using older virglrender version, reported by Alex Bennée - Made enabling of Venus context configrable via new virtio-gpu device "vulkan=true" flag, suggested by Marc-André Lureau. The flag is disabled by default because it requires blob and hostmem options to be enabled and configured Changes from V5 to V6 - Move macros configurations under virgl.found() and rename HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS. - Handle the case while context_init is disabled. - Enable context_init by default. - Move virtio_gpu_virgl_resource_unmap() into virgl_cmd_resource_unmap_blob(). - Introduce new struct virgl_gpu_resource to store virgl specific members. - Remove erro handling of g_new0, because glib will abort() on OOM. - Set resource uuid as option. - Implement optional subsection of vmstate_virtio_gpu_resource_uuid_state for virtio live migration. - Use g_int_hash/g_int_equal instead of the default - Add scanout_blob function for virtio-gpu-virgl - Resolve the memory leak on virtio-gpu-virgl - Remove the unstable API flags check because virglrenderer is already 1.0 - Squash the render server flag support into "Initialize Venus" Changes from V4 (virtio gpu V4) to V5 - Inverted patch 5 and 6 because we should configure HAVE_VIRGL_CONTEXT_INIT firstly. - Validate owner of memory region to avoid slowing down DMA. - Use memory_region_init_ram_ptr() instead of memory_region_init_ram_device_ptr(). - Adjust sequence to allocate gpu resource before virglrender resource creation - Add virtio migration handling for uuid. - Send kernel patch to define VIRTIO_GPU_CAPSET_VENUS. https://lore.kernel.org/lkml/20230915105918.3763061-1-ray.hu...@amd.com/ - Add meson check to make sure unstable APIs defined from 0.9.0. Changes from V1 to V2 (virtio gpu V4) - Remove unused #include "hw/virtio/virtio-iommu.h" - Add a local function, called virgl_resource_destroy(), that is used to release a vgpu resource on error paths and in resource_unref. - Remove virtio_gpu_virgl_resource_unmap from virtio_gpu_cleanup_mapping(), since this function won't be called on blob resources and also because blob resources are unmapped via virgl_cmd_resource_unmap_blob(). - In virgl_cmd_resource_create_blob(), do proper cleanup in error paths and move QTAILQ_INSERT_HEAD(>reslist, res, next) after the resource has been fully initialized. - Memory region has a different life-cycle from virtio gpu resources i.e. cannot be released synchronously along with the vgpu resource. So, here the field "region" was changed to a pointer and is allocated dynamically when the blob is mapped. Also, since the pointer can be used to indicate whether the blob is mapped, the explicite field "mapped" was removed. - In virgl_cmd_resource_map_blob(), add check on the value of res->region, to prevent beeing called twice on the same resource. - Add a patch to enable automatic deallocation of memory regions to resolve use-after-free memory corruption with a reference. Antonio Caggiano (2): virtio-gpu: Handle resource blob commands virtio-gpu: Support Venus context Dmitry Osipenko (4): virtio-gpu: Unrealize GL device virtio-gpu: Use pkgconfig version to decide which virgl features are available virtio-gpu: Don't require udmabuf when blobs and virgl are enabled virtio-gpu: Support suspension of commands processing Huang Rui (2): virtio-gpu: Support context-init feature with virglrenderer virtio-gpu: Add virgl resource management Pierre-Eric Pelloux-Prayer (1): virtio-gpu: Register capsets dynamically Robert Beckett (1): virtio-gpu: Support blob scanout using dmabuf fd hw/display/virtio-gpu-gl.c | 24 +- hw/display/virtio-gpu-rutabaga.c | 1 + hw/display/virtio-gpu-virgl.c| 534 ++- hw/display/virtio-gpu.c | 35 +- include/hw/virtio/virtio-gpu.h | 18 +- meson.build | 10 +- 6 files changed, 590 insertions(+), 32 deletions(-) -- 2.44.0
Re: [PATCH v9 09/11] virtio-gpu: Register capsets dynamically
On 5/1/24 22:38, Dmitry Osipenko wrote: > On 5/1/24 22:31, Dmitry Osipenko wrote: >> On 4/27/24 10:12, Akihiko Odaki wrote: >>>> int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g) >>>> { >>>> uint32_t capset2_max_ver, capset2_max_size; >>>> + >>>> + if (g->capset_ids) { >>> >>> Move capset_ids initialization to virtio_gpu_virgl_init() to save this >>> conditional. >> >> Capsets are used before virgl is inited. At first guest queries virtio >> device features and then enables virgl only if capset is available. >> While virgl itself is initialized when first virtio command is >> processed. I.e. it's not possible to move to virtio_gpu_virgl_init. > > Though no, capsets aren't part of device features. I'll move it to > virtio_gpu_virgl_init, thanks. > Number of capsets actually is a part of generic virtio device cfg descriptor. Capsets initialization can't be moved without probing capsets twice, i.e. not worthwhile. -- Best regards, Dmitry
Re: [PATCH v9 09/11] virtio-gpu: Register capsets dynamically
On 5/1/24 22:31, Dmitry Osipenko wrote: > On 4/27/24 10:12, Akihiko Odaki wrote: >>> int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g) >>> { >>> uint32_t capset2_max_ver, capset2_max_size; >>> + >>> + if (g->capset_ids) { >> >> Move capset_ids initialization to virtio_gpu_virgl_init() to save this >> conditional. > > Capsets are used before virgl is inited. At first guest queries virtio > device features and then enables virgl only if capset is available. > While virgl itself is initialized when first virtio command is > processed. I.e. it's not possible to move to virtio_gpu_virgl_init. Though no, capsets aren't part of device features. I'll move it to virtio_gpu_virgl_init, thanks. -- Best regards, Dmitry
Re: [PATCH v9 09/11] virtio-gpu: Register capsets dynamically
On 4/27/24 10:12, Akihiko Odaki wrote: >> int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g) >> { >> uint32_t capset2_max_ver, capset2_max_size; >> + >> + if (g->capset_ids) { > > Move capset_ids initialization to virtio_gpu_virgl_init() to save this > conditional. Capsets are used before virgl is inited. At first guest queries virtio device features and then enables virgl only if capset is available. While virgl itself is initialized when first virtio command is processed. I.e. it's not possible to move to virtio_gpu_virgl_init. > capset_ids also needs to be freed when the device gets > unrealized. ACK -- Best regards, Dmitry
Re: [PATCH v8 08/11] virtio-gpu: Handle resource blob commands
On 4/27/24 08:52, Akihiko Odaki wrote: > On 2024/04/24 19:30, Dmitry Osipenko wrote: >> On 4/19/24 12:18, Akihiko Odaki wrote: >>>> @@ -61,6 +61,10 @@ struct virtio_gpu_simple_resource { >>>> int dmabuf_fd; >>>> uint8_t *remapped; >>>> + MemoryRegion *mr; >>>> + bool async_unmap_completed; >>>> + bool async_unmap_in_progress; >>>> + >>> >>> Don't add fields to virtio_gpu_simple_resource but instead create a >>> struct that embeds virtio_gpu_simple_resource in virtio-gpu-virgl.c. >> >> Please give a justification. I'd rather rename >> virtio_gpu_simple_resource s/_simple//. Simple resource already supports >> blob and the added fields are directly related to the blob. Don't see >> why another struct is needed. >> > > Because mapping is only implemented in virtio-gpu-gl while blob itself > is implemented also in virtio-gpu. Rutubaga maps blobs and it should do unmapping blobs asynchronously as well, AFAICT. -- Best regards, Dmitry
Re: [PATCH v8 07/11] virtio-gpu: Support suspension of commands processing
On 4/27/24 08:48, Akihiko Odaki wrote: >> >> The VIRTIO_GPU_FILL_CMD() macro returns void and this macro is used by >> every function processing commands. Changing process_cmd() to return >> bool will require to change all those functions. Not worthwhile to >> change it, IMO. > >> The flag reflects the exact command status. The !finished + !suspended >> means that command is fenced, i.e. these flags don't have exactly same >> meaning. > > It is not necessary to change the signature of process_cmd(). You can > just refer to !finished. No need to have the suspended flag. Not sure what you're meaning. The !finished says that cmd is fenced, this fenced command is added to the polling list and the fence is checked periodically by the fence_poll timer, meanwhile next virgl commands are executed in the same time. This is completely different from the suspension where whole cmd processing is blocked until command is resumed. -- Best regards, Dmitry
[PATCH v9 02/11] virtio-gpu: Support context-init feature with virglrenderer
From: Huang Rui Patch "virtio-gpu: CONTEXT_INIT feature" has added the context_init feature flags. Expose this feature and support creating virglrenderer context with flags using context_id if libvirglrenderer is new enough. Originally-by: Antonio Caggiano Signed-off-by: Huang Rui Reviewed-by: Antonio Caggiano Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c| 4 hw/display/virtio-gpu-virgl.c | 20 ++-- meson.build | 1 + 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index e06be60dfbfc..ba478124e2c2 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -127,6 +127,10 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = virtio_gpu_virgl_get_num_capsets(g); +#ifdef HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS +g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED; +#endif + virtio_gpu_device_realize(qdev, errp); } diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 9f34d0e6619c..ef598d8d23ee 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -106,8 +106,24 @@ static void virgl_cmd_context_create(VirtIOGPU *g, trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id, cc.debug_name); -virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen, - cc.debug_name); +if (cc.context_init) { +if (!virtio_gpu_context_init_enabled(g->parent_obj.conf)) { +qemu_log_mask(LOG_GUEST_ERROR, "%s: context_init disabled", + __func__); +cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; +return; +} + +#ifdef HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS +virgl_renderer_context_create_with_flags(cc.hdr.ctx_id, + cc.context_init, + cc.nlen, + cc.debug_name); +return; +#endif +} + +virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen, cc.debug_name); } static void virgl_cmd_context_destroy(VirtIOGPU *g, diff --git a/meson.build b/meson.build index c6f22f565071..c131db46b2a6 100644 --- a/meson.build +++ b/meson.build @@ -2288,6 +2288,7 @@ config_host_data.set('CONFIG_VNC_JPEG', jpeg.found()) config_host_data.set('CONFIG_VNC_SASL', sasl.found()) if virgl.version().version_compare('>=1.0.0') config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT', 1) + config_host_data.set('HAVE_VIRGL_CONTEXT_CREATE_WITH_FLAGS', 1) endif config_host_data.set('CONFIG_VIRTFS', have_virtfs) config_host_data.set('CONFIG_VTE', vte.found()) -- 2.44.0
[PATCH v9 11/11] migration/virtio: Add virtio-gpu section
Document virtio-gpu migration specifics. Suggested-by: Akihiko Odaki Signed-off-by: Dmitry Osipenko --- docs/devel/migration/virtio.rst | 7 +++ 1 file changed, 7 insertions(+) diff --git a/docs/devel/migration/virtio.rst b/docs/devel/migration/virtio.rst index 611a18b82151..67f5fcfed196 100644 --- a/docs/devel/migration/virtio.rst +++ b/docs/devel/migration/virtio.rst @@ -113,3 +113,10 @@ virtio_load() returned (like e.g. code depending on features). Any extension of the state being migrated should be done in subsections added to the core for compatibility reasons. If transport or device specific state is added, core needs to invoke a callback from the new subsection. + +VirtIO-GPU migration + +VirtIO-GPU doesn't adhere to a common virtio migration scheme. It doesn't +support save/loading of virtio device state, instead it uses generic device +migration management on top of the virtio core to save/load GPU state. +Migration of virgl and rutabaga states not supported. -- 2.44.0