22#include "VulkanRenderer.hpp"
23#include "VulkanBuffer.hpp"
24#include "VulkanUtilities.hpp"
33 mVulkanRenderer { aVulkanRenderer },
36 mProperties { aProperties }
49 VulkanBuffer::~VulkanBuffer()
55 mVulkanRenderer { aBuffer.mVulkanRenderer }
57 std::swap ( mBuffer, aBuffer.mBuffer );
58 std::swap ( mSize, aBuffer.mSize );
59 std::swap ( mUsage, aBuffer.mUsage );
60 std::swap ( mProperties, aBuffer.mProperties );
61 std::swap ( mDeviceMemory, aBuffer.mDeviceMemory );
64 void VulkanBuffer::Initialize (
const VkDeviceSize aSize,
const VkBufferUsageFlags aUsage,
const VkMemoryPropertyFlags aProperties,
const void * aData )
66 if ( mDeviceMemory != VK_NULL_HANDLE || mBuffer != VK_NULL_HANDLE )
68 std::cout <<
LogLevel::Error <<
"Buffer already initialized." << std::endl;
69 throw ( std::runtime_error (
"Buffer already initialized." ) );
73 mProperties = aProperties;
86 if ( ( mProperties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT ) )
88 void* data =
Map ( aOffset, aSize );
89 memcpy ( data, aData, aSize );
92 else if ( ( mProperties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) && ( mUsage & VK_BUFFER_USAGE_TRANSFER_DST_BIT ) )
94 VulkanBuffer source ( mVulkanRenderer, aSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, aData );
95 VkCommandBuffer command_buffer = mVulkanRenderer.BeginSingleTimeCommands();
96 VkBufferCopy copy_region = {};
97 copy_region.size = aSize;
98 copy_region.dstOffset = aOffset;
99 vkCmdCopyBuffer ( command_buffer, source.
GetBuffer(), mBuffer, 1, ©_region );
100 mVulkanRenderer.EndSingleTimeCommands ( command_buffer );
107 void* data =
nullptr;
108 if ( mProperties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT )
110 if ( VkResult result = vkMapMemory ( mVulkanRenderer.GetDevice(), mDeviceMemory, aOffset, aSize, 0, &data ) )
112 std::ostringstream stream;
113 stream <<
"vkMapMemory failed for buffer. error code: ( " <<
GetVulkanResultString ( result ) <<
" )";
115 throw std::runtime_error ( stream.str().c_str() );
120 std::cout <<
LogLevel::Error <<
"The VkBuffer VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT property must be set to be able to map buffer memory." << std::endl;
121 throw std::runtime_error (
"The VkBuffer VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT property must be set to be able to map buffer memory." );
128 vkUnmapMemory ( mVulkanRenderer.GetDevice(), mDeviceMemory );
142 VkBufferCreateInfo buffer_create_info{};
143 buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
144 buffer_create_info.pNext =
nullptr;
145 buffer_create_info.flags = 0;
146 buffer_create_info.size = mSize;
147 buffer_create_info.usage = mUsage;
148 buffer_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
149 buffer_create_info.queueFamilyIndexCount = 0;
150 buffer_create_info.pQueueFamilyIndices =
nullptr;
152 if ( VkResult result = vkCreateBuffer ( mVulkanRenderer.GetDevice(), &buffer_create_info,
nullptr, &mBuffer ) )
154 std::ostringstream stream;
155 stream <<
"vkCreateBuffer failed for vertex buffer. error code: ( " <<
GetVulkanResultString ( result ) <<
" )";
156 std::string error_string = stream.str();
158 throw std::runtime_error ( error_string.c_str() );
161 VkMemoryRequirements memory_requirements;
162 vkGetBufferMemoryRequirements ( mVulkanRenderer.GetDevice(), mBuffer, &memory_requirements );
164 VkMemoryAllocateInfo memory_allocate_info{};
165 memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
166 memory_allocate_info.pNext =
nullptr;
167 memory_allocate_info.allocationSize = memory_requirements.size;
168 memory_allocate_info.memoryTypeIndex = mVulkanRenderer.GetMemoryTypeIndex ( mProperties );
170 if ( memory_allocate_info.memoryTypeIndex == std::numeric_limits<uint32_t>::max() )
172 std::cout <<
LogLevel::Error <<
"No suitable memory type found for buffer." << std::endl;
173 throw std::runtime_error (
"No suitable memory type found for buffer." );
176 if ( VkResult result = vkAllocateMemory ( mVulkanRenderer.GetDevice(), &memory_allocate_info,
nullptr, &mDeviceMemory ) )
178 std::ostringstream stream;
179 stream <<
"vkAllocateMemory failed for buffer. error code: ( " <<
GetVulkanResultString ( result ) <<
" )";
181 throw std::runtime_error ( stream.str().c_str() );
183 vkBindBufferMemory ( mVulkanRenderer.GetDevice(), mBuffer, mDeviceMemory, 0 );
192 if ( ( mDeviceMemory != VK_NULL_HANDLE ) || ( mBuffer != VK_NULL_HANDLE ) )
194 if ( VkResult result = vkQueueWaitIdle ( mVulkanRenderer.GetQueue() ) )
196 std::cout <<
GetVulkanResultString ( result ) <<
" " << __func__ <<
" " << __LINE__ <<
" " << std::endl;
199 if ( mBuffer != VK_NULL_HANDLE )
201 vkDestroyBuffer ( mVulkanRenderer.GetDevice(), mBuffer,
nullptr );
202 mBuffer = VK_NULL_HANDLE;
204 if ( mDeviceMemory != VK_NULL_HANDLE )
206 vkFreeMemory ( mVulkanRenderer.GetDevice(), mDeviceMemory,
nullptr );
207 mDeviceMemory = VK_NULL_HANDLE;
Defines log severity levels and stream output for the AeonGames engine.
size_t GetSize() const final
Get the total size of the buffer in bytes.
VulkanBuffer(const VulkanRenderer &aVulkanRenderer)
Construct an uninitialized buffer.
void WriteMemory(const size_t aOffset, const size_t aSize, const void *aData=nullptr) const final
Write data into the buffer at a given offset.
void * Map(const size_t aOffset, size_t aSize) const final
Map a region of the buffer into CPU-accessible memory.
void Initialize(const VkDeviceSize aSize, const VkBufferUsageFlags aUsage, const VkMemoryPropertyFlags aProperties, const void *aData=nullptr)
Initialize the buffer with the given size, usage, memory properties, and optional data.
const VkBuffer & GetBuffer() const
Get the underlying Vulkan buffer handle.
void Finalize()
Release the Vulkan buffer and its device memory.
void Unmap() const final
Unmap a previously mapped buffer region.
Vulkan rendering backend implementing the Renderer interface.
<- This is here just for the literals
const char * GetVulkanResultString(VkResult aResult)
Convert a VkResult code to a human-readable string.
@ Info
General informational messages.