diff --git a/src/asahi/vulkan/hk_device.c b/src/asahi/vulkan/hk_device.c index 5478e673c08..e904f80eaa9 100644 --- a/src/asahi/vulkan/hk_device.c +++ b/src/asahi/vulkan/hk_device.c @@ -452,6 +452,10 @@ hk_CreateDevice(VkPhysicalDevice physicalDevice, agx_scratch_init(&dev->dev, &dev->scratch.fs); agx_scratch_init(&dev->dev, &dev->scratch.cs); + u_rwlock_init(&dev->external_bos.lock); + util_dynarray_init(&dev->external_bos.counts, NULL); + util_dynarray_init(&dev->external_bos.list, NULL); + return VK_SUCCESS; fail_mem_cache: @@ -491,6 +495,10 @@ hk_DestroyDevice(VkDevice _device, const VkAllocationCallbacks *pAllocator) if (!dev) return; + util_dynarray_fini(&dev->external_bos.counts); + util_dynarray_fini(&dev->external_bos.list); + u_rwlock_destroy(&dev->external_bos.lock); + hk_device_finish_meta(dev); hk_destroy_internal_shaders(dev, &dev->kernels, false); hk_destroy_internal_shaders(dev, &dev->prolog_epilog, true); diff --git a/src/asahi/vulkan/hk_device.h b/src/asahi/vulkan/hk_device.h index cf05b26173c..08545826d09 100644 --- a/src/asahi/vulkan/hk_device.h +++ b/src/asahi/vulkan/hk_device.h @@ -8,7 +8,9 @@ #pragma once #include "asahi/lib/agx_device.h" +#include "util/rwlock.h" #include "util/simple_mtx.h" +#include "util/u_dynarray.h" #include "agx_bg_eot.h" #include "agx_pack.h" #include "agx_scratch.h" @@ -107,6 +109,12 @@ struct hk_device { } scratch; uint32_t perftest; + + struct { + struct u_rwlock lock; + struct util_dynarray list; + struct util_dynarray counts; + } external_bos; }; VK_DEFINE_HANDLE_CASTS(hk_device, vk.base, VkDevice, VK_OBJECT_TYPE_DEVICE) diff --git a/src/asahi/vulkan/hk_device_memory.c b/src/asahi/vulkan/hk_device_memory.c index a0922e80176..326ced5067e 100644 --- a/src/asahi/vulkan/hk_device_memory.c +++ b/src/asahi/vulkan/hk_device_memory.c @@ -49,6 +49,79 @@ hk_memory_type_flags(const VkMemoryType *type, return flags; } +static void +hk_add_ext_bo_locked(struct hk_device *dev, struct agx_bo *bo) +{ + uint32_t id = bo->vbo_res_id; + + unsigned count = util_dynarray_num_elements(&dev->external_bos.list, + struct asahi_ccmd_submit_res); + + for (unsigned i = 0; i < count; i++) { + struct asahi_ccmd_submit_res *p = util_dynarray_element( + &dev->external_bos.list, struct asahi_ccmd_submit_res, i); + + if (p->res_id == id) { + ++*util_dynarray_element(&dev->external_bos.counts, unsigned, i); + return; + } + } + + struct asahi_ccmd_submit_res res = { + .res_id = id, + .flags = ASAHI_EXTRES_READ | ASAHI_EXTRES_WRITE, + }; + util_dynarray_append(&dev->external_bos.list, struct asahi_ccmd_submit_res, + res); + util_dynarray_append(&dev->external_bos.counts, unsigned, 1); +} + +static void +hk_add_ext_bo(struct hk_device *dev, struct agx_bo *bo) +{ + if (dev->dev.is_virtio) { + u_rwlock_wrlock(&dev->external_bos.lock); + hk_add_ext_bo_locked(dev, bo); + u_rwlock_wrunlock(&dev->external_bos.lock); + } +} + +static void +hk_remove_ext_bo_locked(struct hk_device *dev, struct agx_bo *bo) +{ + uint32_t id = bo->vbo_res_id; + unsigned count = util_dynarray_num_elements(&dev->external_bos.list, + struct asahi_ccmd_submit_res); + + for (unsigned i = 0; i < count; i++) { + struct asahi_ccmd_submit_res *p = util_dynarray_element( + &dev->external_bos.list, struct asahi_ccmd_submit_res, i); + + if (p->res_id == id) { + unsigned *ctr = + util_dynarray_element(&dev->external_bos.counts, unsigned, i); + if (!--*ctr) { + *ctr = util_dynarray_pop(&dev->external_bos.counts, unsigned); + *p = util_dynarray_pop(&dev->external_bos.list, + struct asahi_ccmd_submit_res); + } + return; + } + } + + unreachable("BO not found"); +} + +static void +hk_remove_ext_bo(struct hk_device *dev, struct agx_bo *bo) +{ + if (dev->dev.is_virtio) { + u_rwlock_wrlock(&dev->external_bos.lock); + hk_remove_ext_bo_locked(dev, bo); + u_rwlock_wrunlock(&dev->external_bos.lock); + } +} + VKAPI_ATTR VkResult VKAPI_CALL hk_GetMemoryFdPropertiesKHR(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, @@ -146,6 +219,9 @@ hk_AllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo, } } + if (mem->bo->flags & (AGX_BO_SHAREABLE | AGX_BO_SHARED)) + hk_add_ext_bo(dev, mem->bo); + if (fd_info && fd_info->handleType) { /* From the Vulkan spec: * @@ -190,6 +266,9 @@ hk_FreeMemory(VkDevice device, VkDeviceMemory _mem, struct hk_memory_heap *heap = &pdev->mem_heaps[type->heapIndex]; p_atomic_add(&heap->used, -((int64_t)mem->bo->size)); + if (mem->bo->flags & (AGX_BO_SHAREABLE | AGX_BO_SHARED)) + hk_remove_ext_bo(dev, mem->bo); + agx_bo_unreference(&dev->dev, mem->bo); vk_device_memory_destroy(&dev->vk, pAllocator, &mem->vk); diff --git a/src/asahi/vulkan/hk_queue.c b/src/asahi/vulkan/hk_queue.c index 6a991c877e1..d34d855a732 100644 --- a/src/asahi/vulkan/hk_queue.c +++ b/src/asahi/vulkan/hk_queue.c @@ -272,7 +272,7 @@ max_commands_per_submit(struct hk_device *dev) } static VkResult -queue_submit_single(struct agx_device *dev, struct drm_asahi_submit *submit) +queue_submit_single(struct hk_device *dev, struct drm_asahi_submit *submit) { /* Currently we don't use the result buffer or implicit sync */ struct agx_submit_virt virt = { @@ -280,7 +280,17 @@ queue_submit_single(struct agx_device *dev, struct drm_asahi_submit *submit) .extres_count = 0, }; - int ret = dev->ops.submit(dev, submit, &virt); + if (dev->dev.is_virtio) { + u_rwlock_rdlock(&dev->external_bos.lock); + virt.extres_count = util_dynarray_num_elements( + &dev->external_bos.list, struct asahi_ccmd_submit_res); + virt.extres = util_dynarray_begin(&dev->external_bos.list); + } + + int ret = dev->dev.ops.submit(&dev->dev, submit, &virt); + + if (dev->dev.is_virtio) + u_rwlock_rdunlock(&dev->external_bos.lock); /* XXX: don't trap */ if (ret) { @@ -348,7 +358,7 @@ queue_submit_looped(struct hk_device *dev, struct drm_asahi_submit *submit) .out_sync_count = last ? submit->out_sync_count : 0, }; - VkResult result = queue_submit_single(&dev->dev, &submit_ioctl); + VkResult result = queue_submit_single(dev, &submit_ioctl); if (result != VK_SUCCESS) return result; @@ -520,7 +530,7 @@ queue_submit(struct hk_device *dev, struct hk_queue *queue, }; if (command_count <= max_commands_per_submit(dev)) - return queue_submit_single(&dev->dev, &submit_ioctl); + return queue_submit_single(dev, &submit_ioctl); else return queue_submit_looped(dev, &submit_ioctl); }