/*
VulkanFramework
by John Ryland
Copyright (c) 2023
*/
////////////////////////////////////////////////////////////////////////////////////
// Vulkan Buffer
#include "VulkanBuffer.h"
#include <cstring>
namespace Vulkan {
Buffer::Buffer()
: m_buffer(nullptr)
, m_memory(nullptr)
{
}
// virtual
Buffer::~Buffer()
{
Destroy();
}
// virtual
void Buffer::Initialize(Device* device, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties)
{
m_owner = device;
m_size = size;
m_usage = usage;
m_properties = properties;
Create();
}
// virtual
void Buffer::Create()
{
size_t BufferMemoryAlignment = 256;
VkDeviceSize vertex_buffer_size_aligned = ((m_size - 1) / BufferMemoryAlignment + 1) * BufferMemoryAlignment;
VkBufferCreateInfo buffer_info = {};
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
buffer_info.size = vertex_buffer_size_aligned;
buffer_info.usage = m_usage;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
m_owner->CheckResult(vkCreateBuffer(m_owner->m_device, &buffer_info, m_owner->m_allocator, &m_buffer));
VkMemoryRequirements req;
vkGetBufferMemoryRequirements(m_owner->m_device, m_buffer, &req);
//BufferMemoryAlignment = (BufferMemoryAlignment > req.alignment) ? BufferMemoryAlignment : req.alignment;
VkMemoryAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = req.size;
alloc_info.memoryTypeIndex = m_owner->FindMemoryType(req.memoryTypeBits, m_properties);
m_owner->CheckResult(vkAllocateMemory(m_owner->m_device, &alloc_info, m_owner->m_allocator, &m_memory));
m_owner->CheckResult(vkBindBufferMemory(m_owner->m_device, m_buffer, m_memory, 0));
m_size = req.size;
}
// virtual
void Buffer::Destroy()
{
if (m_buffer)
vkDestroyBuffer(m_owner->m_device, m_buffer, m_owner->m_allocator);
if (m_memory)
vkFreeMemory(m_owner->m_device, m_memory, m_owner->m_allocator);
m_buffer = nullptr;
m_memory = nullptr;
m_size = 0;
}
// virtual
void Buffer::Resize(size_t size)
{
m_size = size;
Destroy();
Create();
}
// virtual
void Buffer::UploadDataUsingStagingBuffer(const uint8_t* data)
{
Vulkan::Buffer staging;
staging.Initialize(m_owner, m_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
staging.UploadData(m_size, data);
{
auto commandBuffer = m_owner->BeginSingleTimeCommands();
VkBufferCopy copyRegion {};
copyRegion.size = m_size;
vkCmdCopyBuffer(commandBuffer.m_commandBuffer, staging.m_buffer, m_buffer, 1, ©Region);
}
staging.Destroy();
}
// virtual
void Buffer::UploadData(size_t size, std::function<void(void*)> callback)
{
if (!m_buffer || m_size < size)
Resize(size);
void* ptr;
m_owner->CheckResult(vkMapMemory(m_owner->m_device, m_memory, 0, m_size, 0, (void**)(&ptr)));
callback(ptr);
VkMappedMemoryRange range{ VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, m_memory, 0, VK_WHOLE_SIZE };
m_owner->CheckResult(vkFlushMappedMemoryRanges(m_owner->m_device, 1, &range));
vkUnmapMemory(m_owner->m_device, m_memory);
}
// virtual
void Buffer::UploadData(size_t size, const uint8_t* data)
{
UploadData(size, [size, data](void* dst){ memcpy(dst, data, size); });
}
} // Vulkan namespace