Re: [PATCH v17 00/13] Support blob memory and venus on qemu
On 8/27/24 12:57, Alex Bennée wrote: > 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 or huge pages [1], othewrwise hostmem blob mapping will fail >> with a KVM error from Qemu. >> >> [1] https://lore.kernel.org/all/20240726235234.228822-1-sea...@google.com/ >> >> On guest you'll need to use recent Mesa 24.2+ 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 > > I've expanded the set of working tests so: > > x86 host, Intel GPU > > x86/kvm Trixie guest + latest mesa - works > aarch64/tcg buildroot guest - works > > Aarch64 host, AMD GPU > > x86/tcg Trixies guest + latest mesa - works > aarch64/kvm buildroot guest - works > > As the Aarch64 HW I'm testing on (AVA Devbox) needs additional patches > on top of Sean's series to deal with the busted Altra PCI which I > provide here: > > > https://git.linaro.org/people/alex.bennee/linux.git/log/?h=review/pfn-references-v12-with-altra-tweaks > > Anyway I'll re-state: > > Tested-by: Alex Bennée > > And I think this series is ready to merge once the tree re-opens. Thanks for the update, nice to see that you nailed the ARM problem -- Best regards, Dmitry
[PATCH v17 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 Reviewed-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Tested-by: Alex Bennée Acked-by: Alex Bennée 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 24608338d7ea..5015f17f9242 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1053,6 +1053,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(&g->cmdq, cmd, next); if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { g->stats.requests++; -- 2.45.2
[PATCH v17 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 Reviewed-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Tested-by: Alex Bennée Acked-by: Alex Bennée 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 f2555673a18e..e859c0dff055 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -144,8 +144,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; @@ -177,6 +177,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 b2f4e215a7ad..5a881c58a11d 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -622,19 +622,13 @@ static void virgl_cmd_get_capset_info(VirtIOGPU *g, VIRTIO_GPU_FILL_CMD(info); memset(&resp, 0, sizeof(resp)); -if (info.capset_index == 0) { -resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL; -virgl_renderer_get_cap_set(resp.capset_id, - &resp.capset_max_version, - &resp.capset_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, &resp.capset_max_version, &resp.capset_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, &resp.hdr, sizeof(resp)); @@ -1160,12 +1154,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, &capset2_max_ver, &capset2_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.45.2
[PATCH v17 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 Reviewed-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Tested-by: Alex Bennée Acked-by: Alex Bennée Signed-off-by: Dmitry Osipenko --- docs/system/devices/virtio-gpu.rst | 11 +++ 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 +++ 5 files changed, 49 insertions(+), 4 deletions(-) diff --git a/docs/system/devices/virtio-gpu.rst b/docs/system/devices/virtio-gpu.rst index cb73dd799858..b7eb0fc0e727 100644 --- a/docs/system/devices/virtio-gpu.rst +++ b/docs/system/devices/virtio-gpu.rst @@ -71,6 +71,17 @@ representation back to OpenGL API calls. .. _Gallium3D: https://www.freedesktop.org/wiki/Software/gallium/ .. _virglrenderer: https://gitlab.freedesktop.org/virgl/virglrenderer/ +Translation of Vulkan API calls is supported since release of `virglrenderer`_ +v1.0.0 using `venus`_ protocol. ``Venus`` virtio-gpu capability set ("capset") +requires host blob support (``hostmem`` and ``blob`` fields) and should +be enabled using ``venus`` field. The ``hostmem`` field specifies the size +of virtio-gpu host memory window. This is typically between 256M and 8G. + +.. parsed-literal:: +-device virtio-gpu-gl,hostmem=8G,blob=true,venus=true + +.. _venus: https://gitlab.freedesktop.org/virgl/venus-protocol/ + virtio-gpu rutabaga --- diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index e859c0dff055..7c0e448b4661 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -157,6 +157,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 5a881c58a11d..eedae7357f1a 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -1128,6 +1128,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, &virtio_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,11 +1175,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, - &capset2_max_ver, - &capset2_max_size); -if (capset2_max_ver) { + &capset_max_ver, + &capset_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, + &capset_max_ver, + &capset_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 6a9eb880ebbf..0d1de7dc398c 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1506,6 +1506,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 (!virt
[PATCH v17 11/13] virtio-gpu: Handle resource blob commands
From: Robert Beckett Support BLOB resources creation, mapping, unmapping and set-scanout 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: Robert Beckett Signed-off-by: Xenia Ragiadakou Signed-off-by: Huang Rui Reviewed-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Tested-by: Alex Bennée Acked-by: Alex Bennée Signed-off-by: Dmitry Osipenko --- hw/display/virtio-gpu-gl.c | 3 + hw/display/virtio-gpu-virgl.c | 414 - hw/display/virtio-gpu.c| 18 +- include/hw/virtio/virtio-gpu.h | 9 + 4 files changed, 434 insertions(+), 10 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index bf87ba423283..f2555673a18e 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -166,6 +166,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 3ffea478e723..b2f4e215a7ad 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" @@ -24,6 +26,7 @@ struct virtio_gpu_virgl_resource { struct virtio_gpu_simple_resource base; +MemoryRegion *mr; }; static struct virtio_gpu_virgl_resource * @@ -47,6 +50,145 @@ virgl_get_egl_display(G_GNUC_UNUSED void *cookie) } #endif +#if VIRGL_VERSION_MAJOR >= 1 +struct virtio_gpu_virgl_hostmem_region { +MemoryRegion mr; +struct VirtIOGPU *g; +bool finish_unmapping; +}; + +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->finish_unmapping = true; + +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, &data, &size); +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 = &vmr->mr; +memory_region_init_ram_ptr(mr, OBJECT(mr), "blob", size, data); +memory_region_add_subregion(&b->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; +
[PATCH v17 05/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. Reviewed-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Tested-by: Alex Bennée Acked-by: Alex Bennée 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 ea3413aa566f..753b35ed69fd 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -156,6 +156,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); @@ -169,6 +185,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.45.2
[PATCH v17 07/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 Reviewed-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Tested-by: Alex Bennée Acked-by: Alex Bennée 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 753b35ed69fd..bf87ba423283 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -147,6 +147,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.45.2
[PATCH v17 08/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: Akihiko Odaki Reviewed-by: Marc-André Lureau Tested-by: Alex Bennée Acked-by: Alex Bennée 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 60dfed87765b..24608338d7ea 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1484,6 +1484,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.45.2
[PATCH v17 06/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 Reviewed-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Tested-by: Alex Bennée Acked-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(&ext, 0, sizeof(ext)); ret = virgl_renderer_resource_get_info_ext(ss.resource_id, &ext); diff --git a/meson.build b/meson.build index fbda17c987e2..8bc7ee47da2c 100644 --- a/meson.build +++ b/meson.build @@ -2388,10 +2388,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.45.2
[PATCH v17 09/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 Reviewed-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Tested-by: Alex Bennée Acked-by: Alex Bennée 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(&g->reslist, &res->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(&g->reslist, &res->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, &res_iovs, &num_iovs); @@ -95,6 +167,10 @@ static void virgl_cmd_resource_unref(VirtIOGPU *g, virtio_gpu_cleanup_mapping_iov(g, res_i
[PATCH v17 04/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. Reviewed-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Tested-by: Alex Bennée Acked-by: Alex Bennée 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 29d20b01321c..ea3413aa566f 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, &width, &height); 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.45.2
[PATCH v17 03/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. Reviewed-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Tested-by: Alex Bennée Acked-by: Alex Bennée 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.45.2
[PATCH v17 02/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. Reviewed-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Reviewed-by: Alex Bennée Tested-by: Alex Bennée Acked-by: Alex Bennée 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(&g->cmdq) || !QTAILQ_EMPTY(&g->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.45.2
[PATCH v17 00/13] Support blob memory and venus on qemu
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(&g->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 (1): 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: Handle resource blob commands docs/system/devices/virtio-gpu.rst | 11 + hw/display/trace-events| 3 + hw/display/virtio-gpu-gl.c | 62 ++- hw/display/virtio-gpu-virgl.c | 585 +++-- hw/display/virtio-gpu.c| 44 ++- include/hw/virtio/virtio-gpu.h | 32 +- meson.build| 5 +- 7 files changed, 685 insertions(+), 57 deletions(-) -- 2.45.2
[PATCH v17 01/13] 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 Reviewed-by: Marc-André Lureau Reviewed-by: Akihiko Odaki Reviewed-by: Alex Bennée Tested-by: Alex Bennée Acked-by: Alex Bennée 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 3281842bfe1b..60dfed87765b 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1065,7 +1065,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); @@ -1085,7 +1085,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.45.2
Re: [PATCH v16 00/13] Support blob memory and venus on qemu
On 8/22/24 16:13, Alex Bennée wrote: > "Michael S. Tsirkin" writes: > >> On Sun, Jun 23, 2024 at 06:23:30PM +0300, Dmitry Osipenko wrote: >>> 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. >> >> >> I'd like to see a Tested-by from Alex Bennée for this - >> he's been testing v14 last as far as I could see. > > I've posted it on the top. Broadly x86 and Arm work on my x86 host. So > far my Arm host only runs the x86 image with the AMD card OK. > > I've updated my test images so you can try them: > > https://fileserver.linaro.org/s/ce5jXBFinPxtEdx > > See the notes on the readme on how to run. Thanks, Alex! I'll re-post v17 with all new acks/r-b's soon, will also link your images in the cover letter. -- Best regards, Dmitry
Re: [PATCH v2] virtio-gpu: Correct virgl_renderer_resource_get_info() error check
On 8/9/24 12:16, Philippe Mathieu-Daudé wrote: > Hi Dmitry, > > On 29/1/24 08:39, Dmitry Osipenko wrote: >> virgl_renderer_resource_get_info() returns errno and not -1 on error. > > So basically we were ignoring all errors... > > Could some errors just be safely ignored? Because apparently > this patch now gives troubles, see: > https://gitlab.com/qemu-project/qemu/-/issues/2490 > Can you help us there? Hi, Philippe. Replied on the gitlab. -- Best regards, Dmitry
[PATCH v16 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 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 b2f4e215a7ad..5a881c58a11d 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -622,19 +622,13 @@ static void virgl_cmd_get_capset_info(VirtIOGPU *g, VIRTIO_GPU_FILL_CMD(info); memset(&resp, 0, sizeof(resp)); -if (info.capset_index == 0) { -resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL; -virgl_renderer_get_cap_set(resp.capset_id, - &resp.capset_max_version, - &resp.capset_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, &resp.capset_max_version, &resp.capset_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, &resp.hdr, sizeof(resp)); @@ -1160,12 +1154,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, &capset2_max_ver, &capset2_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.45.2
[PATCH v16 01/13] 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.45.2
[PATCH v16 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/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 40a9d089710c..b348805fbaee 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(&g->cmdq, cmd, next); if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { g->stats.requests++; -- 2.45.2
[PATCH v16 09/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 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(&g->reslist, &res->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(&g->reslist, &res->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, &res_iovs, &num_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(&g->reslist, &res->base, next); + +g_free(res); } static void virgl_cmd_context_create(VirtIOGPU *g, -- 2.45.2
[PATCH v16 08/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 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.45.2
[PATCH v16 00/13] Support blob memory and venus on qemu
e 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(&g->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 (1): 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: Handle resource blob commands docs/system/devices/virtio-gpu.rst | 11 + hw/display/trace-events| 3 + hw/display/virtio-gpu-gl.c | 62 ++- hw/display/virtio-gpu-virgl.c | 585 +++-- hw/display/virtio-gpu.c| 44 ++- include/hw/virtio/virtio-gpu.h | 32 +- meson.build| 5 +- 7 files changed, 685 insertions(+), 57 deletions(-) -- 2.45.2
[PATCH v16 06/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 --- 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(&ext, 0, sizeof(ext)); ret = virgl_renderer_resource_get_info_ext(ss.resource_id, &ext); 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.45.2
[PATCH v16 04/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 | 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, &width, &height); 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.45.2
[PATCH v16 02/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 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(&g->cmdq) || !QTAILQ_EMPTY(&g->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.45.2
[PATCH v16 03/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 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.45.2
[PATCH v16 11/13] virtio-gpu: Handle resource blob commands
From: Robert Beckett Support BLOB resources creation, mapping, unmapping and set-scanout 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: Robert Beckett # added set_scanout_blob 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 | 414 - hw/display/virtio-gpu.c| 18 +- include/hw/virtio/virtio-gpu.h | 9 + 4 files changed, 434 insertions(+), 10 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 3ffea478e723..b2f4e215a7ad 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" @@ -24,6 +26,7 @@ struct virtio_gpu_virgl_resource { struct virtio_gpu_simple_resource base; +MemoryRegion *mr; }; static struct virtio_gpu_virgl_resource * @@ -47,6 +50,145 @@ virgl_get_egl_display(G_GNUC_UNUSED void *cookie) } #endif +#if VIRGL_VERSION_MAJOR >= 1 +struct virtio_gpu_virgl_hostmem_region { +MemoryRegion mr; +struct VirtIOGPU *g; +bool finish_unmapping; +}; + +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->finish_unmapping = true; + +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, &data, &size); +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 = &vmr->mr; +memory_region_init_ram_ptr(mr, OBJECT(mr), "blob", size, data); +memory_region_add_subregion(&b->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
[PATCH v16 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 --- docs/system/devices/virtio-gpu.rst | 11 +++ 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 +++ 5 files changed, 49 insertions(+), 4 deletions(-) diff --git a/docs/system/devices/virtio-gpu.rst b/docs/system/devices/virtio-gpu.rst index cb73dd799858..b7eb0fc0e727 100644 --- a/docs/system/devices/virtio-gpu.rst +++ b/docs/system/devices/virtio-gpu.rst @@ -71,6 +71,17 @@ representation back to OpenGL API calls. .. _Gallium3D: https://www.freedesktop.org/wiki/Software/gallium/ .. _virglrenderer: https://gitlab.freedesktop.org/virgl/virglrenderer/ +Translation of Vulkan API calls is supported since release of `virglrenderer`_ +v1.0.0 using `venus`_ protocol. ``Venus`` virtio-gpu capability set ("capset") +requires host blob support (``hostmem`` and ``blob`` fields) and should +be enabled using ``venus`` field. The ``hostmem`` field specifies the size +of virtio-gpu host memory window. This is typically between 256M and 8G. + +.. parsed-literal:: +-device virtio-gpu-gl,hostmem=8G,blob=true,venus=true + +.. _venus: https://gitlab.freedesktop.org/virgl/venus-protocol/ + virtio-gpu rutabaga --- 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 5a881c58a11d..eedae7357f1a 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -1128,6 +1128,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, &virtio_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,11 +1175,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, - &capset2_max_ver, - &capset2_max_size); -if (capset2_max_ver) { + &capset_max_ver, + &capset_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, + &capset_max_ver, + &capset_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_h
[PATCH v16 07/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 ++-- 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.45.2
[PATCH v16 05/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 | 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.45.2
Re: [PATCH v15 10/14] virtio-gpu: Support blob scanout using dmabuf fd
On 6/23/24 08:44, Akihiko Odaki wrote: > On 2024/06/23 6:55, Dmitry Osipenko wrote: >> 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(&g->reslist, &res->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(&g->reslist, &res->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(&ss); >> + 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, &info)) { >> + 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; > > Just in case you missed my previous email: >> res->base.dmabuf_fd is conditionally assigned but >> virgl_renderer_resource_get_info() is called unconditionally, which is >> inconsistent. > >> The relevant code is better to be moved into >> virgl_cmd_resource_create_blob() for consistenty with >> virtio_gpu_resource_create_blob(). Right, I squashed this change into patch #12 instead of #10 by mistake. Will fix it shortly, thanks for the review! -- Best regards, Dmitry
[PATCH v15 00/14] Support blob memory and venus on qemu
d 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(&g->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 | 592 +++-- hw/display/virtio-gpu.c| 44 ++- include/hw/virtio/virtio-gpu.h | 32 +- meson.build| 5 +- 6 files changed, 681 insertions(+), 57 deletions(-) -- 2.45.2
[PATCH v15 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.45.2
[PATCH v15 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(&g->reslist, &res->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(&g->reslist, &res->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(&ss); +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, &info)) { +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-
[PATCH v15 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 f6cb4fe5b28e..58693dfa2afa 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -629,19 +629,13 @@ static void virgl_cmd_get_capset_info(VirtIOGPU *g, VIRTIO_GPU_FILL_CMD(info); memset(&resp, 0, sizeof(resp)); -if (info.capset_index == 0) { -resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL; -virgl_renderer_get_cap_set(resp.capset_id, - &resp.capset_max_version, - &resp.capset_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, &resp.capset_max_version, &resp.capset_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, &resp.hdr, sizeof(resp)); @@ -1167,12 +1161,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, &capset2_max_ver, &capset2_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.45.2
[PATCH v15 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.45.2
[PATCH v15 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(&ext, 0, sizeof(ext)); ret = virgl_renderer_resource_get_info_ext(ss.resource_id, &ext); 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.45.2
[PATCH v15 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(&g->reslist, &res->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(&g->reslist, &res->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, &res_iovs, &num_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(&g->reslist, &res->base, next); + +g_free(res); } static void virgl_cmd_context_create(VirtIOGPU *g, -- 2.45.2
[PATCH v15 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(&g->cmdq) || !QTAILQ_EMPTY(&g->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.45.2
[PATCH v15 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, &width, &height); 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.45.2
[PATCH v15 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(&g->cmdq, cmd, next); if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { g->stats.requests++; -- 2.45.2
[PATCH v15 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.45.2
[PATCH v15 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 58693dfa2afa..08b0e7e49337 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -1135,6 +1135,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, &virtio_gpu_3d_cbs); if (ret != 0) { @@ -1168,7 +1173,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)); @@ -1177,11 +1182,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, - &capset2_max_ver, - &capset2_max_size); -if (capset2_max_ver) { + &capset_max_ver, + &capset_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, + &capset_max_ver, + &capset_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.45.2
[PATCH v15 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 | 334 +++-- hw/display/virtio-gpu.c| 6 +- include/hw/virtio/virtio-gpu.h | 2 + 4 files changed, 330 insertions(+), 15 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..f6cb4fe5b28e 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,152 @@ virgl_get_egl_display(G_GNUC_UNUSED void *cookie) } #endif +#if VIRGL_VERSION_MAJOR >= 1 +typedef enum { +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, &data, &size); +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 = &vmr->mr; +memory_region_init_ram_ptr(mr, OBJECT(mr), "blob", size, data); +memory_region_add_subregion(&b->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 f
[PATCH v15 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.45.2
[PATCH v15 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.45.2
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
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(&resp, 0, sizeof(resp)); -if (info.capset_index == 0) { -resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL; -virgl_renderer_get_cap_set(resp.capset_id, - &resp.capset_max_version, - &resp.capset_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, &resp.capset_max_version, &resp.capset_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, &resp.hdr, 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, &capset2_max_ver, &capset2_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, &width, &height); 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
us" 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(&g->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(&ext, 0, sizeof(ext)); ret = virgl_renderer_resource_get_info_ext(ss.resource_id, &ext); 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, &virtio_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, - &capset2_max_ver, - &capset2_max_size); -if (capset2_max_ver) { + &capset_max_ver, + &capset_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, + &capset_max_ver, + &capset_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(&g->cmdq) || !QTAILQ_EMPTY(&g->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(&g->reslist, &res->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(&g->reslist, &res->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, &res_iovs, &num_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(&g->reslist, &res->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, &data, &size); +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 = &vmr->mr; +memory_region_init_ram_ptr(mr, OBJECT(mr), "blob", size, data); +memory_region_add_subregion(&b->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. Wa
[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(&g->reslist, &res->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(&g->reslist, &res->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(&ss); +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, &info)) { +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-
[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(&g->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, &res->base.addrs, >> + &res->base.iov, >> &res->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, &data, &size); +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 = &vmr->mr; +memory_region_init_ram_ptr(mr, OBJECT(mr), "blob", size, data); +memory_region_add_subregion(&b->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_subreg
[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(&resp, 0, sizeof(resp)); -if (info.capset_index == 0) { -resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL; -virgl_renderer_get_cap_set(resp.capset_id, - &resp.capset_max_version, - &resp.capset_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, &resp.capset_max_version, &resp.capset_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, &resp.hdr, 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, &capset2_max_ver, &capset2_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, &virtio_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, - &capset2_max_ver, - &capset2_max_size); -if (capset2_max_ver) { + &capset_max_ver, + &capset_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, + &capset_max_ver, + &capset_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
[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(&g->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, &width, &height); 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(&g->reslist, &res->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(&g->reslist, &res->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(&ss); +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, &info)) { +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.b
[PATCH v13 00/13] Support blob memory and venus on qemu
o_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(&g->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(&g->reslist, &res->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(&g->reslist, &res->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, &res_iovs, &num_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(&g->reslist, &res->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(&g->cmdq) || !QTAILQ_EMPTY(&g->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:1
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-
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(&g->reslist, &res->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(&g->reslist, &res->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(&ss); +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, &info)) { +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.b
[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, &width, &height); 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, &virtio_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, - &capset2_max_ver, - &capset2_max_size); -if (capset2_max_ver) { + &capset_max_ver, + &capset_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, + &capset_max_ver, + &capset_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
[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(&g->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, &data, &size); +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 = &vmr->mr; +memory_region_init_ram_ptr(mr, OBJECT(mr), "blob", size, data); +memory_region_add_subregion(&b->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(m
[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(&g->reslist, &res->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(&g->reslist, &res->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, &res_iovs, &num_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(&g->reslist, &res->base, next); + +g_free(res); } static void virgl_cmd_context_create(VirtIOGPU *g, -- 2.44.0