From 6187f36c33cc4cdd8ff48599471cc7c449d3bf7c Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Wed, 29 Dec 2021 21:23:31 +1000 Subject: [PATCH] Vulkan/StreamBuffer: Use VulkanMemoryAllocator --- common/Vulkan/Context.cpp | 6 ++ common/Vulkan/Context.h | 1 + common/Vulkan/StreamBuffer.cpp | 121 +++++++++------------------------ common/Vulkan/StreamBuffer.h | 12 ++-- 4 files changed, 43 insertions(+), 97 deletions(-) diff --git a/common/Vulkan/Context.cpp b/common/Vulkan/Context.cpp index b4cc683131..4878bbea20 100644 --- a/common/Vulkan/Context.cpp +++ b/common/Vulkan/Context.cpp @@ -1121,6 +1121,12 @@ namespace Vulkan resources.cleanup_resources.push_back([this, object]() { vkDestroyBuffer(m_device, object, nullptr); }); } + void Context::DeferBufferDestruction(VkBuffer object, VmaAllocation allocation) + { + FrameResources& resources = m_frame_resources[m_current_frame]; + resources.cleanup_resources.push_back([this, object, allocation]() { vmaDestroyBuffer(m_allocator, object, allocation); }); + } + void Context::DeferBufferViewDestruction(VkBufferView object) { FrameResources& resources = m_frame_resources[m_current_frame]; diff --git a/common/Vulkan/Context.h b/common/Vulkan/Context.h index 7b126f666e..d6ac0e2910 100644 --- a/common/Vulkan/Context.h +++ b/common/Vulkan/Context.h @@ -194,6 +194,7 @@ namespace Vulkan // Schedule a vulkan resource for destruction later on. This will occur when the command buffer // is next re-used, and the GPU has finished working with the specified resource. void DeferBufferDestruction(VkBuffer object); + void DeferBufferDestruction(VkBuffer object, VmaAllocation allocation); void DeferBufferViewDestruction(VkBufferView object); void DeferDeviceMemoryDestruction(VkDeviceMemory object); void DeferFramebufferDestruction(VkFramebuffer object); diff --git a/common/Vulkan/StreamBuffer.cpp b/common/Vulkan/StreamBuffer.cpp index 174448fc51..939932dac0 100644 --- a/common/Vulkan/StreamBuffer.cpp +++ b/common/Vulkan/StreamBuffer.cpp @@ -25,17 +25,22 @@ namespace Vulkan StreamBuffer::StreamBuffer() = default; StreamBuffer::StreamBuffer(StreamBuffer&& move) - : m_usage(move.m_usage) - , m_size(move.m_size) + : m_size(move.m_size) , m_current_offset(move.m_current_offset) , m_current_space(move.m_current_space) , m_current_gpu_position(move.m_current_gpu_position) + , m_allocation(move.m_allocation) , m_buffer(move.m_buffer) - , m_memory(move.m_memory) , m_host_pointer(move.m_host_pointer) , m_tracked_fences(std::move(move.m_tracked_fences)) - , m_coherent_mapping(move.m_coherent_mapping) { + move.m_size = 0; + move.m_current_offset = 0; + move.m_current_space = 0; + move.m_current_gpu_position = 0; + move.m_allocation = VK_NULL_HANDLE; + move.m_buffer = VK_NULL_HANDLE; + move.m_host_pointer = nullptr; } StreamBuffer::~StreamBuffer() @@ -49,124 +54,67 @@ namespace Vulkan if (IsValid()) Destroy(true); - std::swap(m_usage, move.m_usage); std::swap(m_size, move.m_size); std::swap(m_current_offset, move.m_current_offset); std::swap(m_current_space, move.m_current_space); std::swap(m_current_gpu_position, move.m_current_gpu_position); std::swap(m_buffer, move.m_buffer); - std::swap(m_memory, move.m_memory); std::swap(m_host_pointer, move.m_host_pointer); std::swap(m_tracked_fences, move.m_tracked_fences); - std::swap(m_coherent_mapping, move.m_coherent_mapping); return *this; } bool StreamBuffer::Create(VkBufferUsageFlags usage, u32 size) { - // TODO: Move this over to vk_mem_alloc. - - // Create the buffer descriptor - const VkBufferCreateInfo buffer_create_info = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr, 0, + const VkBufferCreateInfo bci = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr, 0, static_cast(size), usage, VK_SHARING_MODE_EXCLUSIVE, 0, nullptr}; - VkBuffer buffer = VK_NULL_HANDLE; - VkResult res = vkCreateBuffer(g_vulkan_context->GetDevice(), &buffer_create_info, nullptr, &buffer); + VmaAllocationCreateInfo aci = {}; + aci.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; + aci.usage = VMA_MEMORY_USAGE_CPU_TO_GPU; + + VmaAllocationInfo ai = {}; + VkBuffer new_buffer = VK_NULL_HANDLE; + VmaAllocation new_allocation = VK_NULL_HANDLE; + VkResult res = vmaCreateBuffer(g_vulkan_context->GetAllocator(), &bci, &aci, &new_buffer, &new_allocation, &ai); if (res != VK_SUCCESS) { LOG_VULKAN_ERROR(res, "vkCreateBuffer failed: "); return false; } - // Get memory requirements (types etc) for this buffer - VkMemoryRequirements memory_requirements; - vkGetBufferMemoryRequirements(g_vulkan_context->GetDevice(), buffer, &memory_requirements); - - // Aim for a coherent mapping if possible. - u32 memory_type_index = - g_vulkan_context->GetUploadMemoryType(memory_requirements.memoryTypeBits, &m_coherent_mapping); - - // Allocate memory for backing this buffer - VkMemoryAllocateInfo memory_allocate_info = { - VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType - nullptr, // const void* pNext - memory_requirements.size, // VkDeviceSize allocationSize - memory_type_index // uint32_t memoryTypeIndex - }; - VkDeviceMemory memory = VK_NULL_HANDLE; - res = vkAllocateMemory(g_vulkan_context->GetDevice(), &memory_allocate_info, nullptr, &memory); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkAllocateMemory failed: "); - vkDestroyBuffer(g_vulkan_context->GetDevice(), buffer, nullptr); - return false; - } - - // Bind memory to buffer - res = vkBindBufferMemory(g_vulkan_context->GetDevice(), buffer, memory, 0); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkBindBufferMemory failed: "); - vkDestroyBuffer(g_vulkan_context->GetDevice(), buffer, nullptr); - vkFreeMemory(g_vulkan_context->GetDevice(), memory, nullptr); - return false; - } - - // Map this buffer into user-space - void* mapped_ptr = nullptr; - res = vkMapMemory(g_vulkan_context->GetDevice(), memory, 0, size, 0, &mapped_ptr); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkMapMemory failed: "); - vkDestroyBuffer(g_vulkan_context->GetDevice(), buffer, nullptr); - vkFreeMemory(g_vulkan_context->GetDevice(), memory, nullptr); - return false; - } - - // Unmap current host pointer (if there was a previous buffer) - if (m_host_pointer) - vkUnmapMemory(g_vulkan_context->GetDevice(), m_memory); - if (IsValid()) Destroy(true); // Replace with the new buffer - m_usage = usage; m_size = size; - m_buffer = buffer; - m_memory = memory; - m_host_pointer = reinterpret_cast(mapped_ptr); m_current_offset = 0; m_current_gpu_position = 0; m_tracked_fences.clear(); + m_allocation = new_allocation; + m_buffer = new_buffer; + m_host_pointer = static_cast(ai.pMappedData); return true; } void StreamBuffer::Destroy(bool defer) { - if (m_host_pointer) - { - vkUnmapMemory(g_vulkan_context->GetDevice(), m_memory); - m_host_pointer = nullptr; - } - if (m_buffer != VK_NULL_HANDLE) { if (defer) - g_vulkan_context->DeferBufferDestruction(m_buffer); + g_vulkan_context->DeferBufferDestruction(m_buffer, m_allocation); else - vkDestroyBuffer(g_vulkan_context->GetDevice(), m_buffer, nullptr); - m_buffer = VK_NULL_HANDLE; - } - if (m_memory != VK_NULL_HANDLE) - { - if (defer) - g_vulkan_context->DeferDeviceMemoryDestruction(m_memory); - else - vkFreeMemory(g_vulkan_context->GetDevice(), m_memory, nullptr); - m_memory = VK_NULL_HANDLE; + vmaDestroyBuffer(g_vulkan_context->GetAllocator(), m_buffer, m_allocation); } + + m_size = 0; + m_current_offset = 0; + m_current_gpu_position = 0; + m_tracked_fences.clear(); + m_buffer = VK_NULL_HANDLE; + m_allocation = VK_NULL_HANDLE; + m_host_pointer = nullptr; } bool StreamBuffer::ReserveMemory(u32 num_bytes, u32 alignment) @@ -244,12 +192,7 @@ namespace Vulkan pxAssert(final_num_bytes <= m_current_space); // For non-coherent mappings, flush the memory range - if (!m_coherent_mapping) - { - VkMappedMemoryRange range = { - VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, nullptr, m_memory, m_current_offset, final_num_bytes}; - vkFlushMappedMemoryRanges(g_vulkan_context->GetDevice(), 1, &range); - } + vmaFlushAllocation(g_vulkan_context->GetAllocator(), m_allocation, m_current_offset, final_num_bytes); m_current_offset += final_num_bytes; m_current_space -= final_num_bytes; diff --git a/common/Vulkan/StreamBuffer.h b/common/Vulkan/StreamBuffer.h index 4b26b720a6..456ca22c57 100644 --- a/common/Vulkan/StreamBuffer.h +++ b/common/Vulkan/StreamBuffer.h @@ -17,6 +17,7 @@ #include "common/Pcsx2Defs.h" #include "common/Vulkan/Loader.h" +#include "vk_mem_alloc.h" #include #include @@ -35,10 +36,8 @@ namespace Vulkan __fi bool IsValid() const { return (m_buffer != VK_NULL_HANDLE); } __fi VkBuffer GetBuffer() const { return m_buffer; } - __fi const VkBuffer* GetBufferPointer() const { return &m_buffer; } - __fi VkDeviceMemory GetDeviceMemory() const { return m_memory; } - __fi void* GetHostPointer() const { return m_host_pointer; } - __fi void* GetCurrentHostPointer() const { return m_host_pointer + m_current_offset; } + __fi u8* GetHostPointer() const { return m_host_pointer; } + __fi u8* GetCurrentHostPointer() const { return m_host_pointer + m_current_offset; } __fi u32 GetCurrentSize() const { return m_size; } __fi u32 GetCurrentSpace() const { return m_current_space; } __fi u32 GetCurrentOffset() const { return m_current_offset; } @@ -57,19 +56,16 @@ namespace Vulkan // Waits for as many fences as needed to allocate num_bytes bytes from the buffer. bool WaitForClearSpace(u32 num_bytes); - VkBufferUsageFlags m_usage = 0; u32 m_size = 0; u32 m_current_offset = 0; u32 m_current_space = 0; u32 m_current_gpu_position = 0; + VmaAllocation m_allocation = VK_NULL_HANDLE; VkBuffer m_buffer = VK_NULL_HANDLE; - VkDeviceMemory m_memory = VK_NULL_HANDLE; u8* m_host_pointer = nullptr; // List of fences and the corresponding positions in the buffer std::deque> m_tracked_fences; - - bool m_coherent_mapping = false; }; } // namespace Vulkan