Add and make use of Vulkan Memory Allocator

This commit is contained in:
Lynix
2020-03-26 21:15:49 +01:00
parent 509c392e05
commit b73d3e8f04
13 changed files with 18536 additions and 119 deletions

View File

@@ -7,11 +7,15 @@
#include <Nazara/Core/String.hpp>
#include <Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp>
#include <Nazara/VulkanRenderer/Wrapper/QueueHandle.hpp>
#include <vma/vk_mem_alloc.h>
#include <Nazara/VulkanRenderer/Debug.hpp>
namespace Nz
{
VulkanBuffer::~VulkanBuffer() = default;
VulkanBuffer::~VulkanBuffer()
{
vmaDestroyBuffer(m_device.GetMemoryAllocator(), m_buffer, m_allocation);
}
bool VulkanBuffer::Fill(const void* data, UInt32 offset, UInt32 size)
{
@@ -32,32 +36,33 @@ namespace Nz
m_usage = usage;
VkBufferUsageFlags bufferUsage = ToVulkan(m_type);
VkMemoryPropertyFlags memoryProperties = 0;
if (usage & BufferUsage_DeviceLocal)
memoryProperties |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
if (usage & BufferUsage_DirectMapping)
memoryProperties |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
else
if ((usage & BufferUsage_DirectMapping) == 0)
bufferUsage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
if (!m_buffer.Create(m_device, 0, size, bufferUsage))
VkBufferCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
createInfo.size = size;
createInfo.usage = bufferUsage;
VmaAllocationCreateInfo allocInfo = {};
if (usage & BufferUsage_DeviceLocal)
{
NazaraError("Failed to create vulkan buffer");
return false;
if (usage & BufferUsage_DirectMapping)
allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
else
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
}
else
allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
VkMemoryRequirements memRequirement = m_buffer.GetMemoryRequirements();
if (usage & BufferUsage_PersistentMapping)
allocInfo.flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT;
if (!m_memory.Create(m_device, memRequirement.size, memRequirement.memoryTypeBits, memoryProperties))
VkResult result = vmaCreateBuffer(m_device.GetMemoryAllocator(), &createInfo, &allocInfo, &m_buffer, &m_allocation, nullptr);
if (result != VK_SUCCESS)
{
NazaraError("Failed to allocate buffer memory");
return false;
}
if (!m_buffer.BindBufferMemory(m_memory))
{
NazaraError("Failed to bind vertex buffer to its memory");
NazaraError("Failed to allocate buffer: " + TranslateVulkanError(result));
return false;
}
@@ -73,38 +78,37 @@ namespace Nz
{
if (m_usage & BufferUsage_DirectMapping)
{
if (!m_memory.Map(offset, size))
void* mappedPtr;
VkResult result = vmaMapMemory(m_device.GetMemoryAllocator(), m_allocation, &mappedPtr);
if (result != VK_SUCCESS)
{
NazaraError("Failed to map buffer: " + TranslateVulkanError(result));
return nullptr;
}
return m_memory.GetMappedPointer();
return static_cast<UInt8*>(mappedPtr) + offset;
}
else
{
if (!m_stagingBuffer.Create(m_device, 0, m_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT))
VkBufferCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
createInfo.size = size;
createInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
VmaAllocationCreateInfo allocInfo = {};
allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
VmaAllocationInfo allocationInfo;
VkResult result = vmaCreateBuffer(m_device.GetMemoryAllocator(), &createInfo, &allocInfo, &m_stagingBuffer, &m_stagingAllocation, &allocationInfo);
if (result != VK_SUCCESS)
{
NazaraError("Failed to create staging buffer");
NazaraError("Failed to allocate staging buffer: " + TranslateVulkanError(result));
return nullptr;
}
VkMemoryPropertyFlags memoryProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
VkMemoryRequirements memRequirement = m_stagingBuffer.GetMemoryRequirements();
if (!m_stagingMemory.Create(m_device, memRequirement.size, memRequirement.memoryTypeBits, memoryProperties))
{
NazaraError("Failed to allocate vertex buffer memory");
return nullptr;
}
if (!m_stagingBuffer.BindBufferMemory(m_stagingMemory))
{
NazaraError("Failed to bind vertex buffer to its memory");
return nullptr;
}
if (!m_stagingMemory.Map(offset, size))
return nullptr;
return m_stagingMemory.GetMappedPointer();
return allocationInfo.pMappedData;
}
}
@@ -112,20 +116,17 @@ namespace Nz
{
if (m_usage & BufferUsage_DirectMapping)
{
m_memory.Unmap();
vmaUnmapMemory(m_device.GetMemoryAllocator(), m_allocation);
return true;
}
else
{
m_stagingMemory.FlushMemory();
m_stagingMemory.Unmap();
Vk::CommandBuffer copyCommandBuffer = m_device.AllocateTransferCommandBuffer();
if (!copyCommandBuffer.Begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT))
Vk::AutoCommandBuffer copyCommandBuffer = m_device.AllocateTransferCommandBuffer();
if (!copyCommandBuffer->Begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT))
return false;
copyCommandBuffer.CopyBuffer(m_stagingBuffer, m_buffer, m_size);
if (!copyCommandBuffer.End())
copyCommandBuffer->CopyBuffer(m_stagingBuffer, m_buffer, m_size);
if (!copyCommandBuffer->End())
return false;
Vk::QueueHandle transferQueue = m_device.GetQueue(m_device.GetTransferQueueFamilyIndex(), 0);
@@ -134,8 +135,7 @@ namespace Nz
transferQueue.WaitIdle();
m_stagingBuffer.Destroy();
m_stagingMemory.Destroy();
vmaDestroyBuffer(m_device.GetMemoryAllocator(), m_stagingBuffer, m_stagingAllocation);
return true;
}
}