Implimented the VMA - Vulkan Memory Allocator to hopefully make memory management easier.
This commit is contained in:
parent
214a5002e6
commit
4f71a9849c
@ -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})
|
||||
|
123
src/main.cpp
123
src/main.cpp
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user