Use vma in GEVulkanDynamicBuffer

This commit is contained in:
Benau 2022-07-13 11:23:08 +08:00
parent b0f91ff33d
commit cf8bafaab3
2 changed files with 59 additions and 97 deletions

View File

@ -9,7 +9,7 @@
namespace GE
{
VkMemoryPropertyFlags GEVulkanDynamicBuffer::m_host_flag = (VkMemoryPropertyFlags)-1;
int GEVulkanDynamicBuffer::m_supports_host_transfer = -1;
// ----------------------------------------------------------------------------
GEVulkanDynamicBuffer::GEVulkanDynamicBuffer(GEVulkanDynamicBufferType t,
VkBufferUsageFlags usage,
@ -20,12 +20,12 @@ GEVulkanDynamicBuffer::GEVulkanDynamicBuffer(GEVulkanDynamicBufferType t,
m_size = m_real_size = initial_size;
m_buffer = new VkBuffer[GEVulkanDriver::getMaxFrameInFlight()];
m_memory = new VkDeviceMemory[GEVulkanDriver::getMaxFrameInFlight()];
m_memory = new VmaAllocation[GEVulkanDriver::getMaxFrameInFlight()];
m_mapped_addr = new void*[GEVulkanDriver::getMaxFrameInFlight()];
if (t == GVDBT_GPU_RAM)
{
m_staging_buffer = new VkBuffer[GEVulkanDriver::getMaxFrameInFlight()];
m_staging_memory = new VkDeviceMemory[GEVulkanDriver::getMaxFrameInFlight()];
m_staging_memory = new VmaAllocation[GEVulkanDriver::getMaxFrameInFlight()];
}
else
{
@ -51,6 +51,7 @@ GEVulkanDynamicBuffer::~GEVulkanDynamicBuffer()
// ----------------------------------------------------------------------------
void GEVulkanDynamicBuffer::initPerFrame(unsigned frame)
{
GEVulkanDriver* vk = getVKDriver();
m_buffer[frame] = VK_NULL_HANDLE;
m_memory[frame] = VK_NULL_HANDLE;
m_mapped_addr[frame] = NULL;
@ -60,128 +61,85 @@ void GEVulkanDynamicBuffer::initPerFrame(unsigned frame)
m_staging_memory[frame] = VK_NULL_HANDLE;
}
start:
VkMemoryPropertyFlags prop = {};
VkBuffer host_buffer = VK_NULL_HANDLE;
VkDeviceMemory host_memory = VK_NULL_HANDLE;
VkMemoryPropertyFlags host_flag = 0;
if (m_host_flag == (VkFlags)-1)
VmaAllocation host_memory = VK_NULL_HANDLE;
VmaAllocationCreateInfo host_info = {};
host_info.usage = VMA_MEMORY_USAGE_AUTO;
host_info.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
VMA_ALLOCATION_CREATE_MAPPED_BIT;
host_info.preferredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
if ((m_type == GVDBT_SYSTEM_RAM && m_supports_host_transfer == 1) ||
(m_type == GVDBT_SYSTEM_RAM && m_supports_host_transfer == -1))
{
// https://zeux.io/2020/02/27/writing-an-efficient-vulkan-renderer/
m_host_flag = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
bool better_flag_exist = false;
if (getVKDriver()->createBuffer(m_size,
m_usage | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, m_host_flag,
host_buffer, host_memory))
{
better_flag_exist = true;
if (m_type == GVDBT_SYSTEM_RAM)
goto succeed;
}
if (host_buffer != VK_NULL_HANDLE)
vkDestroyBuffer(getVKDriver()->getDevice(), host_buffer, NULL);
host_buffer = VK_NULL_HANDLE;
if (host_memory != VK_NULL_HANDLE)
vkFreeMemory(getVKDriver()->getDevice(), host_memory, NULL);
host_memory = VK_NULL_HANDLE;
if (!better_flag_exist)
{
m_host_flag = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
}
host_info.flags |=
VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT;
}
host_flag = m_host_flag;
// From the above website:
// This flag should be used to store staging buffers that are used to
// populate static resources allocated with
// VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT with data.
if (m_type == GVDBT_GPU_RAM)
if (!vk->createBuffer(m_size, m_usage | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
host_info, host_buffer, host_memory))
{
host_flag = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
}
if (!getVKDriver()->createBuffer(m_size,
m_usage | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, host_flag,
host_buffer, host_memory))
{
if (host_buffer != VK_NULL_HANDLE)
vkDestroyBuffer(getVKDriver()->getDevice(), host_buffer, NULL);
if (host_memory != VK_NULL_HANDLE)
vkFreeMemory(getVKDriver()->getDevice(), host_memory, NULL);
vmaDestroyBuffer(vk->getVmaAllocator(), host_buffer, host_memory);
return;
}
succeed:
if (m_type == GVDBT_SYSTEM_RAM && m_supports_host_transfer == -1)
{
vmaGetAllocationMemoryProperties(vk->getVmaAllocator(), host_memory,
&prop);
if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
{
m_supports_host_transfer = 0;
vmaDestroyBuffer(vk->getVmaAllocator(), host_buffer, host_memory);
goto start;
}
else
m_supports_host_transfer = 1;
}
VmaAllocationInfo info = {};
vmaGetAllocationInfo(vk->getVmaAllocator(), host_memory, &info);
if (m_type == GVDBT_SYSTEM_RAM)
{
m_buffer[frame] = host_buffer;
m_memory[frame] = host_memory;
if (vkMapMemory(getVKDriver()->getDevice(), m_memory[frame], 0, m_size,
0, &m_mapped_addr[frame]) != VK_SUCCESS)
{
destroyPerFrame(frame);
}
m_mapped_addr[frame] = info.pMappedData;
return;
}
VkBuffer local_buffer = VK_NULL_HANDLE;
VkDeviceMemory local_memory = VK_NULL_HANDLE;
if (!getVKDriver()->createBuffer(m_size,
m_usage | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, local_buffer, local_memory))
VmaAllocation local_memory = VK_NULL_HANDLE;
VmaAllocationCreateInfo local_info = {};
local_info.usage = VMA_MEMORY_USAGE_AUTO;
if (!vk->createBuffer(m_size, m_usage | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
local_info, local_buffer, local_memory))
{
if (host_buffer != VK_NULL_HANDLE)
vkDestroyBuffer(getVKDriver()->getDevice(), host_buffer, NULL);
if (host_memory != VK_NULL_HANDLE)
vkFreeMemory(getVKDriver()->getDevice(), host_memory, NULL);
if (local_buffer != VK_NULL_HANDLE)
vkDestroyBuffer(getVKDriver()->getDevice(), local_buffer, NULL);
if (local_memory != VK_NULL_HANDLE)
vkFreeMemory(getVKDriver()->getDevice(), local_memory, NULL);
vmaDestroyBuffer(vk->getVmaAllocator(), host_buffer, host_memory);
vmaDestroyBuffer(vk->getVmaAllocator(), local_buffer, local_memory);
return;
}
m_buffer[frame] = local_buffer;
m_memory[frame] = local_memory;
m_staging_buffer[frame] = host_buffer;
m_staging_memory[frame] = host_memory;
if (vkMapMemory(getVKDriver()->getDevice(), m_staging_memory[frame], 0,
m_size, 0, &m_mapped_addr[frame]) != VK_SUCCESS)
{
destroyPerFrame(frame);
}
m_mapped_addr[frame] = info.pMappedData;
} // initPerFrame
// ----------------------------------------------------------------------------
void GEVulkanDynamicBuffer::destroyPerFrame(unsigned frame)
{
if ((m_staging_memory && m_staging_memory[frame] != VK_NULL_HANDLE) ||
m_memory[frame] != VK_NULL_HANDLE)
{
vkUnmapMemory(getVKDriver()->getDevice(), m_type == GVDBT_GPU_RAM ?
m_staging_memory[frame] : m_memory[frame]);
}
if (m_memory[frame] != VK_NULL_HANDLE)
vkFreeMemory(getVKDriver()->getDevice(), m_memory[frame], NULL);
if (m_buffer[frame] != VK_NULL_HANDLE)
vkDestroyBuffer(getVKDriver()->getDevice(), m_buffer[frame], NULL);
GEVulkanDriver* vk = getVKDriver();
vmaDestroyBuffer(vk->getVmaAllocator(), m_buffer[frame], m_memory[frame]);
m_buffer[frame] = VK_NULL_HANDLE;
m_memory[frame] = VK_NULL_HANDLE;
m_mapped_addr[frame] = NULL;
if (m_type == GVDBT_GPU_RAM)
{
if (m_staging_buffer[frame] != VK_NULL_HANDLE)
vkDestroyBuffer(getVKDriver()->getDevice(), m_staging_buffer[frame], NULL);
if (m_staging_memory[frame] != VK_NULL_HANDLE)
vkFreeMemory(getVKDriver()->getDevice(), m_staging_memory[frame], NULL);
vmaDestroyBuffer(vk->getVmaAllocator(), m_staging_buffer[frame],
m_staging_memory[frame]);
m_staging_buffer[frame] = VK_NULL_HANDLE;
m_staging_memory[frame] = VK_NULL_HANDLE;
}
@ -198,7 +156,8 @@ void GEVulkanDynamicBuffer::destroy()
// ----------------------------------------------------------------------------
void GEVulkanDynamicBuffer::setCurrentData(void* data, size_t size)
{
const unsigned cur_frame = getVKDriver()->getCurrentFrame();
GEVulkanDriver* vk = getVKDriver();
const unsigned cur_frame = vk->getCurrentFrame();
if (size > m_size)
{
destroy();
@ -210,11 +169,14 @@ void GEVulkanDynamicBuffer::setCurrentData(void* data, size_t size)
if (size == 0 || m_mapped_addr[cur_frame] == NULL)
return;
memcpy(m_mapped_addr[cur_frame], data, size);
vmaFlushAllocation(vk->getVmaAllocator(), m_staging_memory != NULL ?
m_staging_memory[cur_frame] : m_memory[cur_frame], 0, size);
if (m_type == GVDBT_GPU_RAM)
{
VkBufferCopy copy_region = {};
copy_region.size = size;
vkCmdCopyBuffer(getVKDriver()->getCurrentCommandBuffer(),
vkCmdCopyBuffer(vk->getCurrentCommandBuffer(),
m_staging_buffer[cur_frame], m_buffer[cur_frame], 1, &copy_region);
}
} // setCurrentData

View File

@ -2,6 +2,7 @@
#define HEADER_GE_VULKAN_DYNAMIC_BUFFER_HPP
#include "vulkan_wrapper.h"
#include "ge_vma.hpp"
namespace GE
{
@ -17,11 +18,11 @@ class GEVulkanDynamicBuffer
private:
VkBuffer* m_buffer;
VkDeviceMemory* m_memory;
VmaAllocation* m_memory;
VkBuffer* m_staging_buffer;
VkDeviceMemory* m_staging_memory;
VmaAllocation* m_staging_memory;
void** m_mapped_addr;
@ -29,10 +30,9 @@ private:
GEVulkanDynamicBufferType m_type;
static VkMemoryPropertyFlags m_host_flag;
size_t m_size, m_real_size;
static int m_supports_host_transfer;
// ------------------------------------------------------------------------
void initPerFrame(unsigned frame);
// ------------------------------------------------------------------------