diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index bbe30ced57..ab87a7f5ac 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -57,13 +57,12 @@ struct VulkanPhysicalDeviceInfo { // This is a bit repetitive... class VulkanDeleteList { struct Callback { - explicit Callback(void (*f)(void *userdata1, void *userdata2), void *u1, void *u2) - : func(f), userdata1(u1), userdata2(u2) { + explicit Callback(void (*f)(void *userdata), void *u) + : func(f), userdata(u) { } - void (*func)(void *userdata1, void *userdata2); - void *userdata1; - void *userdata2; + void (*func)(void *userdata); + void *userdata; }; public: @@ -78,7 +77,7 @@ public: void QueueDeletePipelineCache(VkPipelineCache pipelineCache) { pipelineCaches_.push_back(pipelineCache); } void QueueDeleteRenderPass(VkRenderPass renderPass) { renderPasses_.push_back(renderPass); } void QueueDeleteFramebuffer(VkFramebuffer framebuffer) { framebuffers_.push_back(framebuffer); } - void QueueCallback(void (*func)(void *userdata1, void *userdata2), void *userdata1, void *userdata2) { callbacks_.push_back(Callback(func, userdata1, userdata2)); } + void QueueCallback(void (*func)(void *userdata), void *userdata) { callbacks_.push_back(Callback(func, userdata)); } void Take(VulkanDeleteList &del) { assert(descPools_.size() == 0); @@ -153,7 +152,7 @@ public: } framebuffers_.clear(); for (auto &callback : callbacks_) { - callback.func(callback.userdata1, callback.userdata2); + callback.func(callback.userdata); } callbacks_.clear(); } diff --git a/Common/Vulkan/VulkanMemory.cpp b/Common/Vulkan/VulkanMemory.cpp index cf7bbb2868..93541c5249 100644 --- a/Common/Vulkan/VulkanMemory.cpp +++ b/Common/Vulkan/VulkanMemory.cpp @@ -228,8 +228,8 @@ void VulkanDeviceAllocator::Free(VkDeviceMemory deviceMemory, size_t offset) { } // Okay, now enqueue. It's valid. - FreeInfo *info = new FreeInfo(deviceMemory, offset); - vulkan_->Delete().QueueCallback(&DispatchFree, this, info); + FreeInfo *info = new FreeInfo(this, deviceMemory, offset); + vulkan_->Delete().QueueCallback(&DispatchFree, info); } void VulkanDeviceAllocator::ExecuteFree(FreeInfo *userdata) { diff --git a/Common/Vulkan/VulkanMemory.h b/Common/Vulkan/VulkanMemory.h index ea0d504c61..186cc8cddd 100644 --- a/Common/Vulkan/VulkanMemory.h +++ b/Common/Vulkan/VulkanMemory.h @@ -128,11 +128,18 @@ private: uint8_t *writePtr_; }; +// VulkanDeviceAllocator +// +// Implements a slab based allocator that manages suballocations inside the slabs. +// Bitmaps are used to handle allocation state, with a 1KB grain. class VulkanDeviceAllocator { public: + // Slab sizes start at minSlabSize and double until maxSlabSize. + // Total slab count is unlimited, as long as there's free memory. VulkanDeviceAllocator(VulkanContext *vulkan, size_t minSlabSize, size_t maxSlabSize); ~VulkanDeviceAllocator(); + // Requires all memory be free beforehand (including all pending deletes.) void Destroy(); void Begin() { @@ -142,7 +149,10 @@ public: void End() { } + // May return ALLOCATE_FAILED if the allocation fails. size_t Allocate(const VkMemoryRequirements &reqs, VkDeviceMemory *deviceMemory); + + // Crashes on a double or misfree. void Free(VkDeviceMemory deviceMemory, size_t offset); static const size_t ALLOCATE_FAILED = -1; @@ -164,18 +174,18 @@ private: }; struct FreeInfo { - explicit FreeInfo(VkDeviceMemory d, size_t o) - : deviceMemory(d), offset(o) { + explicit FreeInfo(VulkanDeviceAllocator *a, VkDeviceMemory d, size_t o) + : allocator(a), deviceMemory(d), offset(o) { } + VulkanDeviceAllocator *allocator; VkDeviceMemory deviceMemory; size_t offset; }; - static void DispatchFree(void *thiz, void *userdata) { - auto allocator = static_cast(thiz); + static void DispatchFree(void *userdata) { auto freeInfo = static_cast(userdata); - allocator->ExecuteFree(freeInfo); + freeInfo->allocator->ExecuteFree(freeInfo); } bool AllocateSlab(size_t minBytes);