diff --git a/CMakeLists.txt b/CMakeLists.txt index e7b3836..563ce3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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}) diff --git a/src/main.cpp b/src/main.cpp index d8069fb..c97db21 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #define VULKAN_HPP_NO_CONSTRUCTORS @@ -32,6 +31,9 @@ #include +#define VMA_IMPLEMENTATION +#include + #define GLM_FORCE_DEPTH_ZERO_TO_ONE #include #include @@ -67,8 +69,8 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL VulkanExampleApplication_VulkanDebugCallba class VulkanExampleApplication { private: - using VulkanBuffer = std::optional>; - using VulkanImage = std::optional>; + using VulkanBuffer = std::optional>; + using VulkanImage = std::optional>; std::optional libsdl; std::optional window; @@ -82,6 +84,10 @@ private: std::optional vk_queue_graphics; std::optional vk_queue_present; +public: + vma::UniqueAllocator vk_allocator; + +public: std::optional 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(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(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(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(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::floor(std::log2(std::max(texture_buffer_extent.width, texture_buffer_extent.height)))) + 1; - std::uint8_t* const texture_buffer_data = static_cast(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(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(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*>(&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