Implimented the VMA - Vulkan Memory Allocator to hopefully make memory management easier.

This commit is contained in:
Rebekah 2024-07-24 19:51:11 -04:00
parent 214a5002e6
commit 4f71a9849c
Signed by: oneechanhax
GPG Key ID: 0074BF373B812798
2 changed files with 79 additions and 56 deletions

View File

@ -31,15 +31,23 @@ find_package(glm REQUIRED)
find_package(SDL2 REQUIRED)
find_package(SDL2pp REQUIRED)
find_package(Vulkan REQUIRED COMPONENTS glslc)
find_package(VulkanMemoryAllocator-Hpp REQUIRED)
#find_package(Doxygen)
add_executable(${PROJECT_NAME} "")
target_include_directories(${PROJECT_NAME} PRIVATE
Vulkan::Headers SDL2pp::Headers
SDL2pp::Headers
Vulkan::Headers
VulkanMemoryAllocator-Hpp::VulkanMemoryAllocator-Hpp
)
target_link_libraries(${PROJECT_NAME} Vulkan::Vulkan SDL2pp::SDL2pp)
target_link_libraries(${PROJECT_NAME} PUBLIC
SDL2pp::SDL2pp
Vulkan::Vulkan
VulkanMemoryAllocator-Hpp::VulkanMemoryAllocator-Hpp
)
file(GLOB_RECURSE sources "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
target_sources(${PROJECT_NAME} PRIVATE ${sources})

View File

@ -22,7 +22,6 @@
#include <iostream>
#include <vector>
#include <string_view>
#include <bitset>
#include <chrono>
#define VULKAN_HPP_NO_CONSTRUCTORS
@ -32,6 +31,9 @@
#include <SDL2pp/SDL2pp.hh>
#define VMA_IMPLEMENTATION
#include <vk_mem_alloc.hpp>
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
@ -67,8 +69,8 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL VulkanExampleApplication_VulkanDebugCallba
class VulkanExampleApplication {
private:
using VulkanBuffer = std::optional<std::pair<vk::raii::Buffer, vk::raii::DeviceMemory>>;
using VulkanImage = std::optional<std::pair<vk::raii::Image, vk::raii::DeviceMemory>>;
using VulkanBuffer = std::optional<std::pair<vma::UniqueBuffer, vma::UniqueAllocation>>;
using VulkanImage = std::optional<std::pair<vma::UniqueImage, vma::UniqueAllocation>>;
std::optional<SDL2pp::SDL> libsdl;
std::optional<SDL2pp::Window> window;
@ -82,6 +84,10 @@ private:
std::optional<vk::raii::Queue> vk_queue_graphics;
std::optional<vk::raii::Queue> vk_queue_present;
public:
vma::UniqueAllocator vk_allocator;
public:
std::optional<vk::raii::SwapchainKHR> vk_swapchain;
vk::Format vk_swapchain_image_format;
vk::Extent2D vk_swapchain_extent;
@ -442,6 +448,39 @@ public:
this->vk_queue_graphics.emplace(*this->vk_gpu, this->vk_physical_card_info.graphics_family.value(), 0);
this->vk_queue_present.emplace(*this->vk_gpu, this->vk_physical_card_info.present_family.value(), 0);
}
{ // initialize the vulkan memory allocator
// TODO: enable extensions... https://gpuopen-librariesandsdks.github.io/VulkanMemoryAllocator/html/quick_start.html#quick_start_initialization
const auto dispatcher_inst = this->vk_inst->getDispatcher();
const auto dispatcher_gpu = this->vk_gpu->getDispatcher();
const vma::VulkanFunctions vulkan_functions {
.vkGetInstanceProcAddr = dispatcher_inst->vkGetInstanceProcAddr,
.vkGetDeviceProcAddr = dispatcher_gpu->vkGetDeviceProcAddr,
.vkGetPhysicalDeviceProperties = dispatcher_inst->vkGetPhysicalDeviceProperties,
.vkGetPhysicalDeviceMemoryProperties = dispatcher_inst->vkGetPhysicalDeviceMemoryProperties,
.vkAllocateMemory = dispatcher_gpu->vkAllocateMemory,
.vkFreeMemory = dispatcher_gpu->vkFreeMemory,
.vkMapMemory = dispatcher_gpu->vkMapMemory,
.vkUnmapMemory = dispatcher_gpu->vkUnmapMemory,
.vkFlushMappedMemoryRanges = dispatcher_gpu->vkFlushMappedMemoryRanges,
.vkInvalidateMappedMemoryRanges = dispatcher_gpu->vkInvalidateMappedMemoryRanges,
.vkBindBufferMemory = dispatcher_gpu->vkBindBufferMemory,
.vkBindImageMemory = dispatcher_gpu->vkBindImageMemory,
.vkGetBufferMemoryRequirements = dispatcher_gpu->vkGetBufferMemoryRequirements,
.vkGetImageMemoryRequirements = dispatcher_gpu->vkGetImageMemoryRequirements,
.vkCreateBuffer = dispatcher_gpu->vkCreateBuffer,
.vkDestroyBuffer = dispatcher_gpu->vkDestroyBuffer,
.vkCreateImage = dispatcher_gpu->vkCreateImage,
.vkDestroyImage = dispatcher_gpu->vkDestroyImage,
.vkCmdCopyBuffer = dispatcher_gpu->vkCmdCopyBuffer
};
const vma::AllocatorCreateInfo allocator_create_info = {
.physicalDevice = **this->vk_gfx_card,
.device = **this->vk_gpu,
.pVulkanFunctions = &vulkan_functions,
.instance = **this->vk_inst
};
this->vk_allocator = vma::createAllocatorUnique(allocator_create_info);
}
{
this->CreateSwapchain();
}
@ -449,7 +488,6 @@ public:
this->CreateBufferColor();
}
{ // find depth format, needed before a few things
this->CreateBufferDepth();
}
{ // Load Shaders
@ -692,9 +730,7 @@ public:
const auto vertex_buffer_size = sizeof(quad_vertices[0]) * quad_vertices.size();
const auto vertex_buffer_staging = this->CreateBuffer(vertex_buffer_size, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
std::uint8_t* const vertex_buffer_data = static_cast<std::uint8_t*>(vertex_buffer_staging->second.mapMemory(0, vertex_buffer_size));
memcpy(vertex_buffer_data, quad_vertices.data(), vertex_buffer_size);
vertex_buffer_staging->second.unmapMemory();
this->vk_allocator->copyMemoryToAllocation(quad_vertices.data(), *vertex_buffer_staging->second, 0, vertex_buffer_size);
this->vk_buffer_vertex = CreateBuffer(vertex_buffer_size, vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eVertexBuffer, vk::MemoryPropertyFlagBits::eDeviceLocal);
this->CopyBuffer(*vertex_buffer_staging->first, *this->vk_buffer_vertex->first, vertex_buffer_size);
@ -703,9 +739,7 @@ public:
const auto index_buffer_size = sizeof(quad_indexes[0]) * quad_indexes.size();
const auto index_buffer_staging = this->CreateBuffer(index_buffer_size, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
std::uint8_t* const indicies_buffer_data = static_cast<std::uint8_t*>(index_buffer_staging->second.mapMemory(0, index_buffer_size));
memcpy(indicies_buffer_data, quad_indexes.data(), index_buffer_size);
index_buffer_staging->second.unmapMemory();
this->vk_allocator->copyMemoryToAllocation(quad_indexes.data(), *index_buffer_staging->second, 0, index_buffer_size);
this->vk_buffer_index = CreateBuffer(index_buffer_size, vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eIndexBuffer, vk::MemoryPropertyFlagBits::eDeviceLocal);
this->CopyBuffer(*index_buffer_staging->first, *this->vk_buffer_index->first, index_buffer_size);
@ -730,8 +764,9 @@ public:
this->vk_buffers_uniform_mapped.reserve(this->vk_max_frames_in_flight);
const vk::DeviceSize ubo_buffer_size = sizeof(UniformBufferObject);
for (std::size_t i = 0; i < this->vk_max_frames_in_flight; i++) {
auto uniform_buffer = this->CreateBuffer(ubo_buffer_size, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
this->vk_buffers_uniform_mapped.emplace_back(static_cast<std::uint8_t*>(uniform_buffer->second.mapMemory(0, ubo_buffer_size)));
vma::AllocationInfo alloc_info;
auto uniform_buffer = this->CreateBuffer(ubo_buffer_size, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, &alloc_info);
this->vk_buffers_uniform_mapped.emplace_back(static_cast<std::uint8_t*>(alloc_info.pMappedData));
this->vk_buffers_uniform.emplace_back(std::move(uniform_buffer));
}
}
@ -743,9 +778,7 @@ public:
this->vk_texture_mip_levels = static_cast<std::uint32_t>(std::floor(std::log2(std::max(texture_buffer_extent.width, texture_buffer_extent.height)))) + 1;
std::uint8_t* const texture_buffer_data = static_cast<std::uint8_t*>(texture_buffer_staging->second.mapMemory(0, texture_buffer_size));
memcpy(texture_buffer_data, embeded_debug_north_png_rgba.data.begin, texture_buffer_size);
texture_buffer_staging->second.unmapMemory();
this->vk_allocator->copyMemoryToAllocation(embeded_debug_north_png_rgba.data.begin, *texture_buffer_staging->second, 0, texture_buffer_size);
this->vk_texture_image = CreateImage(texture_buffer_extent, texture_format, vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled, vk::MemoryPropertyFlagBits::eDeviceLocal, this->vk_texture_mip_levels, vk::SampleCountFlagBits::e1);
@ -828,7 +861,7 @@ public:
GenerateMipmaps(command_buffer, *this->vk_texture_image->first, texture_format, texture_buffer_extent, this->vk_texture_mip_levels);
});
this->vk_texture_view = this->CreateImageView(this->vk_texture_image->first, texture_format, vk::ImageAspectFlagBits::eColor, this->vk_texture_mip_levels);
this->vk_texture_view = this->CreateImageView(*this->vk_texture_image->first, texture_format, vk::ImageAspectFlagBits::eColor, this->vk_texture_mip_levels);
}
{ // Sampler
const vk::SamplerCreateInfo sampler_create_info {
@ -1052,7 +1085,7 @@ private:
this->vk_msaa_samples = ClampToMaxSupportedMSAA(this->vk_msaa_samples_wanted);
this->vk_color_image = this->CreateImage(this->vk_swapchain_extent, this->vk_swapchain_image_format, vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eTransientAttachment | vk::ImageUsageFlagBits::eColorAttachment, vk::MemoryPropertyFlagBits::eDeviceLocal, 1, this->vk_msaa_samples);
this->vk_color_view = this->CreateImageView(this->vk_color_image->first, this->vk_swapchain_image_format, vk::ImageAspectFlagBits::eColor);
this->vk_color_view = this->CreateImageView(*this->vk_color_image->first, this->vk_swapchain_image_format, vk::ImageAspectFlagBits::eColor);
}
void CreateBufferDepth() {
/*const auto HasStencilComponent = [](vk::Format format) {
@ -1093,23 +1126,26 @@ private:
}
protected:
VulkanBuffer CreateBuffer(const vk::DeviceSize& wanted_size, const vk::BufferUsageFlags& wanted_usage, const vk::MemoryPropertyFlags& wanted_properties) const {
vma::AllocationCreateFlags GetAllocationFlags(const vk::BufferUsageFlags& wanted_usage, const vk::MemoryPropertyFlags& wanted_properties) const {
vma::AllocationCreateFlags ret;
if (wanted_properties & vk::MemoryPropertyFlagBits::eHostVisible)
ret |= vma::AllocationCreateFlagBits::eHostAccessSequentialWrite;
if (wanted_usage == vk::BufferUsageFlagBits::eUniformBuffer)
ret |= vma::AllocationCreateFlagBits::eMapped;
return ret;
}
VulkanBuffer CreateBuffer(const vk::DeviceSize& wanted_size, const vk::BufferUsageFlags& wanted_usage, const vk::MemoryPropertyFlags& wanted_properties, vma::AllocationInfo* allocation_info_return = nullptr) const {
const vk::BufferCreateInfo buffer_create_info {
.size = wanted_size,
.usage = wanted_usage,
.sharingMode = vk::SharingMode::eExclusive
};
auto allocated_buffer = vk::raii::Buffer(*this->vk_gpu, buffer_create_info);
const auto memory_requirements = allocated_buffer.getMemoryRequirements();
const vk::MemoryAllocateInfo vertex_allocate_info {
.allocationSize = memory_requirements.size,
.memoryTypeIndex = this->FindMemoryType(memory_requirements.memoryTypeBits, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent)
const vma::AllocationCreateInfo allocation_create_info = {
.flags = this->GetAllocationFlags(wanted_usage, wanted_properties),
.usage = vma::MemoryUsage::eAuto,
.requiredFlags = wanted_properties,
};
auto allocated_buffer_memory = vk::raii::DeviceMemory(*this->vk_gpu, vertex_allocate_info);
allocated_buffer.bindMemory(*allocated_buffer_memory, 0);
return std::make_pair<vk::raii::Buffer, vk::raii::DeviceMemory>(std::move(allocated_buffer), std::move(allocated_buffer_memory));
return (allocation_info_return != nullptr) ? this->vk_allocator->createBufferUnique(buffer_create_info, allocation_create_info, allocation_info_return) : this->vk_allocator->createBufferUnique(buffer_create_info, allocation_create_info);
};
VulkanImage CreateImage(const vk::Extent2D& image_size, const vk::Format& wanted_format, const vk::ImageTiling& wanted_tiling, const vk::ImageUsageFlags& wanted_usage, const vk::MemoryPropertyFlags& wanted_properties, const std::uint32_t mip_levels = 1, const vk::SampleCountFlagBits& msaa_samples = vk::SampleCountFlagBits::e1) const {
const vk::ImageCreateInfo image_create_info {
@ -1129,18 +1165,13 @@ protected:
.initialLayout = vk::ImageLayout::eUndefined,
//.flags = 0, // optional
};
auto allocated_image_texture = vk::raii::Image(*this->vk_gpu, image_create_info);
const auto memory_requirements = allocated_image_texture.getMemoryRequirements();
const vk::MemoryAllocateInfo image_allocate_info {
.allocationSize = memory_requirements.size,
.memoryTypeIndex = this->FindMemoryType(memory_requirements.memoryTypeBits, wanted_properties)
const vma::AllocationCreateInfo allocation_create_info = {
.usage = vma::MemoryUsage::eAuto,
.requiredFlags = wanted_properties
};
auto allocated_image_memory = vk::raii::DeviceMemory(*this->vk_gpu, image_allocate_info);
allocated_image_texture.bindMemory(*allocated_image_memory, 0);
return std::make_pair<vk::raii::Image, vk::raii::DeviceMemory>(std::move(allocated_image_texture), std::move(allocated_image_memory));
return this->vk_allocator->createImageUnique(image_create_info, allocation_create_info);
}
vk::raii::ImageView CreateImageView(const vk::Image& image_src, const vk::Format& wanted_format, const vk::ImageAspectFlags& flag_mask, const std::uint32_t mip_levels = 1) {
vk::raii::ImageView CreateImageView(const vk::Image& image_src, const vk::Format& wanted_format, const vk::ImageAspectFlags& flag_mask, const std::uint32_t mip_levels = 1) const {
const vk::ImageViewCreateInfo imageview_create_info {
.image = image_src,
.viewType = vk::ImageViewType::e2D,
@ -1154,22 +1185,6 @@ protected:
};
return vk::raii::ImageView(*this->vk_gpu, imageview_create_info);
}
const std::uint32_t FindMemoryType(const std::uint32_t& type_filter, const vk::MemoryPropertyFlags& wanted_properties) const {
const auto memory_properties = this->vk_gfx_card->getMemoryProperties();
const std::uint32_t memory_type_count = memory_properties.memoryTypeCount;
std::uint32_t memory_type_to_test;
for (memory_type_to_test = 0; memory_type_to_test < memory_type_count; memory_type_to_test++) {
if ((*reinterpret_cast<const std::bitset<sizeof(type_filter) * 8>*>(&type_filter))[memory_type_to_test]) {
if ((memory_properties.memoryTypes[memory_type_to_test].propertyFlags & wanted_properties) == wanted_properties) {
break;
}
}
}
if (memory_type_to_test == memory_type_count)
throw std::runtime_error("failed to find suitable memory type!");
return memory_type_to_test;
}
void CopyBuffer(const vk::CommandBuffer& command_buffer, const vk::Buffer& src_buffer, const vk::Buffer& dest_buffer, const vk::DeviceSize& size) const {
const vk::BufferCopy copy_region {
//.srcOffset = 0, // Optional