From 292eb1de1b954cf8d802435ac264ef5e1ae7fc96 Mon Sep 17 00:00:00 2001 From: Tobias Frisch <tfrisch@uni-koblenz.de> Date: Fri, 9 Jul 2021 20:19:51 +0200 Subject: [PATCH] [#59] Implemented VMA into buffer and image managers Signed-off-by: Tobias Frisch <tfrisch@uni-koblenz.de> --- include/vkcv/BufferManager.hpp | 4 +- src/vkcv/BufferManager.cpp | 129 ++++++++++++--------------------- src/vkcv/ImageManager.cpp | 92 ++++++++++++----------- src/vkcv/ImageManager.hpp | 37 ++++------ 4 files changed, 108 insertions(+), 154 deletions(-) diff --git a/include/vkcv/BufferManager.hpp b/include/vkcv/BufferManager.hpp index 9eb80d70..c7f32d9f 100644 --- a/include/vkcv/BufferManager.hpp +++ b/include/vkcv/BufferManager.hpp @@ -2,6 +2,7 @@ #include <vector> #include <vulkan/vulkan.hpp> +#include <vk_mem_alloc.hpp> #include "Handles.hpp" @@ -30,9 +31,8 @@ namespace vkcv struct Buffer { vk::Buffer m_handle; - vk::DeviceMemory m_memory; + vma::Allocation m_allocation; size_t m_size = 0; - void* m_mapped = nullptr; bool m_mappable = false; }; diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp index aec96411..cfa23329 100644 --- a/src/vkcv/BufferManager.cpp +++ b/src/vkcv/BufferManager.cpp @@ -28,32 +28,6 @@ namespace vkcv { } } - /** - * @brief searches memory type index for buffer allocation, combines requirements of buffer and application - * @param physicalMemoryProperties Memory Properties of physical device - * @param typeBits Bit field for suitable memory types - * @param requirements Property flags that are required - * @return memory type index for Buffer - */ - uint32_t searchBufferMemoryType(const vk::PhysicalDeviceMemoryProperties& physicalMemoryProperties, uint32_t typeBits, vk::MemoryPropertyFlags requirements) { - const uint32_t memoryCount = physicalMemoryProperties.memoryTypeCount; - for (uint32_t memoryIndex = 0; memoryIndex < memoryCount; ++memoryIndex) { - const uint32_t memoryTypeBits = (1 << memoryIndex); - const bool isRequiredMemoryType = typeBits & memoryTypeBits; - - const vk::MemoryPropertyFlags properties = - physicalMemoryProperties.memoryTypes[memoryIndex].propertyFlags; - const bool hasRequiredProperties = - (properties & requirements) == requirements; - - if (isRequiredMemoryType && hasRequiredProperties) - return static_cast<int32_t>(memoryIndex); - } - - // failed to find memory type - return -1; - } - BufferHandle BufferManager::createBuffer(BufferType type, size_t size, BufferMemoryType memoryType) { vk::BufferCreateFlags createFlags; vk::BufferUsageFlags usageFlags; @@ -83,43 +57,48 @@ namespace vkcv { usageFlags |= vk::BufferUsageFlagBits::eTransferDst; } - const vk::Device& device = m_core->getContext().getDevice(); - - vk::Buffer buffer = device.createBuffer( - vk::BufferCreateInfo(createFlags, size, usageFlags) - ); - - const vk::MemoryRequirements requirements = device.getBufferMemoryRequirements(buffer); - const vk::PhysicalDevice& physicalDevice = m_core->getContext().getPhysicalDevice(); + const vma::Allocator& allocator = m_core->getContext().getAllocator(); vk::MemoryPropertyFlags memoryTypeFlags; + vma::MemoryUsage memoryUsage; bool mappable = false; switch (memoryType) { case BufferMemoryType::DEVICE_LOCAL: memoryTypeFlags = vk::MemoryPropertyFlagBits::eDeviceLocal; + memoryUsage = vma::MemoryUsage::eGpuOnly; + mappable = false; break; case BufferMemoryType::HOST_VISIBLE: memoryTypeFlags = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent; + memoryUsage = vma::MemoryUsage::eCpuOnly; mappable = true; break; default: - // TODO: maybe an issue + vkcv_log(LogLevel::WARNING, "Unknown buffer memory type"); + memoryUsage = vma::MemoryUsage::eUnknown; + mappable = false; break; } - const uint32_t memoryTypeIndex = searchBufferMemoryType( - physicalDevice.getMemoryProperties(), - requirements.memoryTypeBits, - memoryTypeFlags + auto bufferAllocation = allocator.createBuffer( + vk::BufferCreateInfo(createFlags, size, usageFlags), + vma::AllocationCreateInfo( + vma::AllocationCreateFlags(), + memoryUsage, + memoryTypeFlags, + memoryTypeFlags, + 0, + vma::Pool(), + nullptr + ) ); - vk::DeviceMemory memory = device.allocateMemory(vk::MemoryAllocateInfo(requirements.size, memoryTypeIndex)); - - device.bindBufferMemory(buffer, memory, 0); + vk::Buffer buffer = bufferAllocation.first; + vma::Allocation allocation = bufferAllocation.second; const uint64_t id = m_buffers.size(); - m_buffers.push_back({ buffer, memory, size, nullptr, mappable }); + m_buffers.push_back({ buffer, allocation, size, mappable }); return BufferHandle(id, [&](uint64_t id) { destroyBufferById(id); }); } @@ -130,7 +109,7 @@ namespace vkcv { vk::Buffer buffer; vk::Buffer stagingBuffer; - vk::DeviceMemory stagingMemory; + vma::Allocation stagingAllocation; size_t stagingLimit; size_t stagingPosition; @@ -150,11 +129,11 @@ namespace vkcv { const size_t remaining = info.size - info.stagingPosition; const size_t mapped_size = std::min(remaining, info.stagingLimit); - const vk::Device& device = core->getContext().getDevice(); + const vma::Allocator& allocator = core->getContext().getAllocator(); - void* mapped = device.mapMemory(info.stagingMemory, 0, mapped_size); + void* mapped = allocator.mapMemory(info.stagingAllocation); memcpy(mapped, reinterpret_cast<const char*>(info.data) + info.stagingPosition, mapped_size); - device.unmapMemory(info.stagingMemory); + allocator.unmapMemory(info.stagingAllocation); SubmitInfo submitInfo; submitInfo.queueType = QueueType::Transfer; @@ -216,7 +195,13 @@ namespace vkcv { auto& buffer = m_buffers[id]; - return buffer.m_memory; + const vma::Allocator& allocator = m_core->getContext().getAllocator(); + + auto info = allocator.getAllocationInfo( + buffer.m_allocation + ); + + return info.deviceMemory; } void BufferManager::fillBuffer(const BufferHandle& handle, const void *data, size_t size, size_t offset) { @@ -232,11 +217,7 @@ namespace vkcv { auto& buffer = m_buffers[id]; - if (buffer.m_mapped) { - return; - } - - const vk::Device& device = m_core->getContext().getDevice(); + const vma::Allocator& allocator = m_core->getContext().getAllocator(); if (offset > buffer.m_size) { return; @@ -245,9 +226,9 @@ namespace vkcv { const size_t max_size = std::min(size, buffer.m_size - offset); if (buffer.m_mappable) { - void* mapped = device.mapMemory(buffer.m_memory, offset, max_size); - memcpy(mapped, data, max_size); - device.unmapMemory(buffer.m_memory); + void* mapped = allocator.mapMemory(buffer.m_allocation); + memcpy(reinterpret_cast<char*>(mapped) + offset, data, max_size); + allocator.unmapMemory(buffer.m_allocation); } else { auto& stagingBuffer = m_buffers[ m_stagingBuffer.getId() ]; @@ -258,11 +239,9 @@ namespace vkcv { info.buffer = buffer.m_handle; info.stagingBuffer = stagingBuffer.m_handle; - info.stagingMemory = stagingBuffer.m_memory; + info.stagingAllocation = stagingBuffer.m_allocation; - const vk::MemoryRequirements stagingRequirements = device.getBufferMemoryRequirements(stagingBuffer.m_handle); - - info.stagingLimit = stagingRequirements.size; + info.stagingLimit = stagingBuffer.m_size; info.stagingPosition = 0; copyFromStagingBuffer(m_core, info); @@ -282,19 +261,13 @@ namespace vkcv { auto& buffer = m_buffers[id]; - if (buffer.m_mapped) { - return nullptr; - } - - const vk::Device& device = m_core->getContext().getDevice(); + const vma::Allocator& allocator = m_core->getContext().getAllocator(); if (offset > buffer.m_size) { return nullptr; } - const size_t max_size = std::min(size, buffer.m_size - offset); - buffer.m_mapped = device.mapMemory(buffer.m_memory, offset, max_size); - return buffer.m_mapped; + return reinterpret_cast<char*>(allocator.mapMemory(buffer.m_allocation)) + offset; } void BufferManager::unmapBuffer(const BufferHandle& handle) { @@ -306,14 +279,9 @@ namespace vkcv { auto& buffer = m_buffers[id]; - if (buffer.m_mapped == nullptr) { - return; - } - - const vk::Device& device = m_core->getContext().getDevice(); + const vma::Allocator& allocator = m_core->getContext().getAllocator(); - device.unmapMemory(buffer.m_memory); - buffer.m_mapped = nullptr; + allocator.unmapMemory(buffer.m_allocation); } void BufferManager::destroyBufferById(uint64_t id) { @@ -323,16 +291,13 @@ namespace vkcv { auto& buffer = m_buffers[id]; - const vk::Device& device = m_core->getContext().getDevice(); - - if (buffer.m_memory) { - device.freeMemory(buffer.m_memory); - buffer.m_memory = nullptr; - } + const vma::Allocator& allocator = m_core->getContext().getAllocator(); if (buffer.m_handle) { - device.destroyBuffer(buffer.m_handle); + allocator.destroyBuffer(buffer.m_handle, buffer.m_allocation); + buffer.m_handle = nullptr; + buffer.m_allocation = nullptr; } } diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp index ba96cf8f..1cb6ad3a 100644 --- a/src/vkcv/ImageManager.cpp +++ b/src/vkcv/ImageManager.cpp @@ -12,26 +12,6 @@ namespace vkcv { - ImageManager::Image::Image( - vk::Image handle, - vk::DeviceMemory memory, - std::vector<vk::ImageView> views, - uint32_t width, - uint32_t height, - uint32_t depth, - vk::Format format, - uint32_t layers) - : - m_handle(handle), - m_memory(memory), - m_viewPerMip(views), - m_width(width), - m_height(height), - m_depth(depth), - m_format(format), - m_layers(layers) - {} - /** * @brief searches memory type index for image allocation, combines requirements of image and application * @param physicalMemoryProperties Memory Properties of physical device @@ -124,7 +104,7 @@ namespace vkcv { imageUsageFlags |= vk::ImageUsageFlagBits::eDepthStencilAttachment; } - const vk::Device& device = m_core->getContext().getDevice(); + const vma::Allocator& allocator = m_core->getContext().getAllocator(); vk::ImageType imageType = vk::ImageType::e3D; vk::ImageViewType imageViewType = vk::ImageViewType::e3D; @@ -158,7 +138,7 @@ namespace vkcv { vk::SampleCountFlagBits sampleCountFlag = msaaToVkSampleCountFlag(msaa); - const vk::ImageCreateInfo imageCreateInfo( + const vk::ImageCreateInfo imageCreateInfo ( createFlags, imageType, format, @@ -172,21 +152,22 @@ namespace vkcv { {}, vk::ImageLayout::eUndefined ); - - vk::Image image = device.createImage(imageCreateInfo); - const vk::MemoryRequirements requirements = device.getImageMemoryRequirements(image); - - vk::MemoryPropertyFlags memoryTypeFlags = vk::MemoryPropertyFlagBits::eDeviceLocal; - - const uint32_t memoryTypeIndex = searchImageMemoryType( - physicalDevice.getMemoryProperties(), - requirements.memoryTypeBits, - memoryTypeFlags + auto imageAllocation = allocator.createImage( + imageCreateInfo, + vma::AllocationCreateInfo( + vma::AllocationCreateFlags(), + vma::MemoryUsage::eGpuOnly, + vk::MemoryPropertyFlagBits::eDeviceLocal, + vk::MemoryPropertyFlagBits::eDeviceLocal, + 0, + vma::Pool(), + nullptr + ) ); - vk::DeviceMemory memory = device.allocateMemory(vk::MemoryAllocateInfo(requirements.size, memoryTypeIndex)); - device.bindImageMemory(image, memory, 0); + vk::Image image = imageAllocation.first; + vma::Allocation allocation = imageAllocation.second; vk::ImageAspectFlags aspectFlags; @@ -196,6 +177,8 @@ namespace vkcv { aspectFlags = vk::ImageAspectFlagBits::eColor; } + const vk::Device& device = m_core->getContext().getDevice(); + std::vector<vk::ImageView> views; for (uint32_t mip = 0; mip < mipCount; mip++) { const vk::ImageViewCreateInfo imageViewCreateInfo( @@ -222,11 +205,11 @@ namespace vkcv { } const uint64_t id = m_images.size(); - m_images.push_back(Image(image, memory, views, width, height, depth, format, arrayLayers)); + m_images.push_back({ image, allocation, views, width, height, depth, format, arrayLayers, vk::ImageLayout::eUndefined }); return ImageHandle(id, [&](uint64_t id) { destroyImageById(id); }); } - ImageHandle ImageManager::createSwapchainImage() { + ImageHandle ImageManager::createSwapchainImage() const { return ImageHandle::createSwapchainImageHandle(); } @@ -262,10 +245,16 @@ namespace vkcv { auto& image = m_images[id]; - return image.m_memory; + const vma::Allocator& allocator = m_core->getContext().getAllocator(); + + auto info = allocator.getAllocationInfo( + image.m_allocation + ); + + return info.deviceMemory; } - vk::ImageView ImageManager::getVulkanImageView(const ImageHandle &handle, const size_t mipLevel) const { + vk::ImageView ImageManager::getVulkanImageView(const ImageHandle &handle, size_t mipLevel) const { if (handle.isSwapchainImage()) { return m_swapchainImages[m_currentSwapchainInputImage].m_viewPerMip[0]; @@ -626,15 +615,14 @@ namespace vkcv { view = nullptr; } } - - if (image.m_memory) { - device.freeMemory(image.m_memory); - image.m_memory = nullptr; - } + + const vma::Allocator& allocator = m_core->getContext().getAllocator(); if (image.m_handle) { - device.destroyImage(image.m_handle); + allocator.destroyImage(image.m_handle, image.m_allocation); + image.m_handle = nullptr; + image.m_allocation = nullptr; } } @@ -670,11 +658,11 @@ namespace vkcv { m_currentSwapchainInputImage = index; } - void ImageManager::setSwapchainImages(const std::vector<vk::Image>& images, std::vector<vk::ImageView> views, + void ImageManager::setSwapchainImages(const std::vector<vk::Image>& images, const std::vector<vk::ImageView>& views, uint32_t width, uint32_t height, vk::Format format) { // destroy old views - for (auto image : m_swapchainImages) { + for (const auto& image : m_swapchainImages) { for (const auto& view : image.m_viewPerMip) { m_core->getContext().getDevice().destroyImageView(view); } @@ -683,7 +671,17 @@ namespace vkcv { assert(images.size() == views.size()); m_swapchainImages.clear(); for (size_t i = 0; i < images.size(); i++) { - m_swapchainImages.push_back(Image(images[i], nullptr, { views[i] }, width, height, 1, format, 1)); + m_swapchainImages.push_back({ + images[i], + nullptr, + { views[i] }, + width, + height, + 1, + format, + 1, + vk::ImageLayout::eUndefined + }); } } diff --git a/src/vkcv/ImageManager.hpp b/src/vkcv/ImageManager.hpp index 9edd7471..646b3211 100644 --- a/src/vkcv/ImageManager.hpp +++ b/src/vkcv/ImageManager.hpp @@ -6,6 +6,7 @@ */ #include <vector> #include <vulkan/vulkan.hpp> +#include <vk_mem_alloc.hpp> #include "vkcv/BufferManager.hpp" #include "vkcv/Handles.hpp" @@ -20,28 +21,16 @@ namespace vkcv { struct Image { vk::Image m_handle; - vk::DeviceMemory m_memory; + vma::Allocation m_allocation; std::vector<vk::ImageView> m_viewPerMip; - uint32_t m_width = 0; - uint32_t m_height = 0; - uint32_t m_depth = 0; + uint32_t m_width; + uint32_t m_height; + uint32_t m_depth; vk::Format m_format; - uint32_t m_layers = 1; - vk::ImageLayout m_layout = vk::ImageLayout::eUndefined; + uint32_t m_layers; + vk::ImageLayout m_layout; private: - // struct is public so utility functions can access members, but only ImageManager can create Image friend ImageManager; - Image( - vk::Image handle, - vk::DeviceMemory memory, - std::vector<vk::ImageView> views, - uint32_t width, - uint32_t height, - uint32_t depth, - vk::Format format, - uint32_t layers); - - Image(); }; private: @@ -52,7 +41,7 @@ namespace vkcv { std::vector<Image> m_swapchainImages; int m_currentSwapchainInputImage; - ImageManager(BufferManager& bufferManager) noexcept; + explicit ImageManager(BufferManager& bufferManager) noexcept; /** * Destroys and deallocates image represented by a given @@ -82,7 +71,8 @@ namespace vkcv { bool supportColorAttachment, Multisampling msaa); - ImageHandle createSwapchainImage(); + [[nodiscard]] + ImageHandle createSwapchainImage() const; [[nodiscard]] vk::Image getVulkanImage(const ImageHandle& handle) const; @@ -91,7 +81,7 @@ namespace vkcv { vk::DeviceMemory getVulkanDeviceMemory(const ImageHandle& handle) const; [[nodiscard]] - vk::ImageView getVulkanImageView(const ImageHandle& handle, const size_t mipLevel = 0) const; + vk::ImageView getVulkanImageView(const ImageHandle& handle, size_t mipLevel = 0) const; void switchImageLayoutImmediate(const ImageHandle& handle, vk::ImageLayout newLayout); void recordImageLayoutTransition( @@ -124,8 +114,9 @@ namespace vkcv { uint32_t getImageMipCount(const ImageHandle& handle) const; void setCurrentSwapchainImageIndex(int index); - void setSwapchainImages(const std::vector<vk::Image>& images, std::vector<vk::ImageView> views, - uint32_t width, uint32_t height, vk::Format format); + + void setSwapchainImages(const std::vector<vk::Image>& images, const std::vector<vk::ImageView>& views, + uint32_t width, uint32_t height, vk::Format format); }; } \ No newline at end of file -- GitLab