From 20dab5f819f7016b8d7f4e88927855a0e5ff7a61 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Tue, 29 Jul 2025 15:50:39 -0400 Subject: [PATCH] asahi: enable virtgpu support this updates our virtgpu support to match the upstream protocol, and enables. it is marked for backport since the older Mesa releases already had virtgpu support, just gated off to allow for breaking wire protocol changes (of which there was 1 at the last moment). Upstream virglrenderer MR assigned to marge: https://gitlab.freedesktop.org/virgl/virglrenderer/-/merge_requests/1541 Backport-to: 25.1 Signed-off-by: Alyssa Rosenzweig Part-of: --- src/asahi/lib/agx_device.c | 5 +---- src/asahi/lib/agx_device.h | 1 + src/asahi/lib/agx_device_virtio.c | 15 +++++---------- src/asahi/vulkan/hk_queue.c | 21 +++++++++++++-------- src/asahi/vulkan/hk_queue.h | 3 +++ src/gallium/drivers/asahi/agx_batch.c | 2 +- src/gallium/drivers/asahi/agx_pipe.c | 1 + src/gallium/drivers/asahi/agx_state.h | 2 +- 8 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/asahi/lib/agx_device.c b/src/asahi/lib/agx_device.c index d7740b249c6..35aa8a672e3 100644 --- a/src/asahi/lib/agx_device.c +++ b/src/asahi/lib/agx_device.c @@ -84,7 +84,7 @@ static const struct debug_named_value agx_debug_options[] = { void agx_bo_free(struct agx_device *dev, struct agx_bo *bo) { - const uint64_t handle = bo->uapi_handle; + const uint64_t handle = bo->handle; if (bo->_map) munmap(bo->_map, bo->size); @@ -521,9 +521,6 @@ agx_open_device(void *memctx, struct agx_device *dev) dev->is_virtio = false; dev->ops = agx_device_drm_ops; } else if (!strcmp(version->name, "virtio_gpu")) { - /* TODO: virtio wire protocol is not stable yet */ - return false; - dev->is_virtio = true; if (!agx_virtio_open_device(dev)) { fprintf( diff --git a/src/asahi/lib/agx_device.h b/src/asahi/lib/agx_device.h index 7366c148c8c..e80dd9b5a5e 100644 --- a/src/asahi/lib/agx_device.h +++ b/src/asahi/lib/agx_device.h @@ -68,6 +68,7 @@ struct nir_shader; struct agx_submit_virt { uint32_t extres_count; struct asahi_ccmd_submit_res *extres; + uint32_t ring_idx; }; typedef struct { diff --git a/src/asahi/lib/agx_device_virtio.c b/src/asahi/lib/agx_device_virtio.c index 13e4c631c3e..e245c0c7c97 100644 --- a/src/asahi/lib/agx_device_virtio.c +++ b/src/asahi/lib/agx_device_virtio.c @@ -124,7 +124,7 @@ agx_virtio_bo_bind(struct agx_device *dev, struct drm_asahi_gem_bind_op *ops, *req = (struct asahi_ccmd_vm_bind_req){ .hdr.cmd = ASAHI_CCMD_VM_BIND, - .hdr.len = sizeof(struct asahi_ccmd_vm_bind_req), + .hdr.len = req_len, .vm_id = dev->vm_id, .stride = sizeof(*ops), .count = count, @@ -215,12 +215,8 @@ agx_virtio_get_params(struct agx_device *dev, void *buf, size_t size) sizeof(struct asahi_ccmd_get_params_rsp) + size); int ret = vdrm_send_req(vdrm, &req.hdr, true); - if (!ret) - return ret; - - ret = rsp->ret; - if (ret) - return ret; + if (ret || rsp->ret) + return ret ? ret : rsp->ret; memcpy(buf, &rsp->payload, size); return size; @@ -265,8 +261,7 @@ agx_virtio_submit(struct agx_device *dev, struct drm_asahi_submit *submit, } struct vdrm_execbuf_params p = { - /* Signal the host we want to wait for the command to complete */ - .ring_idx = 1, + .ring_idx = virt->ring_idx, .req = &req->hdr, .num_in_syncobjs = submit->in_sync_count, .in_syncobjs = vdrm_syncs, @@ -296,7 +291,7 @@ agx_virtio_open_device(struct agx_device *dev) { struct vdrm_device *vdrm; - vdrm = vdrm_device_connect(dev->fd, 2); + vdrm = vdrm_device_connect(dev->fd, 4); if (!vdrm) { fprintf(stderr, "could not connect vdrm\n"); return false; diff --git a/src/asahi/vulkan/hk_queue.c b/src/asahi/vulkan/hk_queue.c index 0e0556f590b..2bd3eab6ac1 100644 --- a/src/asahi/vulkan/hk_queue.c +++ b/src/asahi/vulkan/hk_queue.c @@ -267,9 +267,10 @@ max_commands_per_submit(struct hk_device *dev) } static VkResult -queue_submit_single(struct hk_device *dev, struct drm_asahi_submit *submit) +queue_submit_single(struct hk_device *dev, struct drm_asahi_submit *submit, + unsigned ring_idx) { - struct agx_submit_virt virt = {0}; + struct agx_submit_virt virt = {.ring_idx = ring_idx}; if (dev->dev.is_virtio) { u_rwlock_rdlock(&dev->external_bos.lock); @@ -300,7 +301,7 @@ queue_submit_single(struct hk_device *dev, struct drm_asahi_submit *submit) */ static VkResult queue_submit_looped(struct hk_device *dev, struct drm_asahi_submit *submit, - unsigned command_count) + unsigned command_count, unsigned ring_idx) { uint8_t *cmdbuf = (uint8_t *)(uintptr_t)submit->cmdbuf; uint32_t offs = 0; @@ -373,7 +374,7 @@ queue_submit_looped(struct hk_device *dev, struct drm_asahi_submit *submit, .out_sync_count = has_out_syncs ? submit->out_sync_count : 0, }; - VkResult result = queue_submit_single(dev, &submit_ioctl); + VkResult result = queue_submit_single(dev, &submit_ioctl, ring_idx); if (result != VK_SUCCESS) return result; @@ -886,10 +887,13 @@ queue_submit(struct hk_device *dev, struct hk_queue *queue, }; VkResult result; - if (command_count <= max_commands_per_submit(dev)) - result = queue_submit_single(dev, &submit_ioctl); - else - result = queue_submit_looped(dev, &submit_ioctl, command_count); + if (command_count <= max_commands_per_submit(dev)) { + result = + queue_submit_single(dev, &submit_ioctl, queue->drm.virt_ring_idx); + } else { + result = queue_submit_looped(dev, &submit_ioctl, command_count, + queue->drm.virt_ring_idx); + } util_dynarray_fini(&payload); return result; @@ -979,6 +983,7 @@ hk_queue_init(struct hk_device *dev, struct hk_queue *queue, queue->vk.driver_submit = hk_queue_submit; queue->drm.id = agx_create_command_queue(&dev->dev, drm_priority); + queue->drm.virt_ring_idx = drm_priority + 1; if (drmSyncobjCreate(dev->dev.fd, 0, &queue->drm.syncobj)) { mesa_loge("drmSyncobjCreate() failed %d\n", errno); diff --git a/src/asahi/vulkan/hk_queue.h b/src/asahi/vulkan/hk_queue.h index b1073a03f3d..f45c8ed92e0 100644 --- a/src/asahi/vulkan/hk_queue.h +++ b/src/asahi/vulkan/hk_queue.h @@ -22,6 +22,9 @@ struct hk_queue { /* Timeline syncobj backing the queue */ uint32_t syncobj; + /* Ring-idx used with virtgpu, equal to priority + 1 */ + uint32_t virt_ring_idx; + /* Current maximum timeline value for the queue's syncobj. If the * syncobj's value equals timeline_value, then all work is complete. */ diff --git a/src/gallium/drivers/asahi/agx_batch.c b/src/gallium/drivers/asahi/agx_batch.c index f3a92298238..9b3dd959939 100644 --- a/src/gallium/drivers/asahi/agx_batch.c +++ b/src/gallium/drivers/asahi/agx_batch.c @@ -659,7 +659,7 @@ agx_batch_submit(struct agx_context *ctx, struct agx_batch *batch, uint64_t wait_seqid = p_atomic_read(&screen->flush_wait_seqid); - struct agx_submit_virt virt = {0}; + struct agx_submit_virt virt = {.ring_idx = ctx->virt_ring_idx}; /* Elide syncing against our own queue */ if (wait_seqid && wait_seqid == ctx->flush_my_seqid) { diff --git a/src/gallium/drivers/asahi/agx_pipe.c b/src/gallium/drivers/asahi/agx_pipe.c index 6bec0508da3..c9b697483ce 100644 --- a/src/gallium/drivers/asahi/agx_pipe.c +++ b/src/gallium/drivers/asahi/agx_pipe.c @@ -1751,6 +1751,7 @@ agx_create_context(struct pipe_screen *screen, void *priv, unsigned flags) */ ctx->queue_id = agx_create_command_queue(agx_device(screen), priority); + ctx->virt_ring_idx = priority + 1; pctx->destroy = agx_destroy_context; pctx->flush = agx_flush; diff --git a/src/gallium/drivers/asahi/agx_state.h b/src/gallium/drivers/asahi/agx_state.h index 4972513e8bd..ddff271338f 100644 --- a/src/gallium/drivers/asahi/agx_state.h +++ b/src/gallium/drivers/asahi/agx_state.h @@ -634,7 +634,7 @@ struct agx_context { } batches; /* Queue handle */ - uint32_t queue_id; + uint32_t queue_id, virt_ring_idx; struct agx_batch *batch; struct agx_bo *timestamps;