diff --git a/config/Sources.cmake b/config/Sources.cmake index a50be825150e69513d98ac9b0e7caaf3a699e013..f2c69d3504e54de4b2a69fa5db7c38c957c23956 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -23,6 +23,8 @@ set(vkcv_sources ${vkcv_include}/vkcv/Handles.hpp ${vkcv_source}/vkcv/Handles.cpp + + ${vkcv_source}/vkcv/HandleManager.hpp ${vkcv_include}/vkcv/Window.hpp ${vkcv_source}/vkcv/Window.cpp @@ -85,16 +87,21 @@ set(vkcv_sources ${vkcv_include}/vkcv/TypeGuard.hpp ${vkcv_source}/vkcv/TypeGuard.cpp + + ${vkcv_include}/vkcv/DescriptorTypes.hpp - ${vkcv_source}/vkcv/DescriptorManager.hpp - ${vkcv_source}/vkcv/DescriptorManager.cpp - - ${vkcv_include}/vkcv/DescriptorConfig.hpp - ${vkcv_source}/vkcv/DescriptorConfig.cpp + ${vkcv_include}/vkcv/DescriptorBinding.hpp + ${vkcv_source}/vkcv/DescriptorBinding.cpp ${vkcv_include}/vkcv/DescriptorWrites.hpp ${vkcv_source}/vkcv/DescriptorWrites.cpp + ${vkcv_source}/vkcv/DescriptorSetLayoutManager.hpp + ${vkcv_source}/vkcv/DescriptorSetLayoutManager.cpp + + ${vkcv_source}/vkcv/DescriptorSetManager.hpp + ${vkcv_source}/vkcv/DescriptorSetManager.cpp + ${vkcv_source}/vkcv/SamplerManager.hpp ${vkcv_source}/vkcv/SamplerManager.cpp diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index b93f70427919dc39d611a740d656b9def58d8897..bf5cf40fadb17373ffec2f59cdf48e6d05268511 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -22,7 +22,6 @@ #include "CommandResources.hpp" #include "SyncResources.hpp" #include "Result.hpp" -#include "vkcv/DescriptorConfig.hpp" #include "Sampler.hpp" #include "DescriptorWrites.hpp" #include "Event.hpp" @@ -39,7 +38,8 @@ namespace vkcv class PassManager; class GraphicsPipelineManager; class ComputePipelineManager; - class DescriptorManager; + class DescriptorSetLayoutManager; + class DescriptorSetManager; class BufferManager; class SamplerManager; class ImageManager; @@ -79,16 +79,17 @@ namespace vkcv Context m_Context; - std::unique_ptr<PassManager> m_PassManager; - std::unique_ptr<GraphicsPipelineManager> m_PipelineManager; - std::unique_ptr<ComputePipelineManager> m_ComputePipelineManager; - std::unique_ptr<DescriptorManager> m_DescriptorManager; - std::unique_ptr<BufferManager> m_BufferManager; - std::unique_ptr<SamplerManager> m_SamplerManager; - std::unique_ptr<ImageManager> m_ImageManager; - std::unique_ptr<CommandStreamManager> m_CommandStreamManager; - std::unique_ptr<WindowManager> m_WindowManager; - std::unique_ptr<SwapchainManager> m_SwapchainManager; + std::unique_ptr<PassManager> m_PassManager; + std::unique_ptr<GraphicsPipelineManager> m_GraphicsPipelineManager; + std::unique_ptr<ComputePipelineManager> m_ComputePipelineManager; + std::unique_ptr<DescriptorSetLayoutManager> m_DescriptorSetLayoutManager; + std::unique_ptr<DescriptorSetManager> m_DescriptorSetManager; + std::unique_ptr<BufferManager> m_BufferManager; + std::unique_ptr<SamplerManager> m_SamplerManager; + std::unique_ptr<ImageManager> m_ImageManager; + std::unique_ptr<CommandStreamManager> m_CommandStreamManager; + std::unique_ptr<WindowManager> m_WindowManager; + std::unique_ptr<SwapchainManager> m_SwapchainManager; CommandResources m_CommandResources; SyncResources m_SyncResources; @@ -475,14 +476,6 @@ namespace vkcv */ [[nodiscard]] DescriptorSetLayoutHandle createDescriptorSetLayout(const DescriptorBindings &bindings); - - /** - * @brief Returns the descriptor set layout of a descriptor set layout handle. - * - * @param[in] handle Descriptor set layout handle - * @return Descriptor set layout - */ - DescriptorSetLayout getDescriptorSetLayout(const DescriptorSetLayoutHandle handle) const; /** * @brief Creates a new descriptor set @@ -502,14 +495,6 @@ namespace vkcv */ void writeDescriptorSet(DescriptorSetHandle handle, const DescriptorWrites& writes); - /** - * @brief Returns information about a descriptor set - * - * @param handle Handle of the descriptor set - * @return Struct containing the descriptor set's vulkan handle, layout handle and descriptor pool index - */ - DescriptorSet getDescriptorSet(const DescriptorSetHandle handle) const; - /** * @brief Start recording command buffers and increment frame index diff --git a/include/vkcv/DescriptorBinding.hpp b/include/vkcv/DescriptorBinding.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c0a8a670779bd8342995f9287770b857f3373bc8 --- /dev/null +++ b/include/vkcv/DescriptorBinding.hpp @@ -0,0 +1,31 @@ +#pragma once +/** + * @authors Artur Wasmut, Tobias Frisch, Simeon Hermann, Alexander Gauggel, Vanessa Karolek + * @file vkcv/DescriptorConfig.hpp + * @brief Structures to handle descriptor bindings. + */ + +#include <unordered_map> + +#include "DescriptorTypes.hpp" +#include "ShaderStage.hpp" + +namespace vkcv { + + /** + * @brief Structure to store details from a descriptor binding. + */ + struct DescriptorBinding { + uint32_t bindingID; + DescriptorType descriptorType; + uint32_t descriptorCount; + ShaderStages shaderStages; + bool variableCount; + bool partialBinding; + + bool operator ==(const DescriptorBinding &other) const; + }; + + typedef std::unordered_map<uint32_t, DescriptorBinding> DescriptorBindings; + +} diff --git a/include/vkcv/DescriptorConfig.hpp b/include/vkcv/DescriptorConfig.hpp deleted file mode 100644 index 8e4f3df2fad31f2a358f5f6b7f5ba4e0c14bd6e0..0000000000000000000000000000000000000000 --- a/include/vkcv/DescriptorConfig.hpp +++ /dev/null @@ -1,96 +0,0 @@ -#pragma once -/** - * @authors Artur Wasmut, Tobias Frisch, Simeon Hermann, Alexander Gauggel, Vanessa Karolek - * @file vkcv/DescriptorConfig.hpp - * @brief Structures to handle descriptor types and bindings. - */ - -#include <unordered_map> - -#include "Handles.hpp" -#include "ShaderStage.hpp" -#include "Logger.hpp" - -namespace vkcv -{ - - /** - * @brief Enum class to specify the type of a descriptor set binding. - */ - enum class DescriptorType { - UNIFORM_BUFFER, - STORAGE_BUFFER, - SAMPLER, - IMAGE_SAMPLED, - IMAGE_STORAGE, - UNIFORM_BUFFER_DYNAMIC, - STORAGE_BUFFER_DYNAMIC, - ACCELERATION_STRUCTURE_KHR - }; - - /** - * @brief Converts the descriptor type from the frameworks enumeration - * to the Vulkan type specifier. - * - * @param[in] type Descriptor type - * @return Vulkan descriptor type - */ - constexpr vk::DescriptorType getVkDescriptorType(DescriptorType type) noexcept { - switch (type) - { - case DescriptorType::UNIFORM_BUFFER: - return vk::DescriptorType::eUniformBuffer; - case DescriptorType::UNIFORM_BUFFER_DYNAMIC: - return vk::DescriptorType::eUniformBufferDynamic; - case DescriptorType::STORAGE_BUFFER: - return vk::DescriptorType::eStorageBuffer; - case DescriptorType::STORAGE_BUFFER_DYNAMIC: - return vk::DescriptorType::eStorageBufferDynamic; - case DescriptorType::SAMPLER: - return vk::DescriptorType::eSampler; - case DescriptorType::IMAGE_SAMPLED: - return vk::DescriptorType::eSampledImage; - case DescriptorType::IMAGE_STORAGE: - return vk::DescriptorType::eStorageImage; - case DescriptorType::ACCELERATION_STRUCTURE_KHR: - return vk::DescriptorType::eAccelerationStructureKHR; - default: - return vk::DescriptorType::eMutableVALVE; - } - } - - /** - * @brief Structure to store details from a descriptor binding. - */ - struct DescriptorBinding { - uint32_t bindingID; - DescriptorType descriptorType; - uint32_t descriptorCount; - ShaderStages shaderStages; - bool variableCount; - bool partialBinding; - - bool operator ==(const DescriptorBinding &other) const; - }; - - typedef std::unordered_map<uint32_t, DescriptorBinding> DescriptorBindings; - - /** - * @brief Structure to store details about a descriptor set layout. - */ - struct DescriptorSetLayout { - vk::DescriptorSetLayout vulkanHandle; - DescriptorBindings descriptorBindings; - size_t layoutUsageCount; - }; - - /** - * @brief Structure to store details about a descriptor set. - */ - struct DescriptorSet { - vk::DescriptorSet vulkanHandle; - DescriptorSetLayoutHandle setLayoutHandle; - size_t poolIndex; - }; - -} diff --git a/include/vkcv/DescriptorTypes.hpp b/include/vkcv/DescriptorTypes.hpp new file mode 100644 index 0000000000000000000000000000000000000000..eaa739d6d33359b7306254677e323fb1827ca5f0 --- /dev/null +++ b/include/vkcv/DescriptorTypes.hpp @@ -0,0 +1,57 @@ +#pragma once +/** + * @authors Artur Wasmut, Tobias Frisch, Simeon Hermann, Alexander Gauggel, Vanessa Karolek + * @file vkcv/DescriptorConfig.hpp + * @brief Enum classes to handle descriptor types. + */ + +#include <vulkan/vulkan.hpp> + +namespace vkcv { + + /** + * @brief Enum class to specify the type of a descriptor set binding. + */ + enum class DescriptorType { + UNIFORM_BUFFER, + STORAGE_BUFFER, + SAMPLER, + IMAGE_SAMPLED, + IMAGE_STORAGE, + UNIFORM_BUFFER_DYNAMIC, + STORAGE_BUFFER_DYNAMIC, + ACCELERATION_STRUCTURE_KHR + }; + + /** + * @brief Converts the descriptor type from the frameworks enumeration + * to the Vulkan type specifier. + * + * @param[in] type Descriptor type + * @return Vulkan descriptor type + */ + constexpr vk::DescriptorType getVkDescriptorType(DescriptorType type) noexcept { + switch (type) + { + case DescriptorType::UNIFORM_BUFFER: + return vk::DescriptorType::eUniformBuffer; + case DescriptorType::UNIFORM_BUFFER_DYNAMIC: + return vk::DescriptorType::eUniformBufferDynamic; + case DescriptorType::STORAGE_BUFFER: + return vk::DescriptorType::eStorageBuffer; + case DescriptorType::STORAGE_BUFFER_DYNAMIC: + return vk::DescriptorType::eStorageBufferDynamic; + case DescriptorType::SAMPLER: + return vk::DescriptorType::eSampler; + case DescriptorType::IMAGE_SAMPLED: + return vk::DescriptorType::eSampledImage; + case DescriptorType::IMAGE_STORAGE: + return vk::DescriptorType::eStorageImage; + case DescriptorType::ACCELERATION_STRUCTURE_KHR: + return vk::DescriptorType::eAccelerationStructureKHR; + default: + return vk::DescriptorType::eMutableVALVE; + } + } + +} diff --git a/include/vkcv/DrawcallRecording.hpp b/include/vkcv/DrawcallRecording.hpp index 597774eef59a2ac4d059dba1cfd9934370a86c4e..217614c111d2648df7844bf4a8504136609f2299 100644 --- a/include/vkcv/DrawcallRecording.hpp +++ b/include/vkcv/DrawcallRecording.hpp @@ -5,10 +5,10 @@ * @brief Structures and functions to record drawcalls. */ +#include <vector> #include <vulkan/vulkan.hpp> #include "Handles.hpp" -#include "DescriptorConfig.hpp" #include "PushConstants.hpp" namespace vkcv { diff --git a/include/vkcv/Handles.hpp b/include/vkcv/Handles.hpp index dea1793871a320016cf7c0da3f3877fc66a6f616..52ccb7a84a5d82bf51c3285c6536d6ce9aa0bc48 100644 --- a/include/vkcv/Handles.hpp +++ b/include/vkcv/Handles.hpp @@ -130,23 +130,23 @@ namespace vkcv private: using Handle::Handle; }; - - /** - * @brief Handle class for descriptor sets. + + /** + * @brief Handle class for descriptor set layouts. */ - class DescriptorSetHandle : public Handle { - friend class DescriptorManager; + class DescriptorSetLayoutHandle : public Handle { + friend class DescriptorSetLayoutManager; private: using Handle::Handle; }; /** - * @brief Handle class for descriptor set layouts. + * @brief Handle class for descriptor sets. */ - class DescriptorSetLayoutHandle : public Handle { - friend class DescriptorManager; + class DescriptorSetHandle : public Handle { + friend class DescriptorSetManager; private: - using Handle::Handle; + using Handle::Handle; }; /** diff --git a/include/vkcv/ShaderProgram.hpp b/include/vkcv/ShaderProgram.hpp index c815834a3d7a948df3307769f34abe94cbd2ff22..0cc4fed0d87195dec3b0eae345e206724d2f4060 100644 --- a/include/vkcv/ShaderProgram.hpp +++ b/include/vkcv/ShaderProgram.hpp @@ -13,8 +13,8 @@ #include <vulkan/vulkan.hpp> #include <spirv_cross.hpp> +#include "DescriptorBinding.hpp" #include "VertexLayout.hpp" -#include "DescriptorConfig.hpp" #include "ShaderStage.hpp" namespace vkcv { diff --git a/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp b/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp index 47560b4d9fddb867dd5573c64fe57c24c69095ce..406f145161661880f6a2d726090f1fb6889ed7e1 100644 --- a/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp +++ b/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp @@ -123,7 +123,7 @@ namespace vkcv::rtx { vertexInfo.setRange(blas.vertexBuffer.deviceSize); //maybe check if size is correct vk::WriteDescriptorSet vertexWrite; - vertexWrite.setDstSet(m_core->getDescriptorSet(descriptorSetHandles[0]).vulkanHandle); + vertexWrite.setDstSet(m_core->getDescriptorSet().vulkanHandle); vertexWrite.setDstBinding(3); vertexWrite.setDescriptorCount(1); vertexWrite.setDescriptorType(vk::DescriptorType::eStorageBuffer); diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp index 3e245cb7b980ddca03de08073fac2bd15a43dfb8..22ef289039d844a324372c055f0f6ec921a1b122 100644 --- a/src/vkcv/BufferManager.cpp +++ b/src/vkcv/BufferManager.cpp @@ -9,14 +9,9 @@ namespace vkcv { - BufferManager::BufferManager() noexcept : - m_core(nullptr), m_buffers(), m_stagingBuffer(BufferHandle()) - { - } - - void BufferManager::init() { - if (!m_core) { - return; + bool BufferManager::init(Core& core) { + if (!HandleManager<BufferEntry, BufferHandle>::init(core)) { + return false; } m_stagingBuffer = createBuffer( @@ -26,14 +21,40 @@ namespace vkcv { 1024 * 1024, false ); + + return true; } - BufferManager::~BufferManager() noexcept { - for (uint64_t id = 0; id < m_buffers.size(); id++) { - destroyBufferById(id); + uint64_t BufferManager::getIdFrom(const BufferHandle &handle) const { + return handle.getId(); + } + + BufferHandle BufferManager::createById(uint64_t id, const HandleDestroyFunction &destroy) { + return BufferHandle(id, destroy); + } + + void BufferManager::destroyById(uint64_t id) { + auto& buffer = getById(id); + + const vma::Allocator& allocator = getCore().getContext().getAllocator(); + + if (buffer.m_handle) { + allocator.destroyBuffer(buffer.m_handle, buffer.m_allocation); + + buffer.m_handle = nullptr; + buffer.m_allocation = nullptr; } } + BufferManager::BufferManager() noexcept : + HandleManager<BufferEntry, BufferHandle>(), + m_stagingBuffer(BufferHandle()) + {} + + BufferManager::~BufferManager() noexcept { + clear(); + } + BufferHandle BufferManager::createBuffer(const TypeGuard &typeGuard, BufferType type, BufferMemoryType memoryType, @@ -76,7 +97,7 @@ namespace vkcv { usageFlags |= vk::BufferUsageFlagBits::eTransferSrc; } - const vma::Allocator& allocator = m_core->getContext().getAllocator(); + const vma::Allocator& allocator = getCore().getContext().getAllocator(); vk::MemoryPropertyFlags memoryTypeFlags; vma::MemoryUsage memoryUsage; @@ -120,8 +141,7 @@ namespace vkcv { vk::Buffer buffer = bufferAllocation.first; vma::Allocation allocation = bufferAllocation.second; - const uint64_t id = m_buffers.size(); - m_buffers.push_back({ + return add({ typeGuard, type, memoryType, @@ -130,8 +150,6 @@ namespace vkcv { allocation, mappable }); - - return BufferHandle(id, [&](uint64_t id) { destroyBufferById(id); }); } /** @@ -160,11 +178,11 @@ namespace vkcv { * @param core Core instance * @param info Staging-info structure */ - static void fillFromStagingBuffer(Core* core, StagingWriteInfo& info) { + static void fillFromStagingBuffer(Core& core, StagingWriteInfo& info) { const size_t remaining = info.size - info.stagingPosition; const size_t mapped_size = std::min(remaining, info.stagingLimit); - const vma::Allocator& allocator = core->getContext().getAllocator(); + const vma::Allocator& allocator = core.getContext().getAllocator(); void* mapped = allocator.mapMemory(info.stagingAllocation); memcpy(mapped, reinterpret_cast<const char*>(info.data) + info.stagingPosition, mapped_size); @@ -173,7 +191,7 @@ namespace vkcv { SubmitInfo submitInfo; submitInfo.queueType = QueueType::Transfer; - core->recordAndSubmitCommandsImmediate( + core.recordAndSubmitCommandsImmediate( submitInfo, [&info, &mapped_size](const vk::CommandBuffer& commandBuffer) { const vk::BufferCopy region ( @@ -223,14 +241,14 @@ namespace vkcv { * @param core Core instance * @param info Staging-info structure */ - static void readToStagingBuffer(Core* core, StagingReadInfo& info) { + static void readToStagingBuffer(Core& core, StagingReadInfo& info) { const size_t remaining = info.size - info.stagingPosition; const size_t mapped_size = std::min(remaining, info.stagingLimit); SubmitInfo submitInfo; submitInfo.queueType = QueueType::Transfer; - core->recordAndSubmitCommandsImmediate( + core.recordAndSubmitCommandsImmediate( submitInfo, [&info, &mapped_size](const vk::CommandBuffer& commandBuffer) { const vk::BufferCopy region ( @@ -242,7 +260,7 @@ namespace vkcv { commandBuffer.copyBuffer(info.buffer, info.stagingBuffer, 1, ®ion); }, [&core, &info, &mapped_size, &remaining]() { - const vma::Allocator& allocator = core->getContext().getAllocator(); + const vma::Allocator& allocator = core.getContext().getAllocator(); const void* mapped = allocator.mapMemory(info.stagingAllocation); memcpy(reinterpret_cast<char*>(info.data) + info.stagingPosition, mapped, mapped_size); @@ -261,75 +279,39 @@ namespace vkcv { } vk::Buffer BufferManager::getBuffer(const BufferHandle& handle) const { - const uint64_t id = handle.getId(); - - if (id >= m_buffers.size()) { - return nullptr; - } - - auto& buffer = m_buffers[id]; + auto& buffer = (*this)[handle]; return buffer.m_handle; } TypeGuard BufferManager::getTypeGuard(const BufferHandle &handle) const { - const uint64_t id = handle.getId(); - - if (id >= m_buffers.size()) { - return TypeGuard(0); - } - - auto& buffer = m_buffers[id]; + auto& buffer = (*this)[handle]; return buffer.m_typeGuard; } BufferType BufferManager::getBufferType(const BufferHandle &handle) const { - const uint64_t id = handle.getId(); - - if (id >= m_buffers.size()) { - return BufferType::UNKNOWN; - } - - auto& buffer = m_buffers[id]; + auto& buffer = (*this)[handle]; return buffer.m_type; } BufferMemoryType BufferManager::getBufferMemoryType(const BufferHandle &handle) const { - const uint64_t id = handle.getId(); - - if (id >= m_buffers.size()) { - return BufferMemoryType::UNKNOWN; - } - - auto& buffer = m_buffers[id]; + auto& buffer = (*this)[handle]; return buffer.m_memoryType; } size_t BufferManager::getBufferSize(const BufferHandle &handle) const { - const uint64_t id = handle.getId(); - - if (id >= m_buffers.size()) { - return 0; - } - - auto& buffer = m_buffers[id]; + auto& buffer = (*this)[handle]; return buffer.m_size; } vk::DeviceMemory BufferManager::getDeviceMemory(const BufferHandle& handle) const { - const uint64_t id = handle.getId(); + auto& buffer = (*this)[handle]; - if (id >= m_buffers.size()) { - return nullptr; - } - - auto& buffer = m_buffers[id]; - - const vma::Allocator& allocator = m_core->getContext().getAllocator(); + const vma::Allocator& allocator = getCore().getContext().getAllocator(); auto info = allocator.getAllocationInfo( buffer.m_allocation @@ -342,19 +324,13 @@ namespace vkcv { const void *data, size_t size, size_t offset) { - const uint64_t id = handle.getId(); + auto& buffer = (*this)[handle]; if (size == 0) { size = SIZE_MAX; } - if (id >= m_buffers.size()) { - return; - } - - auto& buffer = m_buffers[id]; - - const vma::Allocator& allocator = m_core->getContext().getAllocator(); + const vma::Allocator& allocator = getCore().getContext().getAllocator(); if (offset > buffer.m_size) { return; @@ -367,7 +343,7 @@ namespace vkcv { memcpy(reinterpret_cast<char*>(mapped) + offset, data, max_size); allocator.unmapMemory(buffer.m_allocation); } else { - auto& stagingBuffer = m_buffers[ m_stagingBuffer.getId() ]; + auto& stagingBuffer = (*this)[ m_stagingBuffer ]; StagingWriteInfo info; info.data = data; @@ -381,7 +357,7 @@ namespace vkcv { info.stagingLimit = stagingBuffer.m_size; info.stagingPosition = 0; - fillFromStagingBuffer(m_core, info); + fillFromStagingBuffer(getCore(), info); } } @@ -389,19 +365,13 @@ namespace vkcv { void *data, size_t size, size_t offset) { - const uint64_t id = handle.getId(); + auto& buffer = (*this)[handle]; if (size == 0) { size = SIZE_MAX; } - if (id >= m_buffers.size()) { - return; - } - - auto& buffer = m_buffers[id]; - - const vma::Allocator& allocator = m_core->getContext().getAllocator(); + const vma::Allocator& allocator = getCore().getContext().getAllocator(); if (offset > buffer.m_size) { return; @@ -414,7 +384,7 @@ namespace vkcv { memcpy(data, reinterpret_cast<const char*>(mapped) + offset, max_size); allocator.unmapMemory(buffer.m_allocation); } else { - auto& stagingBuffer = m_buffers[ m_stagingBuffer.getId() ]; + auto& stagingBuffer = (*this)[ m_stagingBuffer ]; StagingReadInfo info; info.data = data; @@ -428,24 +398,18 @@ namespace vkcv { info.stagingLimit = stagingBuffer.m_size; info.stagingPosition = 0; - readToStagingBuffer(m_core, info); + readToStagingBuffer(getCore(), info); } } void* BufferManager::mapBuffer(const BufferHandle& handle, size_t offset, size_t size) { - const uint64_t id = handle.getId(); + auto& buffer = (*this)[handle]; if (size == 0) { size = SIZE_MAX; } - if (id >= m_buffers.size()) { - return nullptr; - } - - auto& buffer = m_buffers[id]; - - const vma::Allocator& allocator = m_core->getContext().getAllocator(); + const vma::Allocator& allocator = getCore().getContext().getAllocator(); if (offset > buffer.m_size) { return nullptr; @@ -455,46 +419,15 @@ namespace vkcv { } void BufferManager::unmapBuffer(const BufferHandle& handle) { - const uint64_t id = handle.getId(); - - if (id >= m_buffers.size()) { - return; - } + auto& buffer = (*this)[handle]; - auto& buffer = m_buffers[id]; - - const vma::Allocator& allocator = m_core->getContext().getAllocator(); + const vma::Allocator& allocator = getCore().getContext().getAllocator(); allocator.unmapMemory(buffer.m_allocation); } - - void BufferManager::destroyBufferById(uint64_t id) { - if (id >= m_buffers.size()) { - return; - } - - auto& buffer = m_buffers[id]; - - const vma::Allocator& allocator = m_core->getContext().getAllocator(); - - if (buffer.m_handle) { - allocator.destroyBuffer(buffer.m_handle, buffer.m_allocation); - - buffer.m_handle = nullptr; - buffer.m_allocation = nullptr; - } - } void BufferManager ::recordBufferMemoryBarrier(const BufferHandle& handle, vk::CommandBuffer cmdBuffer) { - - const uint64_t id = handle.getId(); - - if (id >= m_buffers.size()) { - vkcv_log(vkcv::LogLevel::ERROR, "Invalid buffer handle"); - return; - } - - auto& buffer = m_buffers[id]; + auto& buffer = (*this)[handle]; vk::BufferMemoryBarrier memoryBarrier( vk::AccessFlagBits::eMemoryWrite, diff --git a/src/vkcv/BufferManager.hpp b/src/vkcv/BufferManager.hpp index dd9b07e3b7abd6c7533c57bd77fe9e590fd28c40..e86438126fd6775c241fbcfb7a0e493d0885c775 100644 --- a/src/vkcv/BufferManager.hpp +++ b/src/vkcv/BufferManager.hpp @@ -10,42 +10,41 @@ #include <vk_mem_alloc.hpp> #include "vkcv/BufferTypes.hpp" -#include "vkcv/Handles.hpp" #include "vkcv/TypeGuard.hpp" +#include "HandleManager.hpp" + namespace vkcv { - class Core; + struct BufferEntry { + TypeGuard m_typeGuard; + + BufferType m_type; + BufferMemoryType m_memoryType; + size_t m_size; + + vk::Buffer m_handle; + vma::Allocation m_allocation; + + bool m_mappable; + }; /** * @brief Class to manage the creation, destruction, allocation * and filling of buffers. */ - class BufferManager - { + class BufferManager : public HandleManager<BufferEntry, BufferHandle> { friend class Core; private: - - struct Buffer { - TypeGuard m_typeGuard; - - BufferType m_type; - BufferMemoryType m_memoryType; - size_t m_size; - - vk::Buffer m_handle; - vma::Allocation m_allocation; - - bool m_mappable; - }; - - Core* m_core; - std::vector<Buffer> m_buffers; BufferHandle m_stagingBuffer; - BufferManager() noexcept; + bool init(Core& core) override; - void init(); + [[nodiscard]] + uint64_t getIdFrom(const BufferHandle& handle) const override; + + [[nodiscard]] + BufferHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override; /** * Destroys and deallocates buffer represented by a given @@ -53,16 +52,12 @@ namespace vkcv { * * @param id Buffer handle id */ - void destroyBufferById(uint64_t id); + void destroyById(uint64_t id) override; public: - ~BufferManager() noexcept; - - BufferManager(BufferManager&& other) = delete; - BufferManager(const BufferManager& other) = delete; + BufferManager() noexcept; - BufferManager& operator=(BufferManager&& other) = delete; - BufferManager& operator=(const BufferManager& other) = delete; + ~BufferManager() noexcept override; /** * @brief Creates and allocates a new buffer and returns its @@ -76,6 +71,7 @@ namespace vkcv { * @param[in] readable Support read functionality * @return New buffer handle */ + [[nodiscard]] BufferHandle createBuffer(const TypeGuard &typeGuard, BufferType type, BufferMemoryType memoryType, diff --git a/src/vkcv/ComputePipelineManager.cpp b/src/vkcv/ComputePipelineManager.cpp index 264389ca9b5ed118666911b07158ab589a4ca0ee..68836cdba92e4a28d6edfe4ee4e142043cde2c44 100644 --- a/src/vkcv/ComputePipelineManager.cpp +++ b/src/vkcv/ComputePipelineManager.cpp @@ -1,53 +1,62 @@ #include "ComputePipelineManager.hpp" -namespace vkcv -{ - - ComputePipelineManager::ComputePipelineManager(vk::Device device) noexcept : - m_Device{device}, - m_Pipelines{} - {} - - ComputePipelineManager::~ComputePipelineManager() noexcept - { - for (uint64_t id = 0; id < m_Pipelines.size(); id++) { - destroyPipelineById(id); - } +#include "vkcv/Core.hpp" + +namespace vkcv { + + uint64_t ComputePipelineManager::getIdFrom(const ComputePipelineHandle &handle) const { + return handle.getId(); + } + + ComputePipelineHandle ComputePipelineManager::createById(uint64_t id, const HandleDestroyFunction &destroy) { + return ComputePipelineHandle(id, destroy); + } + + void ComputePipelineManager::destroyById(uint64_t id) { + auto& pipeline = getById(id); + + if (pipeline.m_handle) { + getCore().getContext().getDevice().destroy(pipeline.m_handle); + pipeline.m_handle = nullptr; + } + + if (pipeline.m_layout) { + getCore().getContext().getDevice().destroy(pipeline.m_layout); + pipeline.m_layout = nullptr; + } + } + + ComputePipelineManager::ComputePipelineManager() noexcept : + HandleManager<ComputePipelineEntry, ComputePipelineHandle>() {} + + vk::Result ComputePipelineManager::createShaderModule(vk::ShaderModule &module, + const ShaderProgram &shaderProgram, + const ShaderStage stage) { + std::vector<uint32_t> code = shaderProgram.getShaderBinary(stage); + vk::ShaderModuleCreateInfo moduleInfo({}, code.size() * sizeof(uint32_t), code.data()); + return getCore().getContext().getDevice().createShaderModule(&moduleInfo, nullptr, &module); + } + + ComputePipelineManager::~ComputePipelineManager() noexcept { + clear(); } - vk::Pipeline ComputePipelineManager::getVkPipeline(const ComputePipelineHandle &handle) const - { - const uint64_t id = handle.getId(); - - if (id >= m_Pipelines.size()) { - return nullptr; - } - - auto& pipeline = m_Pipelines[id]; - + vk::Pipeline ComputePipelineManager::getVkPipeline(const ComputePipelineHandle &handle) const { + auto& pipeline = (*this)[handle]; return pipeline.m_handle; } - vk::PipelineLayout ComputePipelineManager::getVkPipelineLayout(const ComputePipelineHandle &handle) const - { - const uint64_t id = handle.getId(); - - if (id >= m_Pipelines.size()) { - return nullptr; - } - - auto& pipeline = m_Pipelines[id]; - + vk::PipelineLayout ComputePipelineManager::getVkPipelineLayout(const ComputePipelineHandle &handle) const { + auto& pipeline = (*this)[handle]; return pipeline.m_layout; } ComputePipelineHandle ComputePipelineManager::createComputePipeline(const ShaderProgram& shaderProgram, const std::vector<vk::DescriptorSetLayout>& descriptorSetLayouts) { - // Temporally handing over the Shader Program instead of a pipeline config vk::ShaderModule computeModule{}; if (createShaderModule(computeModule, shaderProgram, ShaderStage::COMPUTE) != vk::Result::eSuccess) - return ComputePipelineHandle(); + return {}; vk::PipelineShaderStageCreateInfo pipelineComputeShaderStageInfo( {}, @@ -67,10 +76,11 @@ namespace vkcv } vk::PipelineLayout vkPipelineLayout{}; - if (m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &vkPipelineLayout) != - vk::Result::eSuccess) { - m_Device.destroy(computeModule); - return ComputePipelineHandle(); + if (getCore().getContext().getDevice().createPipelineLayout(&pipelineLayoutCreateInfo, + nullptr, + &vkPipelineLayout) != vk::Result::eSuccess) { + getCore().getContext().getDevice().destroy(computeModule); + return {}; } vk::ComputePipelineCreateInfo computePipelineCreateInfo{}; @@ -78,42 +88,17 @@ namespace vkcv computePipelineCreateInfo.layout = vkPipelineLayout; vk::Pipeline vkPipeline; - if (m_Device.createComputePipelines(nullptr, 1, &computePipelineCreateInfo, nullptr, &vkPipeline) != - vk::Result::eSuccess) { - m_Device.destroy(computeModule); + if (getCore().getContext().getDevice().createComputePipelines(nullptr, + 1, + &computePipelineCreateInfo, + nullptr, + &vkPipeline) != vk::Result::eSuccess) { + getCore().getContext().getDevice().destroy(computeModule); return ComputePipelineHandle(); } - - m_Device.destroy(computeModule); - - const uint64_t id = m_Pipelines.size(); - m_Pipelines.push_back({vkPipeline, vkPipelineLayout}); - - return ComputePipelineHandle(id, [&](uint64_t id) { destroyPipelineById(id); }); + + getCore().getContext().getDevice().destroy(computeModule); + return add({ vkPipeline, vkPipelineLayout }); } - void vkcv::ComputePipelineManager::destroyPipelineById(uint64_t id) { - if (id >= m_Pipelines.size()) { - return; - } - - auto& pipeline = m_Pipelines[id]; - - if (pipeline.m_handle) { - m_Device.destroy(pipeline.m_handle); - pipeline.m_handle = nullptr; - } - - if (pipeline.m_layout) { - m_Device.destroy(pipeline.m_layout); - pipeline.m_layout = nullptr; - } - } - - vk::Result ComputePipelineManager::createShaderModule(vk::ShaderModule &module, const ShaderProgram &shaderProgram, const ShaderStage stage) - { - std::vector<uint32_t> code = shaderProgram.getShaderBinary(stage); - vk::ShaderModuleCreateInfo moduleInfo({}, code.size() * sizeof(uint32_t), code.data()); - return m_Device.createShaderModule(&moduleInfo, nullptr, &module); - } } \ No newline at end of file diff --git a/src/vkcv/ComputePipelineManager.hpp b/src/vkcv/ComputePipelineManager.hpp index 4c186ac7508a0cb8ff98d691d25cd8c3b1726f47..860181c8745756bab37790dadfa37b13d9ac0eab 100644 --- a/src/vkcv/ComputePipelineManager.hpp +++ b/src/vkcv/ComputePipelineManager.hpp @@ -9,28 +9,45 @@ #include <vulkan/vulkan.hpp> #include <vector> -#include "vkcv/Handles.hpp" +#include "HandleManager.hpp" + #include "vkcv/ShaderProgram.hpp" #include "vkcv/ComputePipelineConfig.hpp" -namespace vkcv -{ +namespace vkcv { + + struct ComputePipelineEntry { + vk::Pipeline m_handle; + vk::PipelineLayout m_layout; + }; /** * @brief Class to manage compute pipelines. */ - class ComputePipelineManager - { + class ComputePipelineManager : public HandleManager<ComputePipelineEntry, ComputePipelineHandle> { + private: + [[nodiscard]] + uint64_t getIdFrom(const ComputePipelineHandle& handle) const override; + + [[nodiscard]] + ComputePipelineHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override; + + /** + * Destroys and deallocates compute pipeline represented by a given + * compute pipeline handle id. + * + * @param id Compute pipeline handle id + */ + void destroyById(uint64_t id) override; + + vk::Result createShaderModule(vk::ShaderModule &module, + const ShaderProgram &shaderProgram, + ShaderStage stage); + public: - ComputePipelineManager() = delete; // no default ctor - explicit ComputePipelineManager(vk::Device device) noexcept; // ctor - ~ComputePipelineManager() noexcept; // dtor - - ComputePipelineManager(const ComputePipelineManager &other) = delete; // copy-ctor - ComputePipelineManager(ComputePipelineManager &&other) = delete; // move-ctor; - - ComputePipelineManager & operator=(const ComputePipelineManager &other) = delete; // copy-assign op - ComputePipelineManager & operator=(ComputePipelineManager &&other) = delete; // move-assign op + ComputePipelineManager() noexcept; + + ~ComputePipelineManager() noexcept override; // dtor /** * Returns a vk::Pipeline object by handle. @@ -58,20 +75,7 @@ namespace vkcv */ ComputePipelineHandle createComputePipeline(const ShaderProgram& shaderProgram, const std::vector<vk::DescriptorSetLayout>& descriptorSetLayouts); - - private: - struct ComputePipeline { - vk::Pipeline m_handle; - vk::PipelineLayout m_layout; - }; - - vk::Device m_Device; - std::vector<ComputePipeline> m_Pipelines; - - void destroyPipelineById(uint64_t id); - - vk::Result createShaderModule(vk::ShaderModule &module, const ShaderProgram &shaderProgram, ShaderStage stage); - + }; } diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 22f334be819cfdb2832870b63a9e2daa4659736a..821ae5e334e7f2be4e4c9d156d2a774a232e4718 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -1,5 +1,5 @@ /** - * @authors Artur Wasmut + * @authors Artur Wasmut, Alexander Gauggel, Tobias Frisch * @file src/vkcv/Core.cpp * @brief Handling of global states regarding dependencies */ @@ -13,7 +13,8 @@ #include "BufferManager.hpp" #include "SamplerManager.hpp" #include "ImageManager.hpp" -#include "DescriptorManager.hpp" +#include "DescriptorSetLayoutManager.hpp" +#include "DescriptorSetManager.hpp" #include "WindowManager.hpp" #include "CommandStreamManager.hpp" #include <cmath> @@ -44,32 +45,36 @@ namespace vkcv return Core(std::move(context) , commandResources, defaultSyncResources); } - const Context &Core::getContext() const - { + const Context &Core::getContext() const { return m_Context; } Core::Core(Context &&context, const CommandResources& commandResources, const SyncResources& syncResources) noexcept : - m_Context(std::move(context)), - m_PassManager{std::make_unique<PassManager>(m_Context.m_Device)}, - m_PipelineManager{std::make_unique<GraphicsPipelineManager>(m_Context.m_Device, m_Context.m_PhysicalDevice)}, - m_ComputePipelineManager{std::make_unique<ComputePipelineManager>(m_Context.m_Device)}, - m_DescriptorManager(std::make_unique<DescriptorManager>(m_Context.m_Device)), - m_BufferManager{std::unique_ptr<BufferManager>(new BufferManager())}, - m_SamplerManager(std::unique_ptr<SamplerManager>(new SamplerManager(m_Context.m_Device))), - m_ImageManager{std::unique_ptr<ImageManager>(new ImageManager(*m_BufferManager))}, - m_CommandStreamManager{std::unique_ptr<CommandStreamManager>(new CommandStreamManager)}, + m_Context(std::move(context)), + m_PassManager(std::make_unique<PassManager>()), + m_GraphicsPipelineManager(std::make_unique<GraphicsPipelineManager>()), + m_ComputePipelineManager(std::make_unique<ComputePipelineManager>()), + m_DescriptorSetLayoutManager(std::make_unique<DescriptorSetLayoutManager>()), + m_DescriptorSetManager(std::make_unique<DescriptorSetManager>()), + m_BufferManager(std::make_unique<BufferManager>()), + m_SamplerManager(std::unique_ptr<SamplerManager>(new SamplerManager(m_Context.m_Device))), + m_ImageManager(std::make_unique<ImageManager>()), + m_CommandStreamManager{std::unique_ptr<CommandStreamManager>(new CommandStreamManager)}, m_WindowManager(std::make_unique<WindowManager>()), m_SwapchainManager(std::make_unique<SwapchainManager>()), - m_CommandResources(commandResources), - m_SyncResources(syncResources), + m_CommandResources(commandResources), + m_SyncResources(syncResources), m_downsampler(nullptr) { - m_BufferManager->m_core = this; - m_BufferManager->init(); + m_PassManager->init(*this); + m_GraphicsPipelineManager->init(*this); + m_ComputePipelineManager->init(*this); + m_DescriptorSetLayoutManager->init(*this); + m_DescriptorSetManager->init(*this, *m_DescriptorSetLayoutManager); + m_BufferManager->init(*this); m_CommandStreamManager->init(this); m_SwapchainManager->m_context = &m_Context; - m_ImageManager->m_core = this; + m_ImageManager->init(*this, *m_BufferManager); m_downsampler = std::unique_ptr<Downsampler>(new BlitDownsampler(*this, *m_ImageManager)); } @@ -81,7 +86,7 @@ namespace vkcv } GraphicsPipelineHandle Core::createGraphicsPipeline(const GraphicsPipelineConfig &config) { - return m_PipelineManager->createPipeline(config, *m_PassManager, *m_DescriptorManager); + return m_GraphicsPipelineManager->createPipeline(config, *m_PassManager, *m_DescriptorSetLayoutManager); } ComputePipelineHandle Core::createComputePipeline(const ComputePipelineConfig &config) { @@ -89,7 +94,9 @@ namespace vkcv layouts.resize(config.getDescriptorSetLayouts().size()); for (size_t i = 0; i < layouts.size(); i++) { - layouts[i] = getDescriptorSetLayout(config.getDescriptorSetLayouts()[i]).vulkanHandle; + layouts[i] = m_DescriptorSetLayoutManager->getDescriptorSetLayout( + config.getDescriptorSetLayouts()[i] + ).vulkanHandle; } return m_ComputePipelineManager->createComputePipeline(config.getShaderProgram(), layouts); @@ -341,13 +348,13 @@ namespace vkcv } } - void recordDrawcall( - const Core &core, - const DrawcallInfo &drawcall, - vk::CommandBuffer cmdBuffer, - vk::PipelineLayout pipelineLayout, - const PushConstants &pushConstants, - const size_t drawcallIndex) { + static void recordDrawcall( + const DescriptorSetManager &descriptorSetManager, + const DrawcallInfo &drawcall, + vk::CommandBuffer cmdBuffer, + vk::PipelineLayout pipelineLayout, + const PushConstants &pushConstants, + const size_t drawcallIndex) { for (uint32_t i = 0; i < drawcall.mesh.vertexBufferBindings.size(); i++) { const auto& vertexBinding = drawcall.mesh.vertexBufferBindings[i]; @@ -359,7 +366,7 @@ namespace vkcv vk::PipelineBindPoint::eGraphics, pipelineLayout, descriptorUsage.setLocation, - core.getDescriptorSet(descriptorUsage.descriptorSet).vulkanHandle, + descriptorSetManager.getDescriptorSet(descriptorUsage.descriptorSet).vulkanHandle, nullptr); } @@ -375,8 +382,7 @@ namespace vkcv if (drawcall.mesh.indexBuffer) { cmdBuffer.bindIndexBuffer(drawcall.mesh.indexBuffer, 0, getIndexType(drawcall.mesh.indexBitCount)); cmdBuffer.drawIndexed(drawcall.mesh.indexCount, drawcall.instanceCount, 0, 0, {}); - } - else { + } else { cmdBuffer.draw(drawcall.mesh.indexCount, drawcall.instanceCount, 0, 0, {}); } } @@ -403,8 +409,8 @@ namespace vkcv const vk::RenderPass renderpass = m_PassManager->getVkPass(renderpassHandle); const PassConfig passConfig = m_PassManager->getPassConfig(renderpassHandle); - const vk::Pipeline pipeline = m_PipelineManager->getVkPipeline(pipelineHandle); - const vk::PipelineLayout pipelineLayout = m_PipelineManager->getVkPipelineLayout(pipelineHandle); + const vk::Pipeline pipeline = m_GraphicsPipelineManager->getVkPipeline(pipelineHandle); + const vk::PipelineLayout pipelineLayout = m_GraphicsPipelineManager->getVkPipelineLayout(pipelineHandle); const vk::Rect2D renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height)); vk::CommandBuffer cmdBuffer = m_CommandStreamManager->getStreamCommandBuffer(cmdStreamHandle); @@ -429,13 +435,13 @@ namespace vkcv cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {}); - const GraphicsPipelineConfig &pipeConfig = m_PipelineManager->getPipelineConfig(pipelineHandle); + const GraphicsPipelineConfig &pipeConfig = m_GraphicsPipelineManager->getPipelineConfig(pipelineHandle); if (pipeConfig.isViewportDynamic()) { recordDynamicViewport(cmdBuffer, width, height); } for (size_t i = 0; i < drawcalls.size(); i++) { - recordDrawcall(*this, drawcalls[i], cmdBuffer, pipelineLayout, pushConstantData, i); + recordDrawcall(*m_DescriptorSetManager, drawcalls[i], cmdBuffer, pipelineLayout, pushConstantData, i); } cmdBuffer.endRenderPass(); @@ -473,8 +479,8 @@ namespace vkcv const vk::RenderPass renderpass = m_PassManager->getVkPass(renderpassHandle); const PassConfig passConfig = m_PassManager->getPassConfig(renderpassHandle); - const vk::Pipeline pipeline = m_PipelineManager->getVkPipeline(pipelineHandle); - const vk::PipelineLayout pipelineLayout = m_PipelineManager->getVkPipelineLayout(pipelineHandle); + const vk::Pipeline pipeline = m_GraphicsPipelineManager->getVkPipeline(pipelineHandle); + const vk::PipelineLayout pipelineLayout = m_GraphicsPipelineManager->getVkPipelineLayout(pipelineHandle); const vk::Rect2D renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height)); vk::CommandBuffer cmdBuffer = m_CommandStreamManager->getStreamCommandBuffer(cmdStreamHandle); @@ -502,7 +508,7 @@ namespace vkcv cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {}); - const GraphicsPipelineConfig &pipeConfig = m_PipelineManager->getPipelineConfig(pipelineHandle); + const GraphicsPipelineConfig &pipeConfig = m_GraphicsPipelineManager->getPipelineConfig(pipelineHandle); if (pipeConfig.isViewportDynamic()) { recordDynamicViewport(cmdBuffer, width, height); } @@ -517,7 +523,7 @@ namespace vkcv pushConstantData.getDrawcallData(0)); } - vkcv::DescriptorSet descSet = m_DescriptorManager->getDescriptorSet(compiledDescriptorSet); + const auto& descSet = m_DescriptorSetManager->getDescriptorSet(compiledDescriptorSet); cmdBuffer.bindDescriptorSets( vk::PipelineBindPoint::eGraphics, @@ -547,6 +553,7 @@ namespace vkcv } static void recordMeshShaderDrawcall(const Core& core, + const DescriptorSetManager &descriptorSetManager, vk::CommandBuffer cmdBuffer, vk::PipelineLayout pipelineLayout, const PushConstants& pushConstantData, @@ -567,7 +574,7 @@ namespace vkcv vk::PipelineBindPoint::eGraphics, pipelineLayout, descriptorUsage.setLocation, - core.getDescriptorSet(descriptorUsage.descriptorSet).vulkanHandle, + descriptorSetManager.getDescriptorSet(descriptorUsage.descriptorSet).vulkanHandle, nullptr); } @@ -608,8 +615,8 @@ namespace vkcv const vk::RenderPass renderpass = m_PassManager->getVkPass(renderpassHandle); const PassConfig passConfig = m_PassManager->getPassConfig(renderpassHandle); - const vk::Pipeline pipeline = m_PipelineManager->getVkPipeline(pipelineHandle); - const vk::PipelineLayout pipelineLayout = m_PipelineManager->getVkPipelineLayout(pipelineHandle); + const vk::Pipeline pipeline = m_GraphicsPipelineManager->getVkPipeline(pipelineHandle); + const vk::PipelineLayout pipelineLayout = m_GraphicsPipelineManager->getVkPipelineLayout(pipelineHandle); const vk::Rect2D renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height)); vk::CommandBuffer cmdBuffer = m_CommandStreamManager->getStreamCommandBuffer(cmdStreamHandle); @@ -634,7 +641,7 @@ namespace vkcv cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {}); - const GraphicsPipelineConfig& pipeConfig = m_PipelineManager->getPipelineConfig(pipelineHandle); + const GraphicsPipelineConfig& pipeConfig = m_GraphicsPipelineManager->getPipelineConfig(pipelineHandle); if (pipeConfig.isViewportDynamic()) { recordDynamicViewport(cmdBuffer, width, height); } @@ -643,6 +650,7 @@ namespace vkcv const uint32_t pushConstantOffset = i * pushConstantData.getSizePerDrawcall(); recordMeshShaderDrawcall( *this, + *m_DescriptorSetManager, cmdBuffer, pipelineLayout, pushConstantData, @@ -682,7 +690,7 @@ namespace vkcv vk::PipelineBindPoint::eRayTracingKHR, rtxPipelineLayout, usage.setLocation, - { getDescriptorSet(usage.descriptorSet).vulkanHandle }, + { m_DescriptorSetManager->getDescriptorSet(usage.descriptorSet).vulkanHandle }, usage.dynamicOffsets ); } @@ -723,7 +731,7 @@ namespace vkcv vk::PipelineBindPoint::eCompute, pipelineLayout, usage.setLocation, - { getDescriptorSet(usage.descriptorSet).vulkanHandle }, + { m_DescriptorSetManager->getDescriptorSet(usage.descriptorSet).vulkanHandle }, usage.dynamicOffsets ); } @@ -802,7 +810,7 @@ namespace vkcv vk::PipelineBindPoint::eCompute, pipelineLayout, usage.setLocation, - { getDescriptorSet(usage.descriptorSet).vulkanHandle }, + { m_DescriptorSetManager->getDescriptorSet(usage.descriptorSet).vulkanHandle }, usage.dynamicOffsets ); } @@ -1021,23 +1029,16 @@ namespace vkcv return getSwapchain(swapchainHandle); } - DescriptorSetLayoutHandle Core::createDescriptorSetLayout(const DescriptorBindings &bindings) - { - return m_DescriptorManager->createDescriptorSetLayout(bindings); - } - - DescriptorSetLayout Core::getDescriptorSetLayout(const DescriptorSetLayoutHandle handle) const - { - return m_DescriptorManager->getDescriptorSetLayout(handle); + DescriptorSetLayoutHandle Core::createDescriptorSetLayout(const DescriptorBindings &bindings) { + return m_DescriptorSetLayoutManager->createDescriptorSetLayout(bindings); } - DescriptorSetHandle Core::createDescriptorSet(const DescriptorSetLayoutHandle &layout) - { - return m_DescriptorManager->createDescriptorSet(layout); + DescriptorSetHandle Core::createDescriptorSet(const DescriptorSetLayoutHandle &layout) { + return m_DescriptorSetManager->createDescriptorSet(layout); } void Core::writeDescriptorSet(DescriptorSetHandle handle, const DescriptorWrites &writes) { - m_DescriptorManager->writeDescriptorSet( + m_DescriptorSetManager->writeDescriptorSet( handle, writes, *m_ImageManager, @@ -1045,10 +1046,6 @@ namespace vkcv *m_SamplerManager); } - DescriptorSet Core::getDescriptorSet(const DescriptorSetHandle handle) const { - return m_DescriptorManager->getDescriptorSet(handle); - } - void Core::prepareSwapchainImageForPresent(const CommandStreamHandle& cmdStream) { auto swapchainHandle = ImageHandle::createSwapchainImageHandle(); recordCommandsToStream(cmdStream, [swapchainHandle, this](const vk::CommandBuffer cmdBuffer) { @@ -1280,7 +1277,7 @@ namespace vkcv m_Context.getDevice(), vk::ObjectType::ePipeline, uint64_t(static_cast<VkPipeline>( - m_PipelineManager->getVkPipeline(handle) + m_GraphicsPipelineManager->getVkPipeline(handle) )), label ); @@ -1312,7 +1309,7 @@ namespace vkcv m_Context.getDevice(), vk::ObjectType::eDescriptorSet, uint64_t(static_cast<VkDescriptorSet>( - m_DescriptorManager->getDescriptorSet(handle).vulkanHandle + m_DescriptorSetManager->getDescriptorSet(handle).vulkanHandle )), label ); diff --git a/src/vkcv/DescriptorConfig.cpp b/src/vkcv/DescriptorBinding.cpp similarity index 86% rename from src/vkcv/DescriptorConfig.cpp rename to src/vkcv/DescriptorBinding.cpp index 15bb05fd9cb3e5430b2a9909a682c468dfcde342..0ed0144e29942630bd3627a2eac086e82a8b3da6 100644 --- a/src/vkcv/DescriptorConfig.cpp +++ b/src/vkcv/DescriptorBinding.cpp @@ -1,7 +1,7 @@ -#include "vkcv/DescriptorConfig.hpp" +#include "vkcv/DescriptorBinding.hpp" -namespace vkcv -{ +namespace vkcv { + bool DescriptorBinding::operator==(const DescriptorBinding &other) const { return (this->bindingID == other.bindingID) && @@ -10,4 +10,5 @@ namespace vkcv (this->shaderStages == other.shaderStages) && (this->variableCount == other.variableCount); } + } diff --git a/src/vkcv/DescriptorManager.cpp b/src/vkcv/DescriptorManager.cpp deleted file mode 100644 index a9cabbd4b65bd8e460bc3506338497992ded890a..0000000000000000000000000000000000000000 --- a/src/vkcv/DescriptorManager.cpp +++ /dev/null @@ -1,399 +0,0 @@ -#include "DescriptorManager.hpp" - -namespace vkcv -{ - DescriptorManager::DescriptorManager(vk::Device device) noexcept: - m_Device{ device } - { - /** - * Allocate the set size for the descriptor pools, namely 1000 units of each descriptor type below. - * Finally, create an initial pool. - */ - m_PoolSizes = { - vk::DescriptorPoolSize(vk::DescriptorType::eSampler, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eSampledImage, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eUniformBuffer, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eUniformBufferDynamic, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eStorageBufferDynamic, 1000), // for RTX - vk::DescriptorPoolSize(vk::DescriptorType::eAccelerationStructureKHR, 1000) // for RTX - }; - - m_PoolInfo = vk::DescriptorPoolCreateInfo( - vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet, - 1000, - static_cast<uint32_t>(m_PoolSizes.size()), - m_PoolSizes.data()); - - allocateDescriptorPool(); - } - - DescriptorManager::~DescriptorManager() noexcept - { - for (uint64_t id = 0; id < m_DescriptorSets.size(); id++) { - destroyDescriptorSetById(id); - } - - for (uint64_t id = 0; id < m_DescriptorSetLayouts.size(); id++) { - // Resets the usage count to zero for destruction. - m_DescriptorSetLayouts[id].layoutUsageCount = 0; - destroyDescriptorSetLayoutById(id); - } - - m_DescriptorSets.clear(); - m_DescriptorSetLayouts.clear(); - - for (const auto &pool : m_Pools) { - if (pool) { - m_Device.destroy(pool); - } - } - } - - DescriptorSetLayoutHandle DescriptorManager::createDescriptorSetLayout(const DescriptorBindings &bindings) - { - for (size_t i = 0; i < m_DescriptorSetLayouts.size(); i++) - { - if(m_DescriptorSetLayouts[i].descriptorBindings.size() != bindings.size()) - continue; - - if (m_DescriptorSetLayouts[i].descriptorBindings == bindings) - { - m_DescriptorSetLayouts[i].layoutUsageCount++; - return DescriptorSetLayoutHandle(i, [&](uint64_t id) { destroyDescriptorSetLayoutById(id); }); - } - } - - //create the descriptor set's layout and binding flags by iterating over its bindings - std::vector<vk::DescriptorSetLayoutBinding> bindingsVector = {}; - std::vector<vk::DescriptorBindingFlags> bindingsFlags = {}; - - for (auto bindingElem : bindings) - { - DescriptorBinding binding = bindingElem.second; - uint32_t bindingID = bindingElem.first; - - bindingsVector.emplace_back( - bindingID, - getVkDescriptorType(binding.descriptorType), - binding.descriptorCount, - getShaderStageFlags(binding.shaderStages), - nullptr - ); - - vk::DescriptorBindingFlags flags; - - if (binding.variableCount) - flags |= vk::DescriptorBindingFlagBits::eVariableDescriptorCount; - - if (binding.partialBinding) - flags |= vk::DescriptorBindingFlagBits::ePartiallyBound; - - bindingsFlags.push_back(flags); - } - - vk::DescriptorSetLayoutBindingFlagsCreateInfo bindingFlagsInfo ( - bindingsFlags.size(), bindingsFlags.data() - ); - - //create the descriptor set's layout from the binding data gathered above - vk::DescriptorSetLayout vulkanHandle; - vk::DescriptorSetLayoutCreateInfo layoutInfo(vk::DescriptorSetLayoutCreateFlags(), bindingsVector); - layoutInfo.setPNext(&bindingFlagsInfo); - - auto result = m_Device.createDescriptorSetLayout(&layoutInfo, nullptr, &vulkanHandle); - if (result != vk::Result::eSuccess) { - vkcv_log(LogLevel::ERROR, "Failed to create descriptor set layout"); - return DescriptorSetLayoutHandle(); - }; - - const uint64_t id = m_DescriptorSetLayouts.size(); - m_DescriptorSetLayouts.push_back({vulkanHandle, bindings, 1}); - return DescriptorSetLayoutHandle(id, [&](uint64_t id) { destroyDescriptorSetLayoutById(id); }); - } - - DescriptorSetHandle DescriptorManager::createDescriptorSet(const DescriptorSetLayoutHandle &layout) - { - //create and allocate the set based on the layout provided - DescriptorSetLayout setLayout = m_DescriptorSetLayouts[layout.getId()]; - vk::DescriptorSet vulkanHandle; - vk::DescriptorSetAllocateInfo allocInfo(m_Pools.back(), 1, &setLayout.vulkanHandle); - - uint32_t sumVariableDescriptorCounts = 0; - for (auto bindingElem : setLayout.descriptorBindings) - { - auto binding = bindingElem.second; - if(binding.variableCount) - sumVariableDescriptorCounts += binding.descriptorCount; - } - - vk::DescriptorSetVariableDescriptorCountAllocateInfo variableAllocInfo(1, &sumVariableDescriptorCounts); - - if (sumVariableDescriptorCounts > 0) { - allocInfo.setPNext(&variableAllocInfo); - } - - auto result = m_Device.allocateDescriptorSets(&allocInfo, &vulkanHandle); - if(result != vk::Result::eSuccess) - { - //create a new descriptor pool if the previous one ran out of memory - if (result == vk::Result::eErrorOutOfPoolMemory) { - allocateDescriptorPool(); - allocInfo.setDescriptorPool(m_Pools.back()); - result = m_Device.allocateDescriptorSets(&allocInfo, &vulkanHandle); - } - - if (result != vk::Result::eSuccess) { - vkcv_log(LogLevel::ERROR, "Failed to create descriptor set (%s)", - vk::to_string(result).c_str()); - return DescriptorSetHandle(); - } - }; - - size_t poolIndex = (m_Pools.size() - 1); - const uint64_t id = m_DescriptorSets.size(); - m_DescriptorSets.push_back({ vulkanHandle, layout, poolIndex }); - return DescriptorSetHandle(id, [&](uint64_t id) { destroyDescriptorSetById(id); }); - } - - /** - * @brief Structure to store details to write to a descriptor set. - */ - struct WriteDescriptorSetInfo { - size_t imageInfoIndex; - size_t bufferInfoIndex; - uint32_t binding; - uint32_t arrayElementIndex; - uint32_t descriptorCount; - vk::DescriptorType type; - }; - - void DescriptorManager::writeDescriptorSet( - const DescriptorSetHandle &handle, - const DescriptorWrites &writes, - const ImageManager &imageManager, - const BufferManager &bufferManager, - const SamplerManager &samplerManager) { - vk::DescriptorSet set = m_DescriptorSets[handle.getId()].vulkanHandle; - - std::vector<vk::DescriptorImageInfo> imageInfos; - std::vector<vk::DescriptorBufferInfo> bufferInfos; - - std::vector<WriteDescriptorSetInfo> writeInfos; - - for (const auto& write : writes.getSampledImageWrites()) - { - const vk::ImageLayout layout = (write.useGeneralLayout? - vk::ImageLayout::eGeneral : - vk::ImageLayout::eShaderReadOnlyOptimal - ); - - for (uint32_t i = 0; i < write.mipCount; i++) { - const vk::DescriptorImageInfo imageInfo( - nullptr, - imageManager.getVulkanImageView( - write.image, - write.mipLevel + i, - write.arrayView - ), - layout - ); - - imageInfos.push_back(imageInfo); - } - - WriteDescriptorSetInfo vulkanWrite = { - imageInfos.size() + 1 - write.mipCount, - 0, - write.binding, - write.arrayIndex, - write.mipCount, - vk::DescriptorType::eSampledImage, - }; - - writeInfos.push_back(vulkanWrite); - } - - for (const auto& write : writes.getStorageImageWrites()) { - for (uint32_t i = 0; i < write.mipCount; i++) { - const vk::DescriptorImageInfo imageInfo( - nullptr, - imageManager.getVulkanImageView( - write.image, - write.mipLevel + i, - write.arrayView - ), - vk::ImageLayout::eGeneral - ); - - imageInfos.push_back(imageInfo); - } - - WriteDescriptorSetInfo vulkanWrite = { - imageInfos.size() + 1 - write.mipCount, - 0, - write.binding, - 0, - write.mipCount, - vk::DescriptorType::eStorageImage - }; - - writeInfos.push_back(vulkanWrite); - } - - for (const auto& write : writes.getUniformBufferWrites()) { - const size_t size = bufferManager.getBufferSize(write.buffer); - const uint32_t offset = std::clamp<uint32_t>(write.offset, 0, size); - - const vk::DescriptorBufferInfo bufferInfo( - bufferManager.getBuffer(write.buffer), - offset, - write.size == 0? size : std::min<uint32_t>( - write.size, size - offset - ) - ); - - bufferInfos.push_back(bufferInfo); - - WriteDescriptorSetInfo vulkanWrite = { - 0, - bufferInfos.size(), - write.binding, - 0, - 1, - write.dynamic? - vk::DescriptorType::eUniformBufferDynamic : - vk::DescriptorType::eUniformBuffer - }; - - writeInfos.push_back(vulkanWrite); - } - - for (const auto& write : writes.getStorageBufferWrites()) { - const size_t size = bufferManager.getBufferSize(write.buffer); - const uint32_t offset = std::clamp<uint32_t>(write.offset, 0, size); - - const vk::DescriptorBufferInfo bufferInfo( - bufferManager.getBuffer(write.buffer), - offset, - write.size == 0? size : std::min<uint32_t>( - write.size, size - offset - ) - ); - - bufferInfos.push_back(bufferInfo); - - WriteDescriptorSetInfo vulkanWrite = { - 0, - bufferInfos.size(), - write.binding, - 0, - 1, - write.dynamic? - vk::DescriptorType::eStorageBufferDynamic : - vk::DescriptorType::eStorageBuffer - }; - - writeInfos.push_back(vulkanWrite); - } - - for (const auto& write : writes.getSamplerWrites()) { - const vk::Sampler& sampler = samplerManager.getVulkanSampler(write.sampler); - - const vk::DescriptorImageInfo imageInfo( - sampler, - nullptr, - vk::ImageLayout::eGeneral - ); - - imageInfos.push_back(imageInfo); - - WriteDescriptorSetInfo vulkanWrite = { - imageInfos.size(), - 0, - write.binding, - 0, - 1, - vk::DescriptorType::eSampler - }; - - writeInfos.push_back(vulkanWrite); - } - - std::vector<vk::WriteDescriptorSet> vulkanWrites; - - for (const auto& write : writeInfos) { - vk::WriteDescriptorSet vulkanWrite( - set, - write.binding, - write.arrayElementIndex, - write.descriptorCount, - write.type, - (write.imageInfoIndex > 0? &(imageInfos[write.imageInfoIndex - 1]) : nullptr), - (write.bufferInfoIndex > 0? &(bufferInfos[write.bufferInfoIndex - 1]) : nullptr) - ); - - vulkanWrites.push_back(vulkanWrite); - } - - m_Device.updateDescriptorSets(vulkanWrites, nullptr); - } - - DescriptorSetLayout DescriptorManager::getDescriptorSetLayout(const DescriptorSetLayoutHandle handle) const - { - return m_DescriptorSetLayouts[handle.getId()]; - } - - DescriptorSet DescriptorManager::getDescriptorSet(const DescriptorSetHandle handle) const { - return m_DescriptorSets[handle.getId()]; - } - - void DescriptorManager::destroyDescriptorSetById(uint64_t id) { - if (id >= m_DescriptorSets.size()) { - vkcv_log(LogLevel::ERROR, "Invalid id"); - return; - } - - auto& set = m_DescriptorSets[id]; - - if (set.vulkanHandle) { - m_Device.freeDescriptorSets(m_Pools[set.poolIndex], 1, &(set.vulkanHandle)); - set.setLayoutHandle = DescriptorSetLayoutHandle(); - set.vulkanHandle = nullptr; - } - } - - void DescriptorManager::destroyDescriptorSetLayoutById(uint64_t id) { - if (id >= m_DescriptorSetLayouts.size()) { - vkcv_log(LogLevel::ERROR, "Invalid id"); - return; - } - - auto& layout = m_DescriptorSetLayouts[id]; - - if (layout.layoutUsageCount > 1) { - layout.layoutUsageCount--; - return; - } else { - layout.layoutUsageCount = 0; - } - - if (layout.vulkanHandle){ - m_Device.destroy(layout.vulkanHandle); - layout.vulkanHandle = nullptr; - } - } - - vk::DescriptorPool DescriptorManager::allocateDescriptorPool() { - vk::DescriptorPool pool; - if (m_Device.createDescriptorPool(&m_PoolInfo, nullptr, &pool) != vk::Result::eSuccess) { - vkcv_log(LogLevel::WARNING, "Failed to allocate descriptor pool"); - pool = nullptr; - } else { - m_Pools.push_back(pool); - } - - return pool; - } - -} diff --git a/src/vkcv/DescriptorManager.hpp b/src/vkcv/DescriptorManager.hpp deleted file mode 100644 index 7b79e3327bf79a8e3afd6d77210dfb956851c06b..0000000000000000000000000000000000000000 --- a/src/vkcv/DescriptorManager.hpp +++ /dev/null @@ -1,120 +0,0 @@ -#pragma once - -/** - * @authors Artur Wasmut, Susanne D�tsch, Simeon Hermann, Tobias Frisch - * @file src/vkcv/DescriptorManager.cpp - * @brief Creation and handling of descriptor sets and the respective descriptor pools - */ -#include <vulkan/vulkan.hpp> - -#include "vkcv/Handles.hpp" -#include "vkcv/DescriptorConfig.hpp" -#include "vkcv/DescriptorWrites.hpp" - -#include "ImageManager.hpp" -#include "BufferManager.hpp" -#include "SamplerManager.hpp" - -namespace vkcv -{ - - /** - * @brief Class to manage descriptor sets and descriptor set layouts. - */ - class DescriptorManager - { - public: - /** - * @brief Constructor of the descriptor manager - * - * @param[in,out] device Vulkan device - */ - explicit DescriptorManager(vk::Device device) noexcept; - - /** - * @brief Destructor of the descriptor manager - */ - ~DescriptorManager() noexcept; - - /** - * @brief Creates a descriptor set layout with given descriptor bindings - * or returns a matching handle. - * - * @param[in] bindings Descriptor bindings - * @return Handle of descriptor set layout - */ - DescriptorSetLayoutHandle createDescriptorSetLayout(const DescriptorBindings &bindings); - - /** - * @brief Creates a descriptor set using a given descriptor set layout. - * - * @param[in] layout Handle of descriptor set layout - * @return Handle of descriptor set - */ - DescriptorSetHandle createDescriptorSet(const DescriptorSetLayoutHandle &layout); - - /** - * @brief Writes to a descriptor set using writes and all required managers. - * - * @param[in] handle Handle of descriptor set - * @param[in] writes Descriptor set writes - * @param[in] imageManager Image manager - * @param[in] bufferManager Buffer manager - * @param[in] samplerManager Sampler manager - */ - void writeDescriptorSet(const DescriptorSetHandle &handle, - const DescriptorWrites &writes, - const ImageManager &imageManager, - const BufferManager &bufferManager, - const SamplerManager &samplerManager); - - [[nodiscard]] - DescriptorSetLayout getDescriptorSetLayout(const DescriptorSetLayoutHandle handle) const; - - [[nodiscard]] - DescriptorSet getDescriptorSet(const DescriptorSetHandle handle) const; - - private: - vk::Device m_Device; - std::vector<vk::DescriptorPool> m_Pools; - std::vector<vk::DescriptorPoolSize> m_PoolSizes; - vk::DescriptorPoolCreateInfo m_PoolInfo; - - /** - * Contains all the descriptor set layout descriptions - * that were requested by the user in calls of createDescriptorSetLayout. - */ - std::vector<DescriptorSetLayout> m_DescriptorSetLayouts; - - /** - * Contains all the descriptor sets that were created by the user in calls of createDescriptorSet. - */ - std::vector<DescriptorSet> m_DescriptorSets; - - /** - * @brief Destroys a specific descriptor set. - * - * @param[in] the DescriptorSetHandle - */ - void destroyDescriptorSetById(uint64_t id); - - /** - * @brief Revokes the usage of a specific descriptor set layout and - * destroys it once the usage count is at zero. - * - * @param[in] the DescriptorSetLayoutHandle - */ - void destroyDescriptorSetLayoutById(uint64_t id); - - /** - * @brief Creates a descriptor pool based on the poolSizes and poolInfo defined in the - * constructor is called initially in the constructor and then every time the pool runs - * out memory. - * - * @return a DescriptorPool object - */ - vk::DescriptorPool allocateDescriptorPool(); - - }; - -} \ No newline at end of file diff --git a/src/vkcv/DescriptorSetLayoutManager.cpp b/src/vkcv/DescriptorSetLayoutManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f3122964036e793f1f49f23fd56253e7fc3c9464 --- /dev/null +++ b/src/vkcv/DescriptorSetLayoutManager.cpp @@ -0,0 +1,109 @@ +#include "DescriptorSetLayoutManager.hpp" + +#include "vkcv/Core.hpp" + +namespace vkcv { + + uint64_t DescriptorSetLayoutManager::getIdFrom(const DescriptorSetLayoutHandle &handle) const { + return handle.getId(); + } + + DescriptorSetLayoutHandle DescriptorSetLayoutManager::createById(uint64_t id, + const HandleDestroyFunction &destroy) { + return DescriptorSetLayoutHandle(id, destroy); + } + + void DescriptorSetLayoutManager::destroyById(uint64_t id) { + auto& layout = getById(id); + + if (layout.layoutUsageCount > 1) { + layout.layoutUsageCount--; + return; + } else { + layout.layoutUsageCount = 0; + } + + if (layout.vulkanHandle){ + getCore().getContext().getDevice().destroy(layout.vulkanHandle); + layout.vulkanHandle = nullptr; + } + } + + DescriptorSetLayoutManager::DescriptorSetLayoutManager() noexcept : + HandleManager<DescriptorSetLayoutEntry, DescriptorSetLayoutHandle>() {} + + DescriptorSetLayoutManager::~DescriptorSetLayoutManager() noexcept { + for (uint64_t id = 0; id < getCount(); id++) { + // Resets the usage count to zero for destruction. + getById(id).layoutUsageCount = 0; + } + + clear(); + } + + DescriptorSetLayoutHandle DescriptorSetLayoutManager::createDescriptorSetLayout(const DescriptorBindings &bindings) { + for (uint64_t id = 0; id < getCount(); id++) { + auto& layout = getById(id); + + if (layout.descriptorBindings.size() != bindings.size()) + continue; + + if (layout.descriptorBindings == bindings) { + layout.layoutUsageCount++; + return createById(id, [&](uint64_t id) { destroyById(id); }); + } + } + + //create the descriptor set's layout and binding flags by iterating over its bindings + std::vector<vk::DescriptorSetLayoutBinding> bindingsVector = {}; + std::vector<vk::DescriptorBindingFlags> bindingsFlags = {}; + + for (auto bindingElem : bindings) + { + DescriptorBinding binding = bindingElem.second; + uint32_t bindingID = bindingElem.first; + + bindingsVector.emplace_back( + bindingID, + getVkDescriptorType(binding.descriptorType), + binding.descriptorCount, + getShaderStageFlags(binding.shaderStages), + nullptr + ); + + vk::DescriptorBindingFlags flags; + + if (binding.variableCount) + flags |= vk::DescriptorBindingFlagBits::eVariableDescriptorCount; + + if (binding.partialBinding) + flags |= vk::DescriptorBindingFlagBits::ePartiallyBound; + + bindingsFlags.push_back(flags); + } + + vk::DescriptorSetLayoutBindingFlagsCreateInfo bindingFlagsInfo ( + bindingsFlags.size(), bindingsFlags.data() + ); + + //create the descriptor set's layout from the binding data gathered above + vk::DescriptorSetLayout vulkanHandle; + vk::DescriptorSetLayoutCreateInfo layoutInfo(vk::DescriptorSetLayoutCreateFlags(), bindingsVector); + layoutInfo.setPNext(&bindingFlagsInfo); + + auto result = getCore().getContext().getDevice().createDescriptorSetLayout(&layoutInfo, + nullptr, + &vulkanHandle); + if (result != vk::Result::eSuccess) { + vkcv_log(LogLevel::ERROR, "Failed to create descriptor set layout"); + return DescriptorSetLayoutHandle(); + }; + + return add({ vulkanHandle, bindings, 1 }); + } + + const DescriptorSetLayoutEntry& DescriptorSetLayoutManager::getDescriptorSetLayout(const DescriptorSetLayoutHandle& handle) const { + return (*this)[handle]; + } + +} diff --git a/src/vkcv/DescriptorSetLayoutManager.hpp b/src/vkcv/DescriptorSetLayoutManager.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0dd2598c70fdeb6aeb3e9da1adc48b1a480e71c5 --- /dev/null +++ b/src/vkcv/DescriptorSetLayoutManager.hpp @@ -0,0 +1,70 @@ +#pragma once +/** + * @authors Artur Wasmut, Susanne D�tsch, Simeon Hermann, Tobias Frisch + * @file src/vkcv/DescriptorManager.cpp + * @brief Creation and handling of descriptor set layouts. + */ +#include <vulkan/vulkan.hpp> + +#include "vkcv/DescriptorBinding.hpp" + +#include "HandleManager.hpp" + +namespace vkcv { + + /** + * @brief Structure to store details about a descriptor set layout. + */ + struct DescriptorSetLayoutEntry { + vk::DescriptorSetLayout vulkanHandle; + DescriptorBindings descriptorBindings; + size_t layoutUsageCount; + }; + + /** + * @brief Class to manage descriptor set layouts. + */ + class DescriptorSetLayoutManager : public HandleManager<DescriptorSetLayoutEntry, DescriptorSetLayoutHandle> { + friend class Core; + private: + [[nodiscard]] + uint64_t getIdFrom(const DescriptorSetLayoutHandle& handle) const override; + + [[nodiscard]] + DescriptorSetLayoutHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override; + + /** + * Destroys and deallocates descriptor set layout represented by a given + * descriptor set layout handle id. + * + * @param id Descriptor set layout handle id + */ + void destroyById(uint64_t id) override; + + public: + /** + * @brief Constructor of the descriptor set layout manager + */ + DescriptorSetLayoutManager() noexcept; + + /** + * @brief Destructor of the descriptor set layout manager + */ + ~DescriptorSetLayoutManager() noexcept override; + + /** + * @brief Creates a descriptor set layout with given descriptor bindings + * or returns a matching handle. + * + * @param[in] bindings Descriptor bindings + * @return Handle of descriptor set layout + */ + [[nodiscard]] + DescriptorSetLayoutHandle createDescriptorSetLayout(const DescriptorBindings &bindings); + + [[nodiscard]] + const DescriptorSetLayoutEntry& getDescriptorSetLayout(const DescriptorSetLayoutHandle& handle) const; + + }; + +} diff --git a/src/vkcv/DescriptorSetManager.cpp b/src/vkcv/DescriptorSetManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31432bf2bd26920a3811255376f02e415e176b84 --- /dev/null +++ b/src/vkcv/DescriptorSetManager.cpp @@ -0,0 +1,314 @@ +#include "DescriptorSetManager.hpp" + +#include "vkcv/Core.hpp" + +namespace vkcv { + + bool DescriptorSetManager::init(Core &core, DescriptorSetLayoutManager& descriptorSetLayoutManager) { + if (!HandleManager<DescriptorSetEntry, DescriptorSetHandle>::init(core)) { + return false; + } + + m_DescriptorSetLayoutManager = &descriptorSetLayoutManager; + + /** + * Allocate the set size for the descriptor pools, namely 1000 units of each descriptor type below. + * Finally, create an initial pool. + */ + m_PoolSizes = { + vk::DescriptorPoolSize(vk::DescriptorType::eSampler, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eSampledImage, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eUniformBuffer, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eUniformBufferDynamic, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eStorageBufferDynamic, 1000), // for RTX + vk::DescriptorPoolSize(vk::DescriptorType::eAccelerationStructureKHR, 1000) // for RTX + }; + + m_PoolInfo = vk::DescriptorPoolCreateInfo( + vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet, + 1000, + static_cast<uint32_t>(m_PoolSizes.size()), + m_PoolSizes.data() + ); + + return allocateDescriptorPool(); + } + + uint64_t DescriptorSetManager::getIdFrom(const DescriptorSetHandle &handle) const { + return handle.getId(); + } + + DescriptorSetHandle DescriptorSetManager::createById(uint64_t id, + const HandleDestroyFunction &destroy) { + return DescriptorSetHandle(id, destroy); + } + + void DescriptorSetManager::destroyById(uint64_t id) { + auto& set = getById(id); + + if (set.vulkanHandle) { + getCore().getContext().getDevice().freeDescriptorSets(m_Pools[set.poolIndex], 1, + &(set.vulkanHandle)); + set.setLayoutHandle = DescriptorSetLayoutHandle(); + set.vulkanHandle = nullptr; + } + } + + vk::DescriptorPool DescriptorSetManager::allocateDescriptorPool() { + vk::DescriptorPool pool; + if (getCore().getContext().getDevice().createDescriptorPool(&m_PoolInfo, + nullptr, + &pool) != vk::Result::eSuccess) { + vkcv_log(LogLevel::WARNING, "Failed to allocate descriptor pool"); + pool = nullptr; + } else { + m_Pools.push_back(pool); + } + + return pool; + } + + DescriptorSetManager::DescriptorSetManager() noexcept : + HandleManager<DescriptorSetEntry, DescriptorSetHandle>() { + + } + + DescriptorSetManager::~DescriptorSetManager() noexcept { + clear(); + + for (const auto &pool : m_Pools) { + if (pool) { + getCore().getContext().getDevice().destroy(pool); + } + } + } + + DescriptorSetHandle DescriptorSetManager::createDescriptorSet(const DescriptorSetLayoutHandle &layout) { + //create and allocate the set based on the layout provided + const auto& setLayout = m_DescriptorSetLayoutManager->getDescriptorSetLayout(layout); + + vk::DescriptorSet vulkanHandle; + vk::DescriptorSetAllocateInfo allocInfo(m_Pools.back(), 1, &setLayout.vulkanHandle); + + uint32_t sumVariableDescriptorCounts = 0; + for (auto bindingElem : setLayout.descriptorBindings) { + auto binding = bindingElem.second; + + if(binding.variableCount) + sumVariableDescriptorCounts += binding.descriptorCount; + } + + vk::DescriptorSetVariableDescriptorCountAllocateInfo variableAllocInfo(1, &sumVariableDescriptorCounts); + + if (sumVariableDescriptorCounts > 0) { + allocInfo.setPNext(&variableAllocInfo); + } + + auto result = getCore().getContext().getDevice().allocateDescriptorSets(&allocInfo, &vulkanHandle); + if(result != vk::Result::eSuccess) + { + //create a new descriptor pool if the previous one ran out of memory + if (result == vk::Result::eErrorOutOfPoolMemory) { + allocateDescriptorPool(); + allocInfo.setDescriptorPool(m_Pools.back()); + result = getCore().getContext().getDevice().allocateDescriptorSets(&allocInfo, &vulkanHandle); + } + + if (result != vk::Result::eSuccess) { + vkcv_log(LogLevel::ERROR, "Failed to create descriptor set (%s)", + vk::to_string(result).c_str()); + return {}; + } + }; + + size_t poolIndex = (m_Pools.size() - 1); + return add({ vulkanHandle, layout, poolIndex }); + } + + /** + * @brief Structure to store details to write to a descriptor set. + */ + struct WriteDescriptorSetInfo { + size_t imageInfoIndex; + size_t bufferInfoIndex; + uint32_t binding; + uint32_t arrayElementIndex; + uint32_t descriptorCount; + vk::DescriptorType type; + }; + + void DescriptorSetManager::writeDescriptorSet(const DescriptorSetHandle &handle, + const DescriptorWrites &writes, + const ImageManager &imageManager, + const BufferManager &bufferManager, + const SamplerManager &samplerManager) { + auto& set = (*this)[handle]; + + std::vector<vk::DescriptorImageInfo> imageInfos; + std::vector<vk::DescriptorBufferInfo> bufferInfos; + + std::vector<WriteDescriptorSetInfo> writeInfos; + + for (const auto& write : writes.getSampledImageWrites()) { + const vk::ImageLayout layout = (write.useGeneralLayout? + vk::ImageLayout::eGeneral : + vk::ImageLayout::eShaderReadOnlyOptimal + ); + + for (uint32_t i = 0; i < write.mipCount; i++) { + const vk::DescriptorImageInfo imageInfo( + nullptr, + imageManager.getVulkanImageView( + write.image, + write.mipLevel + i, + write.arrayView + ), + layout + ); + + imageInfos.push_back(imageInfo); + } + + WriteDescriptorSetInfo vulkanWrite = { + imageInfos.size() + 1 - write.mipCount, + 0, + write.binding, + write.arrayIndex, + write.mipCount, + vk::DescriptorType::eSampledImage, + }; + + writeInfos.push_back(vulkanWrite); + } + + for (const auto& write : writes.getStorageImageWrites()) { + for (uint32_t i = 0; i < write.mipCount; i++) { + const vk::DescriptorImageInfo imageInfo( + nullptr, + imageManager.getVulkanImageView( + write.image, + write.mipLevel + i, + write.arrayView + ), + vk::ImageLayout::eGeneral + ); + + imageInfos.push_back(imageInfo); + } + + WriteDescriptorSetInfo vulkanWrite = { + imageInfos.size() + 1 - write.mipCount, + 0, + write.binding, + 0, + write.mipCount, + vk::DescriptorType::eStorageImage + }; + + writeInfos.push_back(vulkanWrite); + } + + for (const auto& write : writes.getUniformBufferWrites()) { + const size_t size = bufferManager.getBufferSize(write.buffer); + const uint32_t offset = std::clamp<uint32_t>(write.offset, 0, size); + + const vk::DescriptorBufferInfo bufferInfo( + bufferManager.getBuffer(write.buffer), + offset, + write.size == 0? size : std::min<uint32_t>( + write.size, size - offset + ) + ); + + bufferInfos.push_back(bufferInfo); + + WriteDescriptorSetInfo vulkanWrite = { + 0, + bufferInfos.size(), + write.binding, + 0, + 1, + write.dynamic? + vk::DescriptorType::eUniformBufferDynamic : + vk::DescriptorType::eUniformBuffer + }; + + writeInfos.push_back(vulkanWrite); + } + + for (const auto& write : writes.getStorageBufferWrites()) { + const size_t size = bufferManager.getBufferSize(write.buffer); + const uint32_t offset = std::clamp<uint32_t>(write.offset, 0, size); + + const vk::DescriptorBufferInfo bufferInfo( + bufferManager.getBuffer(write.buffer), + offset, + write.size == 0? size : std::min<uint32_t>( + write.size, size - offset + ) + ); + + bufferInfos.push_back(bufferInfo); + + WriteDescriptorSetInfo vulkanWrite = { + 0, + bufferInfos.size(), + write.binding, + 0, + 1, + write.dynamic? + vk::DescriptorType::eStorageBufferDynamic : + vk::DescriptorType::eStorageBuffer + }; + + writeInfos.push_back(vulkanWrite); + } + + for (const auto& write : writes.getSamplerWrites()) { + const vk::Sampler& sampler = samplerManager.getVulkanSampler(write.sampler); + + const vk::DescriptorImageInfo imageInfo( + sampler, + nullptr, + vk::ImageLayout::eGeneral + ); + + imageInfos.push_back(imageInfo); + + WriteDescriptorSetInfo vulkanWrite = { + imageInfos.size(), + 0, + write.binding, + 0, + 1, + vk::DescriptorType::eSampler + }; + + writeInfos.push_back(vulkanWrite); + } + + std::vector<vk::WriteDescriptorSet> vulkanWrites; + + for (const auto& write : writeInfos) { + vk::WriteDescriptorSet vulkanWrite ( + set.vulkanHandle, + write.binding, + write.arrayElementIndex, + write.descriptorCount, + write.type, + (write.imageInfoIndex > 0? &(imageInfos[write.imageInfoIndex - 1]) : nullptr), + (write.bufferInfoIndex > 0? &(bufferInfos[write.bufferInfoIndex - 1]) : nullptr) + ); + + vulkanWrites.push_back(vulkanWrite); + } + + getCore().getContext().getDevice().updateDescriptorSets(vulkanWrites, nullptr); + } + + const DescriptorSetEntry& DescriptorSetManager::getDescriptorSet(const DescriptorSetHandle& handle) const { + return (*this)[handle]; + } + +} diff --git a/src/vkcv/DescriptorSetManager.hpp b/src/vkcv/DescriptorSetManager.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f3c13aff26832888b2f43e33a03feb1ace77fb93 --- /dev/null +++ b/src/vkcv/DescriptorSetManager.hpp @@ -0,0 +1,106 @@ +#pragma once +/** + * @authors Artur Wasmut, Susanne D�tsch, Simeon Hermann, Tobias Frisch + * @file src/vkcv/DescriptorManager.cpp + * @brief Creation and handling of descriptor sets and the respective descriptor pools. + */ +#include <vulkan/vulkan.hpp> + +#include "vkcv/DescriptorBinding.hpp" +#include "vkcv/DescriptorWrites.hpp" + +#include "HandleManager.hpp" +#include "BufferManager.hpp" +#include "DescriptorSetLayoutManager.hpp" +#include "ImageManager.hpp" +#include "SamplerManager.hpp" + +namespace vkcv { + + /** + * @brief Structure to store details about a descriptor set. + */ + struct DescriptorSetEntry { + vk::DescriptorSet vulkanHandle; + DescriptorSetLayoutHandle setLayoutHandle; + size_t poolIndex; + }; + + /** + * @brief Class to manage descriptor sets. + */ + class DescriptorSetManager : public HandleManager<DescriptorSetEntry, DescriptorSetHandle> { + friend class Core; + private: + DescriptorSetLayoutManager* m_DescriptorSetLayoutManager; + + std::vector<vk::DescriptorPool> m_Pools; + std::vector<vk::DescriptorPoolSize> m_PoolSizes; + vk::DescriptorPoolCreateInfo m_PoolInfo; + + bool init(Core& core, DescriptorSetLayoutManager& descriptorSetLayoutManager); + + [[nodiscard]] + uint64_t getIdFrom(const DescriptorSetHandle& handle) const override; + + [[nodiscard]] + DescriptorSetHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override; + + /** + * Destroys and deallocates descriptor set represented by a given + * descriptor set handle id. + * + * @param id Descriptor set handle id + */ + void destroyById(uint64_t id) override; + + /** + * @brief Creates a descriptor pool based on the poolSizes and poolInfo defined in the + * constructor is called initially in the constructor and then every time the pool runs + * out memory. + * + * @return a DescriptorPool object + */ + vk::DescriptorPool allocateDescriptorPool(); + + public: + /** + * @brief Constructor of the descriptor set manager + */ + DescriptorSetManager() noexcept; + + /** + * @brief Destructor of the descriptor set manager + */ + ~DescriptorSetManager() noexcept override; + + /** + * @brief Creates a descriptor set using a given descriptor set layout. + * + * @param[in] layout Handle of descriptor set layout + * @return Handle of descriptor set + */ + [[nodiscard]] + DescriptorSetHandle createDescriptorSet(const DescriptorSetLayoutHandle &layout); + + /** + * @brief Writes to a descriptor set using writes and all required managers. + * + * @param[in] handle Handle of descriptor set + * @param[in] writes Descriptor set writes + * @param[in] imageManager Image manager + * @param[in] bufferManager Buffer manager + * @param[in] samplerManager Sampler manager + */ + void writeDescriptorSet(const DescriptorSetHandle &handle, + const DescriptorWrites &writes, + const ImageManager &imageManager, + const BufferManager &bufferManager, + const SamplerManager &samplerManager); + + [[nodiscard]] + const DescriptorSetEntry& getDescriptorSet(const DescriptorSetHandle& handle) const; + + }; + +} diff --git a/src/vkcv/GraphicsPipelineManager.cpp b/src/vkcv/GraphicsPipelineManager.cpp index 9f30d92e728739fe13b2186bd16736b161979abe..09288ebffde9873363399fe78160f2cfef00f436 100644 --- a/src/vkcv/GraphicsPipelineManager.cpp +++ b/src/vkcv/GraphicsPipelineManager.cpp @@ -1,21 +1,38 @@ #include "GraphicsPipelineManager.hpp" + +#include "vkcv/Core.hpp" #include "vkcv/Image.hpp" #include "vkcv/Logger.hpp" -namespace vkcv -{ +namespace vkcv { - GraphicsPipelineManager::GraphicsPipelineManager(vk::Device device, vk::PhysicalDevice physicalDevice) noexcept : - m_Device(device), - m_physicalDevice(physicalDevice), - m_Pipelines{} - {} + uint64_t GraphicsPipelineManager::getIdFrom(const GraphicsPipelineHandle &handle) const { + return handle.getId(); + } - GraphicsPipelineManager::~GraphicsPipelineManager() noexcept - { - for (uint64_t id = 0; id < m_Pipelines.size(); id++) { - destroyPipelineById(id); - } + GraphicsPipelineHandle GraphicsPipelineManager::createById(uint64_t id, const HandleDestroyFunction &destroy) { + return GraphicsPipelineHandle(id, destroy); + } + + void GraphicsPipelineManager::destroyById(uint64_t id) { + auto& pipeline = getById(id); + + if (pipeline.m_handle) { + getCore().getContext().getDevice().destroy(pipeline.m_handle); + pipeline.m_handle = nullptr; + } + + if (pipeline.m_layout) { + getCore().getContext().getDevice().destroy(pipeline.m_layout); + pipeline.m_layout = nullptr; + } + } + + GraphicsPipelineManager::GraphicsPipelineManager() noexcept : + HandleManager<GraphicsPipelineEntry, GraphicsPipelineHandle>() {} + + GraphicsPipelineManager::~GraphicsPipelineManager() noexcept { + clear(); } // currently assuming default 32 bit formats, no lower precision or normalized variants supported @@ -433,7 +450,7 @@ namespace vkcv GraphicsPipelineHandle GraphicsPipelineManager::createPipeline(const GraphicsPipelineConfig &config, const PassManager& passManager, - const DescriptorManager& descriptorManager) { + const DescriptorSetLayoutManager& descriptorManager) { const vk::RenderPass &pass = passManager.getVkPass(config.getPass()); const auto& program = config.getShaderProgram(); @@ -451,21 +468,20 @@ namespace vkcv (existsTaskShader && existsMeshShader) ); - if (!validGeometryStages) - { + if (!validGeometryStages) { vkcv_log(LogLevel::ERROR, "Requires vertex or task and mesh shader"); - return GraphicsPipelineHandle(); + return {}; } if (!existsFragmentShader) { vkcv_log(LogLevel::ERROR, "Requires fragment shader code"); - return GraphicsPipelineHandle(); + return {}; } std::vector<vk::PipelineShaderStageCreateInfo> shaderStages; auto destroyShaderModules = [&shaderStages, this] { for (auto stage : shaderStages) { - m_Device.destroyShaderModule(stage.module); + getCore().getContext().getDevice().destroyShaderModule(stage.module); } shaderStages.clear(); }; @@ -475,15 +491,14 @@ namespace vkcv const bool success = createPipelineShaderStageCreateInfo( program, ShaderStage::VERTEX, - m_Device, + getCore().getContext().getDevice(), &createInfo); if (success) { shaderStages.push_back(createInfo); - } - else { + } else { destroyShaderModules(); - return GraphicsPipelineHandle(); + return {}; } } @@ -492,15 +507,14 @@ namespace vkcv const bool success = createPipelineShaderStageCreateInfo( program, ShaderStage::TASK, - m_Device, + getCore().getContext().getDevice(), &createInfo); if (success) { shaderStages.push_back(createInfo); - } - else { + } else { destroyShaderModules(); - return GraphicsPipelineHandle(); + return {}; } } @@ -509,15 +523,14 @@ namespace vkcv const bool success = createPipelineShaderStageCreateInfo( program, ShaderStage::MESH, - m_Device, + getCore().getContext().getDevice(), &createInfo); if (success) { shaderStages.push_back(createInfo); - } - else { + } else { destroyShaderModules(); - return GraphicsPipelineHandle(); + return {}; } } @@ -526,15 +539,14 @@ namespace vkcv const bool success = createPipelineShaderStageCreateInfo( program, ShaderStage::FRAGMENT, - m_Device, + getCore().getContext().getDevice(), &createInfo); if (success) { shaderStages.push_back(createInfo); - } - else { + } else { destroyShaderModules(); - return GraphicsPipelineHandle(); + return {}; } } @@ -543,15 +555,14 @@ namespace vkcv const bool success = createPipelineShaderStageCreateInfo( program, ShaderStage::GEOMETRY, - m_Device, + getCore().getContext().getDevice(), &createInfo); if (success) { shaderStages.push_back(createInfo); - } - else { + } else { destroyShaderModules(); - return GraphicsPipelineHandle(); + return {}; } } @@ -560,15 +571,14 @@ namespace vkcv const bool success = createPipelineShaderStageCreateInfo( program, ShaderStage::TESS_CONTROL, - m_Device, + getCore().getContext().getDevice(), &createInfo); if (success) { shaderStages.push_back(createInfo); - } - else { + } else { destroyShaderModules(); - return GraphicsPipelineHandle(); + return {}; } } @@ -577,15 +587,14 @@ namespace vkcv const bool success = createPipelineShaderStageCreateInfo( program, ShaderStage::TESS_EVAL, - m_Device, + getCore().getContext().getDevice(), &createInfo); if (success) { shaderStages.push_back(createInfo); - } - else { + } else { destroyShaderModules(); - return GraphicsPipelineHandle(); + return {}; } } @@ -617,7 +626,7 @@ namespace vkcv vk::PhysicalDeviceProperties deviceProperties; vk::PhysicalDeviceProperties2 deviceProperties2(deviceProperties); deviceProperties2.pNext = &conservativeRasterProperties; - m_physicalDevice.getProperties2(&deviceProperties2); + getCore().getContext().getPhysicalDevice().getProperties2(&deviceProperties2); vk::PipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo = createPipelineRasterizationStateCreateInfo(config, conservativeRasterProperties); @@ -644,9 +653,11 @@ namespace vkcv createPipelineLayoutCreateInfo(config, descriptorSetLayouts); vk::PipelineLayout vkPipelineLayout{}; - if (m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &vkPipelineLayout) != vk::Result::eSuccess) { + if (getCore().getContext().getDevice().createPipelineLayout(&pipelineLayoutCreateInfo, + nullptr, + &vkPipelineLayout) != vk::Result::eSuccess) { destroyShaderModules(); - return GraphicsPipelineHandle(); + return {}; } // Depth Stencil @@ -685,77 +696,38 @@ namespace vkcv ); vk::Pipeline vkPipeline{}; - if (m_Device.createGraphicsPipelines(nullptr, 1, &graphicsPipelineCreateInfo, nullptr, &vkPipeline) != vk::Result::eSuccess) + if (getCore().getContext().getDevice().createGraphicsPipelines(nullptr, + 1, + &graphicsPipelineCreateInfo, + nullptr, + &vkPipeline) != vk::Result::eSuccess) { // Catch runtime error if the creation of the pipeline fails. // Destroy everything to keep the memory clean. destroyShaderModules(); - return GraphicsPipelineHandle(); + return {}; } // Clean Up destroyShaderModules(); // Hand over Handler to main Application - const uint64_t id = m_Pipelines.size(); - m_Pipelines.push_back({ vkPipeline, vkPipelineLayout, config }); - return GraphicsPipelineHandle(id, [&](uint64_t id) { destroyPipelineById(id); }); + return add({ vkPipeline, vkPipelineLayout, config }); } - vk::Pipeline GraphicsPipelineManager::getVkPipeline(const GraphicsPipelineHandle &handle) const - { - const uint64_t id = handle.getId(); - - if (id >= m_Pipelines.size()) { - return nullptr; - } - - auto& pipeline = m_Pipelines[id]; - + vk::Pipeline GraphicsPipelineManager::getVkPipeline(const GraphicsPipelineHandle &handle) const { + auto& pipeline = (*this)[handle]; return pipeline.m_handle; } - vk::PipelineLayout GraphicsPipelineManager::getVkPipelineLayout(const GraphicsPipelineHandle &handle) const - { - const uint64_t id = handle.getId(); - - if (id >= m_Pipelines.size()) { - return nullptr; - } - - auto& pipeline = m_Pipelines[id]; - + vk::PipelineLayout GraphicsPipelineManager::getVkPipelineLayout(const GraphicsPipelineHandle &handle) const { + auto& pipeline = (*this)[handle]; return pipeline.m_layout; } - void GraphicsPipelineManager::destroyPipelineById(uint64_t id) { - if (id >= m_Pipelines.size()) { - return; - } - - auto& pipeline = m_Pipelines[id]; - - if (pipeline.m_handle) { - m_Device.destroy(pipeline.m_handle); - pipeline.m_handle = nullptr; - } - - if (pipeline.m_layout) { - m_Device.destroy(pipeline.m_layout); - pipeline.m_layout = nullptr; - } - } - - const GraphicsPipelineConfig& GraphicsPipelineManager::getPipelineConfig(const GraphicsPipelineHandle &handle) const - { - const uint64_t id = handle.getId(); - - if (id >= m_Pipelines.size()) { - static GraphicsPipelineConfig dummyConfig; - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return dummyConfig; - } - - return m_Pipelines[id].m_config; + const GraphicsPipelineConfig& GraphicsPipelineManager::getPipelineConfig(const GraphicsPipelineHandle &handle) const { + auto& pipeline = (*this)[handle]; + return pipeline.m_config; } + } diff --git a/src/vkcv/GraphicsPipelineManager.hpp b/src/vkcv/GraphicsPipelineManager.hpp index 511dcf47988028617712c191f79bdf1f292a200a..be18a4c983696eea177fbe6842e6f6ff57426b3a 100644 --- a/src/vkcv/GraphicsPipelineManager.hpp +++ b/src/vkcv/GraphicsPipelineManager.hpp @@ -10,23 +10,42 @@ #include <vulkan/vulkan.hpp> #include <vector> -#include "vkcv/Handles.hpp" +#include "HandleManager.hpp" #include "vkcv/GraphicsPipelineConfig.hpp" #include "PassManager.hpp" -#include "DescriptorManager.hpp" +#include "DescriptorSetLayoutManager.hpp" -namespace vkcv -{ +namespace vkcv { + + struct GraphicsPipelineEntry { + vk::Pipeline m_handle; + vk::PipelineLayout m_layout; + GraphicsPipelineConfig m_config; + }; /** * @brief Class to manage graphics pipelines. */ - class GraphicsPipelineManager - { + class GraphicsPipelineManager : public HandleManager<GraphicsPipelineEntry, GraphicsPipelineHandle> { + private: + [[nodiscard]] + uint64_t getIdFrom(const GraphicsPipelineHandle& handle) const override; + + [[nodiscard]] + GraphicsPipelineHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override; + + /** + * Destroys and deallocates graphics pipeline represented by a given + * graphics pipeline handle id. + * + * @param id Graphics pipeline handle id + */ + void destroyById(uint64_t id) override; + public: - GraphicsPipelineManager() = delete; // no default ctor - explicit GraphicsPipelineManager(vk::Device device, vk::PhysicalDevice physicalDevice) noexcept; // ctor - ~GraphicsPipelineManager() noexcept; // dtor + GraphicsPipelineManager() noexcept; + + ~GraphicsPipelineManager() noexcept override; // dtor GraphicsPipelineManager(const GraphicsPipelineManager &other) = delete; // copy-ctor GraphicsPipelineManager(GraphicsPipelineManager &&other) = delete; // move-ctor; @@ -46,7 +65,7 @@ namespace vkcv */ GraphicsPipelineHandle createPipeline(const GraphicsPipelineConfig &config, const PassManager& passManager, - const DescriptorManager& descriptorManager); + const DescriptorSetLayoutManager& descriptorManager); /** * Returns a vk::Pipeline object by handle. @@ -71,20 +90,7 @@ namespace vkcv */ [[nodiscard]] const GraphicsPipelineConfig &getPipelineConfig(const GraphicsPipelineHandle &handle) const; - - private: - struct GraphicsPipeline { - vk::Pipeline m_handle; - vk::PipelineLayout m_layout; - GraphicsPipelineConfig m_config; - }; - - vk::Device m_Device; - vk::PhysicalDevice m_physicalDevice; // needed to get infos to configure conservative rasterization - std::vector<GraphicsPipeline> m_Pipelines; - - void destroyPipelineById(uint64_t id); - + }; } diff --git a/src/vkcv/HandleManager.hpp b/src/vkcv/HandleManager.hpp new file mode 100644 index 0000000000000000000000000000000000000000..13213dc2a4ff5975458690ddc41e5a879580ee16 --- /dev/null +++ b/src/vkcv/HandleManager.hpp @@ -0,0 +1,116 @@ +#pragma once + +#include <optional> +#include <vector> + +#include "vkcv/Handles.hpp" +#include "vkcv/Logger.hpp" + +namespace vkcv { + + class Core; + + template<typename T, typename H = Handle> + class HandleManager { + friend class Core; + private: + Core* m_core; + std::vector<T> m_entries; + + protected: + HandleManager() noexcept : m_core(nullptr), m_entries() {} + + virtual bool init(Core& core) { + if (m_core) { + vkcv_log(vkcv::LogLevel::ERROR, "Manager is already initialized"); + return false; + } + + if (!m_entries.empty()) { + vkcv_log(vkcv::LogLevel::WARNING, "Entries added before initialization will be erased"); + } + + m_core = &core; + m_entries.clear(); + return true; + } + + [[nodiscard]] + const Core& getCore() const { + return *m_core; + } + + [[nodiscard]] + Core& getCore() { + return *m_core; + } + + [[nodiscard]] + size_t getCount() const { + return m_entries.size(); + } + + [[nodiscard]] + const T& getById(uint64_t id) const { + if (id >= m_entries.size()) { + static T invalid; + vkcv_log(vkcv::LogLevel::ERROR, "Invalid handle id"); + return invalid; + } + + return m_entries[id]; + } + + [[nodiscard]] + T& getById(uint64_t id) { + if (id >= m_entries.size()) { + static T invalid; + vkcv_log(vkcv::LogLevel::ERROR, "Invalid handle id"); + return invalid; + } + + return m_entries[id]; + } + + virtual uint64_t getIdFrom(const H& handle) const = 0; + + [[nodiscard]] + virtual const T& operator[](const H& handle) const { + const Handle& _handle = handle; + return getById(getIdFrom(static_cast<const H&>(_handle))); + } + + [[nodiscard]] + virtual T& operator[](const H& handle) { + const Handle& _handle = handle; + return getById(getIdFrom(static_cast<const H&>(_handle))); + } + + H add(const T &entry) { + const uint64_t id = m_entries.size(); + m_entries.push_back(entry); + return createById(id, [&](uint64_t id) { destroyById(id); }); + } + + virtual H createById(uint64_t id, const HandleDestroyFunction& destroy) = 0; + + virtual void destroyById(uint64_t id) = 0; + + void clear() { + for (uint64_t id = 0; id < m_entries.size(); id++) { + destroyById(id); + } + } + + public: + HandleManager(HandleManager&& other) = delete; + HandleManager(const HandleManager& other) = delete; + + HandleManager& operator=(HandleManager&& other) = delete; + HandleManager& operator=(const HandleManager& other) = delete; + + virtual ~HandleManager() noexcept = default; + + }; + +} diff --git a/src/vkcv/ImageConfig.cpp b/src/vkcv/ImageConfig.cpp index 80aeac3d0f702467c8edc1b0f7378d0d7f15b3db..5fe3f0a9a998040064be36ea03c20c17080c26e5 100644 --- a/src/vkcv/ImageConfig.cpp +++ b/src/vkcv/ImageConfig.cpp @@ -2,6 +2,7 @@ #include <vkcv/Logger.hpp> namespace vkcv { + vk::SampleCountFlagBits msaaToVkSampleCountFlag(Multisampling msaa) { switch (msaa) { case Multisampling::None: return vk::SampleCountFlagBits::e1; @@ -21,4 +22,5 @@ namespace vkcv { default: vkcv_log(vkcv::LogLevel::ERROR, "Unknown Multisampling enum setting"); return 1; } } + } \ No newline at end of file diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp index b6d5a1f49fd6bbf57656d32318704b88b350d9f4..fe01a57bb58e536d651da28138458abb2c573318 100644 --- a/src/vkcv/ImageManager.cpp +++ b/src/vkcv/ImageManager.cpp @@ -11,46 +11,139 @@ #include <algorithm> namespace vkcv { - - /** - * @brief searches memory type index for image allocation, combines requirements of image 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 image - */ - uint32_t searchImageMemoryType(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); + + bool ImageManager::init(Core &core, BufferManager &bufferManager) { + if (!HandleManager<ImageEntry, ImageHandle>::init(core)) { + return false; } - - // failed to find memory type - return -1; + + m_bufferManager = &bufferManager; + m_swapchainImages.clear(); + return true; } - - ImageManager::ImageManager(BufferManager& bufferManager) noexcept : - m_core(nullptr), m_bufferManager(bufferManager), m_images() - { + + uint64_t ImageManager::getIdFrom(const ImageHandle &handle) const { + return handle.getId(); } - - ImageManager::~ImageManager() noexcept { - for (uint64_t id = 0; id < m_images.size(); id++) { - destroyImageById(id); + + ImageHandle ImageManager::createById(uint64_t id, const HandleDestroyFunction &destroy) { + return ImageHandle(id, destroy); + } + + void ImageManager::destroyById(uint64_t id) { + auto& image = getById(id); + + const vk::Device& device = getCore().getContext().getDevice(); + + for (auto& view : image.m_viewPerMip) { + if (view) { + device.destroyImageView(view); + view = nullptr; + } + } + + for (auto& view : image.m_arrayViewPerMip) { + if (view) { + device.destroyImageView(view); + view = nullptr; + } + } + + const vma::Allocator& allocator = getCore().getContext().getAllocator(); + + if (image.m_handle) { + allocator.destroyImage(image.m_handle, image.m_allocation); + + image.m_handle = nullptr; + image.m_allocation = nullptr; + } + } + + const BufferManager &ImageManager::getBufferManager() const { + return *m_bufferManager; + } + + BufferManager &ImageManager::getBufferManager() { + return *m_bufferManager; + } + + void ImageManager::recordImageMipGenerationToCmdBuffer(vk::CommandBuffer cmdBuffer, + const ImageHandle& handle) { + auto& image = (*this)[handle]; + recordImageLayoutTransition(handle, 0, 0, vk::ImageLayout::eGeneral, cmdBuffer); + + vk::ImageAspectFlags aspectMask = isDepthImageFormat(image.m_format) ? + vk::ImageAspectFlagBits::eDepth : vk::ImageAspectFlagBits::eColor; + + uint32_t srcWidth = image.m_width; + uint32_t srcHeight = image.m_height; + uint32_t srcDepth = image.m_depth; + + auto half = [](uint32_t in) { + return std::max<uint32_t>(in / 2, 1); + }; + + uint32_t dstWidth = half(srcWidth); + uint32_t dstHeight = half(srcHeight); + uint32_t dstDepth = half(srcDepth); + + for (uint32_t srcMip = 0; srcMip < image.m_viewPerMip.size() - 1; srcMip++) { + uint32_t dstMip = srcMip + 1; + vk::ImageBlit region( + vk::ImageSubresourceLayers(aspectMask, srcMip, 0, 1), + { vk::Offset3D(0, 0, 0), vk::Offset3D(srcWidth, srcHeight, srcDepth) }, + vk::ImageSubresourceLayers(aspectMask, dstMip, 0, 1), + { vk::Offset3D(0, 0, 0), vk::Offset3D(dstWidth, dstHeight, dstDepth) }); + + cmdBuffer.blitImage( + image.m_handle, + vk::ImageLayout::eGeneral, + image.m_handle, + vk::ImageLayout::eGeneral, + region, + vk::Filter::eLinear); + + srcWidth = dstWidth; + srcHeight = dstHeight; + srcDepth = dstDepth; + + dstWidth = half(dstWidth); + dstHeight = half(dstHeight); + dstDepth = half(dstDepth); + + recordImageMemoryBarrier(handle, cmdBuffer); + } + } + + const ImageEntry &ImageManager::operator[](const ImageHandle &handle) const { + if (handle.isSwapchainImage()) { + return m_swapchainImages[m_currentSwapchainInputImage]; + } + + return HandleManager<ImageEntry, ImageHandle>::operator[](handle); + } + + ImageEntry &ImageManager::operator[](const ImageHandle &handle) { + if (handle.isSwapchainImage()) { + return m_swapchainImages[m_currentSwapchainInputImage]; } + return HandleManager<ImageEntry, ImageHandle>::operator[](handle); + } + + ImageManager::ImageManager() noexcept : + HandleManager<ImageEntry, ImageHandle>(), + m_bufferManager(nullptr), + m_swapchainImages(), + m_currentSwapchainInputImage(0) + {} + + ImageManager::~ImageManager() noexcept { + clear(); + for (const auto& swapchainImage : m_swapchainImages) { for (const auto view : swapchainImage.m_viewPerMip) { - m_core->getContext().getDevice().destroy(view); + getCore().getContext().getDevice().destroy(view); } } } @@ -73,9 +166,8 @@ namespace vkcv { uint32_t mipCount, bool supportStorage, bool supportColorAttachment, - Multisampling msaa) - { - const vk::PhysicalDevice& physicalDevice = m_core->getContext().getPhysicalDevice(); + Multisampling msaa) { + const vk::PhysicalDevice& physicalDevice = getCore().getContext().getPhysicalDevice(); const vk::FormatProperties formatProperties = physicalDevice.getFormatProperties(format); @@ -95,7 +187,7 @@ namespace vkcv { imageTiling = vk::ImageTiling::eLinear; if (!(formatProperties.linearTilingFeatures & vk::FormatFeatureFlagBits::eStorageImage)) - return ImageHandle(); + return {}; } } @@ -109,7 +201,7 @@ namespace vkcv { imageUsageFlags |= vk::ImageUsageFlagBits::eDepthStencilAttachment; } - const vma::Allocator& allocator = m_core->getContext().getAllocator(); + const vma::Allocator& allocator = getCore().getContext().getAllocator(); vk::ImageType imageType = vk::ImageType::e3D; vk::ImageViewType imageViewType = vk::ImageViewType::e3D; @@ -135,7 +227,7 @@ namespace vkcv { if (!formatProperties.optimalTilingFeatures) { if (!formatProperties.linearTilingFeatures) - return ImageHandle(); + return {}; imageTiling = vk::ImageTiling::eLinear; } @@ -190,7 +282,7 @@ namespace vkcv { aspectFlags = vk::ImageAspectFlagBits::eColor; } - const vk::Device& device = m_core->getContext().getDevice(); + const vk::Device& device = getCore().getContext().getDevice(); std::vector<vk::ImageView> views; std::vector<vk::ImageView> arrayViews; @@ -243,25 +335,22 @@ namespace vkcv { arrayViews.push_back(device.createImageView(imageViewCreateInfo)); } - const uint64_t id = m_images.size(); - m_images.push_back({ + return add({ image, allocation, views, arrayViews, - + width, height, depth, - + format, arrayLayers, vk::ImageLayout::eUndefined, supportStorage }); - - return ImageHandle(id, [&](uint64_t id) { destroyImageById(id); }); } ImageHandle ImageManager::createSwapchainImage() const { @@ -269,38 +358,18 @@ namespace vkcv { } vk::Image ImageManager::getVulkanImage(const ImageHandle &handle) const { - - if (handle.isSwapchainImage()) { - m_swapchainImages[m_currentSwapchainInputImage].m_handle; - } - - const uint64_t id = handle.getId(); - if (id >= m_images.size()) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return nullptr; - } - - auto& image = m_images[id]; - + auto& image = (*this)[handle]; return image.m_handle; } vk::DeviceMemory ImageManager::getVulkanDeviceMemory(const ImageHandle &handle) const { - if (handle.isSwapchainImage()) { vkcv_log(LogLevel::ERROR, "Swapchain image has no memory"); return nullptr; } - - const uint64_t id = handle.getId(); - if (id >= m_images.size()) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return nullptr; - } - - auto& image = m_images[id]; - const vma::Allocator& allocator = m_core->getContext().getAllocator(); + auto& image = (*this)[handle]; + const vma::Allocator& allocator = getCore().getContext().getAllocator(); auto info = allocator.getAllocationInfo( image.m_allocation @@ -312,18 +381,11 @@ namespace vkcv { vk::ImageView ImageManager::getVulkanImageView(const ImageHandle &handle, size_t mipLevel, bool arrayView) const { - if (handle.isSwapchainImage()) { return m_swapchainImages[m_currentSwapchainInputImage].m_viewPerMip[0]; } - - const uint64_t id = handle.getId(); - if (id >= m_images.size()) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return nullptr; - } - const auto& image = m_images[id]; + const auto& image = (*this)[handle]; const auto& views = arrayView? image.m_arrayViewPerMip : image.m_viewPerMip; if (mipLevel >= views.size()) { @@ -334,7 +396,7 @@ namespace vkcv { return views[mipLevel]; } - static vk::ImageMemoryBarrier createImageLayoutTransitionBarrier(const ImageManager::Image &image, + static vk::ImageMemoryBarrier createImageLayoutTransitionBarrier(const ImageEntry &image, uint32_t mipLevelCount, uint32_t mipLevelOffset, vk::ImageLayout newLayout) { @@ -375,22 +437,13 @@ namespace vkcv { } void ImageManager::switchImageLayoutImmediate(const ImageHandle& handle, vk::ImageLayout newLayout) { - uint64_t id = handle.getId(); - - const bool isSwapchainImage = handle.isSwapchainImage(); - - if (id >= m_images.size() && !isSwapchainImage) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return; - } - - auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; + auto& image = (*this)[handle]; const auto transitionBarrier = createImageLayoutTransitionBarrier(image, 0, 0, newLayout); SubmitInfo submitInfo; submitInfo.queueType = QueueType::Graphics; - m_core->recordAndSubmitCommandsImmediate( + getCore().recordAndSubmitCommandsImmediate( submitInfo, [transitionBarrier](const vk::CommandBuffer& commandBuffer) { // TODO: precise PipelineStageFlagBits, will require a lot of context @@ -414,15 +467,7 @@ namespace vkcv { uint32_t mipLevelOffset, vk::ImageLayout newLayout, vk::CommandBuffer cmdBuffer) { - const uint64_t id = handle.getId(); - const bool isSwapchainImage = handle.isSwapchainImage(); - - if (id >= m_images.size() && !isSwapchainImage) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return; - } - - auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; + auto& image = (*this)[handle]; const auto transitionBarrier = createImageLayoutTransitionBarrier( image, mipLevelCount, @@ -442,19 +487,9 @@ namespace vkcv { image.m_layout = newLayout; } - void ImageManager::recordImageMemoryBarrier( - const ImageHandle& handle, - vk::CommandBuffer cmdBuffer) { - - const uint64_t id = handle.getId(); - const bool isSwapchainImage = handle.isSwapchainImage(); - - if (id >= m_images.size() && !isSwapchainImage) { - std::cerr << "Error: ImageManager::recordImageMemoryBarrier invalid handle" << std::endl; - return; - } - - auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; + void ImageManager::recordImageMemoryBarrier(const ImageHandle& handle, + vk::CommandBuffer cmdBuffer) { + auto& image = (*this)[handle]; const auto transitionBarrier = createImageLayoutTransitionBarrier(image, 0, 0, image.m_layout); cmdBuffer.pipelineBarrier( @@ -485,22 +520,13 @@ namespace vkcv { } } - void ImageManager::fillImage(const ImageHandle& handle, const void* data, size_t size) - { - const uint64_t id = handle.getId(); - + void ImageManager::fillImage(const ImageHandle& handle, const void* data, size_t size) { if (handle.isSwapchainImage()) { vkcv_log(LogLevel::ERROR, "Swapchain image cannot be filled"); return; } - - if (id >= m_images.size()) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return; - } - - auto& image = m_images[id]; + auto& image = (*this)[handle]; switchImageLayoutImmediate( handle, vk::ImageLayout::eTransferDstOptimal); @@ -512,7 +538,7 @@ namespace vkcv { const size_t max_size = std::min(size, image_size); - BufferHandle bufferHandle = m_bufferManager.createBuffer( + BufferHandle bufferHandle = getBufferManager().createBuffer( TypeGuard(1), BufferType::STAGING, BufferMemoryType::DEVICE_LOCAL, @@ -520,14 +546,14 @@ namespace vkcv { false ); - m_bufferManager.fillBuffer(bufferHandle, data, max_size, 0); + getBufferManager().fillBuffer(bufferHandle, data, max_size, 0); - vk::Buffer stagingBuffer = m_bufferManager.getBuffer(bufferHandle); + vk::Buffer stagingBuffer = getBufferManager().getBuffer(bufferHandle); SubmitInfo submitInfo; submitInfo.queueType = QueueType::Transfer; - m_core->recordAndSubmitCommandsImmediate( + getCore().recordAndSubmitCommandsImmediate( submitInfo, [&image, &stagingBuffer](const vk::CommandBuffer& commandBuffer) { vk::ImageAspectFlags aspectFlags; @@ -569,89 +595,21 @@ namespace vkcv { ); } - void ImageManager::recordImageMipGenerationToCmdBuffer(vk::CommandBuffer cmdBuffer, const ImageHandle& handle) { - - const auto id = handle.getId(); - if (id >= m_images.size()) { - vkcv_log(vkcv::LogLevel::ERROR, "Invalid image handle"); - return; - } - - auto& image = m_images[id]; - recordImageLayoutTransition(handle, 0, 0, vk::ImageLayout::eGeneral, cmdBuffer); - - vk::ImageAspectFlags aspectMask = isDepthImageFormat(image.m_format) ? - vk::ImageAspectFlagBits::eDepth : vk::ImageAspectFlagBits::eColor; - - uint32_t srcWidth = image.m_width; - uint32_t srcHeight = image.m_height; - uint32_t srcDepth = image.m_depth; - - auto half = [](uint32_t in) { - return std::max<uint32_t>(in / 2, 1); - }; - - uint32_t dstWidth = half(srcWidth); - uint32_t dstHeight = half(srcHeight); - uint32_t dstDepth = half(srcDepth); - - for (uint32_t srcMip = 0; srcMip < image.m_viewPerMip.size() - 1; srcMip++) { - uint32_t dstMip = srcMip + 1; - vk::ImageBlit region( - vk::ImageSubresourceLayers(aspectMask, srcMip, 0, 1), - { vk::Offset3D(0, 0, 0), vk::Offset3D(srcWidth, srcHeight, srcDepth) }, - vk::ImageSubresourceLayers(aspectMask, dstMip, 0, 1), - { vk::Offset3D(0, 0, 0), vk::Offset3D(dstWidth, dstHeight, dstDepth) }); - - cmdBuffer.blitImage( - image.m_handle, - vk::ImageLayout::eGeneral, - image.m_handle, - vk::ImageLayout::eGeneral, - region, - vk::Filter::eLinear); - - srcWidth = dstWidth; - srcHeight = dstHeight; - srcDepth = dstDepth; - - dstWidth = half(dstWidth); - dstHeight = half(dstHeight); - dstDepth = half(dstDepth); - - recordImageMemoryBarrier(handle, cmdBuffer); - } - } - - void ImageManager::recordImageMipChainGenerationToCmdStream( - const vkcv::CommandStreamHandle& cmdStream, - const ImageHandle& handle) { - + void ImageManager::recordImageMipChainGenerationToCmdStream(const vkcv::CommandStreamHandle& cmdStream, + const ImageHandle& handle) { const auto record = [this, handle](const vk::CommandBuffer cmdBuffer) { recordImageMipGenerationToCmdBuffer(cmdBuffer, handle); }; - m_core->recordCommandsToStream(cmdStream, record, nullptr); + + getCore().recordCommandsToStream(cmdStream, record, nullptr); } - void ImageManager::recordMSAAResolve(vk::CommandBuffer cmdBuffer, ImageHandle src, ImageHandle dst) { - - const uint64_t srcId = src.getId(); - const uint64_t dstId = dst.getId(); - - const bool isSrcSwapchainImage = src.isSwapchainImage(); - const bool isDstSwapchainImage = dst.isSwapchainImage(); - - const bool isSrcHandleInvalid = srcId >= m_images.size() && !isSrcSwapchainImage; - const bool isDstHandleInvalid = dstId >= m_images.size() && !isDstSwapchainImage; - - if (isSrcHandleInvalid || isDstHandleInvalid) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return; - } - - auto& srcImage = isSrcSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[srcId]; - auto& dstImage = isDstSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[dstId]; - + void ImageManager::recordMSAAResolve(vk::CommandBuffer cmdBuffer, + const ImageHandle& src, + const ImageHandle& dst) { + auto& srcImage = (*this)[src]; + auto& dstImage = (*this)[dst]; + vk::ImageResolve region( vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1), vk::Offset3D(0, 0, 0), @@ -671,152 +629,62 @@ namespace vkcv { } uint32_t ImageManager::getImageWidth(const ImageHandle &handle) const { - const uint64_t id = handle.getId(); - const bool isSwapchainImage = handle.isSwapchainImage(); - - if (id >= m_images.size() && !isSwapchainImage) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return 0; - } - - auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; - + auto& image = (*this)[handle]; return image.m_width; } uint32_t ImageManager::getImageHeight(const ImageHandle &handle) const { - const uint64_t id = handle.getId(); - const bool isSwapchainImage = handle.isSwapchainImage(); - - if (id >= m_images.size() && !isSwapchainImage) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return 0; - } - - auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; - + auto& image = (*this)[handle]; return image.m_height; } uint32_t ImageManager::getImageDepth(const ImageHandle &handle) const { - const uint64_t id = handle.getId(); - const bool isSwapchainImage = handle.isSwapchainImage(); - - if (id >= m_images.size() && !isSwapchainImage) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return 0; - } - - auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; - + auto& image = (*this)[handle]; return image.m_depth; } - - void ImageManager::destroyImageById(uint64_t id) - { - if (id >= m_images.size()) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return; - } - - auto& image = m_images[id]; - - const vk::Device& device = m_core->getContext().getDevice(); - - for (auto& view : image.m_viewPerMip) { - if (view) { - device.destroyImageView(view); - view = nullptr; - } - } - - for (auto& view : image.m_arrayViewPerMip) { - if (view) { - device.destroyImageView(view); - view = nullptr; - } - } - - const vma::Allocator& allocator = m_core->getContext().getAllocator(); - - if (image.m_handle) { - allocator.destroyImage(image.m_handle, image.m_allocation); - - image.m_handle = nullptr; - image.m_allocation = nullptr; - } - } vk::Format ImageManager::getImageFormat(const ImageHandle& handle) const { - - const uint64_t id = handle.getId(); - const bool isSwapchainFormat = handle.isSwapchainImage(); - - if (id >= m_images.size() && !isSwapchainFormat) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return vk::Format::eUndefined; - } - - return isSwapchainFormat ? m_swapchainImages[m_currentSwapchainInputImage].m_format : m_images[id].m_format; + auto& image = (*this)[handle]; + return image.m_format; } bool ImageManager::isImageSupportingStorage(const ImageHandle& handle) const { - const uint64_t id = handle.getId(); - const bool isSwapchainFormat = handle.isSwapchainImage(); - - if (isSwapchainFormat) { - return false; - } - - if (id >= m_images.size()) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); + if (handle.isSwapchainImage()) { return false; } - return m_images[id].m_storage; + auto& image = (*this)[handle]; + return image.m_storage; } uint32_t ImageManager::getImageMipCount(const ImageHandle& handle) const { - const uint64_t id = handle.getId(); - if (handle.isSwapchainImage()) { return 1; } - - if (id >= m_images.size()) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return 0; - } - - return m_images[id].m_viewPerMip.size(); + + auto& image = (*this)[handle]; + return image.m_viewPerMip.size(); } uint32_t ImageManager::getImageArrayLayers(const ImageHandle& handle) const { - const uint64_t id = handle.getId(); - - if (handle.isSwapchainImage()) { - return m_swapchainImages[0].m_layers; - } - - if (id >= m_images.size()) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return 0; - } - - return m_images[id].m_layers; + auto& image = (*this)[handle]; + return image.m_layers; } void ImageManager::setCurrentSwapchainImageIndex(int index) { m_currentSwapchainInputImage = index; } - void ImageManager::setSwapchainImages(const std::vector<vk::Image>& images, const std::vector<vk::ImageView>& views, - uint32_t width, uint32_t height, vk::Format format) { + 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 (const auto& image : m_swapchainImages) { for (const auto& view : image.m_viewPerMip) { - m_core->getContext().getDevice().destroyImageView(view); + getCore().getContext().getDevice().destroyImageView(view); } } @@ -839,20 +707,10 @@ namespace vkcv { } } - void ImageManager::updateImageLayoutManual(const vkcv::ImageHandle& handle, const vk::ImageLayout layout) { - const uint64_t id = handle.getId(); - - if (handle.isSwapchainImage()) { - m_swapchainImages[m_currentSwapchainInputImage].m_layout = layout; - } - else { - if (id >= m_images.size()) { - vkcv_log(LogLevel::ERROR, "Invalid handle"); - return; - } - m_swapchainImages[id].m_layout = layout; - } - + void ImageManager::updateImageLayoutManual(const vkcv::ImageHandle& handle, + const vk::ImageLayout layout) { + auto& image = (*this)[handle]; + image.m_layout = layout; } } \ No newline at end of file diff --git a/src/vkcv/ImageManager.hpp b/src/vkcv/ImageManager.hpp index fca4f3b23944238f69da377090b2d3b34848b8af..bda9a6a0c7600c96dfdb257a4e0de382c0ca6d10 100644 --- a/src/vkcv/ImageManager.hpp +++ b/src/vkcv/ImageManager.hpp @@ -9,7 +9,7 @@ #include <vk_mem_alloc.hpp> #include "BufferManager.hpp" -#include "vkcv/Handles.hpp" +#include "HandleManager.hpp" #include "vkcv/ImageConfig.hpp" namespace vkcv { @@ -22,44 +22,44 @@ namespace vkcv { * @return True, if the format is usable for depth buffers, otherwise false. */ bool isDepthImageFormat(vk::Format format); + + struct ImageEntry { + vk::Image m_handle; + vma::Allocation m_allocation; + + std::vector<vk::ImageView> m_viewPerMip; + std::vector<vk::ImageView> m_arrayViewPerMip; + + uint32_t m_width; + uint32_t m_height; + uint32_t m_depth; + + vk::Format m_format; + uint32_t m_layers; + vk::ImageLayout m_layout; + bool m_storage; + }; /** * @brief Class to manage the creation, destruction, allocation * and filling of images. */ - class ImageManager + class ImageManager : HandleManager<ImageEntry, ImageHandle> { friend class Core; - public: - struct Image - { - vk::Image m_handle; - vma::Allocation m_allocation; - - std::vector<vk::ImageView> m_viewPerMip; - std::vector<vk::ImageView> m_arrayViewPerMip; - - uint32_t m_width; - uint32_t m_height; - uint32_t m_depth; - - vk::Format m_format; - uint32_t m_layers; - vk::ImageLayout m_layout; - bool m_storage; - private: - friend ImageManager; - }; private: + BufferManager* m_bufferManager; - Core* m_core; - BufferManager& m_bufferManager; - - std::vector<Image> m_images; - std::vector<Image> m_swapchainImages; + std::vector<ImageEntry> m_swapchainImages; int m_currentSwapchainInputImage; - explicit ImageManager(BufferManager& bufferManager) noexcept; + bool init(Core& core, BufferManager& bufferManager); + + [[nodiscard]] + uint64_t getIdFrom(const ImageHandle& handle) const override; + + [[nodiscard]] + ImageHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override; /** * Destroys and deallocates image represented by a given @@ -67,18 +67,29 @@ namespace vkcv { * * @param id Image handle id */ - void destroyImageById(uint64_t id); + void destroyById(uint64_t id) override; + + [[nodiscard]] + const BufferManager& getBufferManager() const; + + [[nodiscard]] + BufferManager& getBufferManager(); void recordImageMipGenerationToCmdBuffer(vk::CommandBuffer cmdBuffer, const ImageHandle& handle); - + + protected: + [[nodiscard]] + virtual const ImageEntry& operator[](const ImageHandle& handle) const override; + + [[nodiscard]] + virtual ImageEntry& operator[](const ImageHandle& handle) override; + public: - ~ImageManager() noexcept; - ImageManager(ImageManager&& other) = delete; - ImageManager(const ImageManager& other) = delete; - - ImageManager& operator=(ImageManager&& other) = delete; - ImageManager& operator=(const ImageManager& other) = delete; + ImageManager() noexcept; + + ~ImageManager() noexcept override; + [[nodiscard]] ImageHandle createImage( uint32_t width, uint32_t height, @@ -103,22 +114,28 @@ namespace vkcv { size_t mipLevel = 0, bool arrayView = false) const; - void switchImageLayoutImmediate(const ImageHandle& handle, vk::ImageLayout newLayout); - - void recordImageLayoutTransition( - const ImageHandle& handle, - uint32_t mipLevelCount, - uint32_t mipLevelOffset, - vk::ImageLayout newLayout, - vk::CommandBuffer cmdBuffer); + void switchImageLayoutImmediate(const ImageHandle& handle, + vk::ImageLayout newLayout); + + void recordImageLayoutTransition(const ImageHandle& handle, + uint32_t mipLevelCount, + uint32_t mipLevelOffset, + vk::ImageLayout newLayout, + vk::CommandBuffer cmdBuffer); - void recordImageMemoryBarrier( - const ImageHandle& handle, - vk::CommandBuffer cmdBuffer); + void recordImageMemoryBarrier(const ImageHandle& handle, + vk::CommandBuffer cmdBuffer); - void fillImage(const ImageHandle& handle, const void* data, size_t size); - void recordImageMipChainGenerationToCmdStream(const vkcv::CommandStreamHandle& cmdStream, const ImageHandle& handle); - void recordMSAAResolve(vk::CommandBuffer cmdBuffer, ImageHandle src, ImageHandle dst); + void fillImage(const ImageHandle& handle, + const void* data, + size_t size); + + void recordImageMipChainGenerationToCmdStream(const vkcv::CommandStreamHandle& cmdStream, + const ImageHandle& handle); + + void recordMSAAResolve(vk::CommandBuffer cmdBuffer, + const ImageHandle& src, + const ImageHandle& dst); [[nodiscard]] uint32_t getImageWidth(const ImageHandle& handle) const; @@ -143,12 +160,16 @@ namespace vkcv { void setCurrentSwapchainImageIndex(int index); - void setSwapchainImages(const std::vector<vk::Image>& images, const 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); // if manual vulkan work, e.g. ImGui integration, changes an image layout this function must be used // to update the internal image state - void updateImageLayoutManual(const vkcv::ImageHandle& handle, const vk::ImageLayout layout); + void updateImageLayoutManual(const vkcv::ImageHandle& handle, + const vk::ImageLayout layout); }; } \ No newline at end of file diff --git a/src/vkcv/PassManager.cpp b/src/vkcv/PassManager.cpp index 5eb727c75f9ec7e6f4cc3fa8fd8118a1a05f036f..20ba600c07a0638f7a72b7aaa97606121861d641 100644 --- a/src/vkcv/PassManager.cpp +++ b/src/vkcv/PassManager.cpp @@ -1,5 +1,6 @@ #include "PassManager.hpp" #include "vkcv/Image.hpp" +#include "vkcv/Core.hpp" namespace vkcv { @@ -27,21 +28,31 @@ namespace vkcv return vk::AttachmentLoadOp::eDontCare; } } - - PassManager::PassManager(vk::Device device) noexcept : - m_Device{device}, - m_Passes{} - {} - - PassManager::~PassManager() noexcept - { - for (uint64_t id = 0; id < m_Passes.size(); id++) { - destroyPassById(id); - } + + uint64_t PassManager::getIdFrom(const PassHandle &handle) const { + return handle.getId(); + } + + PassHandle PassManager::createById(uint64_t id, const HandleDestroyFunction &destroy) { + return PassHandle(id, destroy); + } + + void PassManager::destroyById(uint64_t id) { + auto& pass = getById(id); + + if (pass.m_Handle) { + getCore().getContext().getDevice().destroy(pass.m_Handle); + pass.m_Handle = nullptr; + } + } + + PassManager::PassManager() noexcept : HandleManager<PassEntry, PassHandle>() {} + + PassManager::~PassManager() noexcept { + clear(); } - PassHandle PassManager::createPass(const PassConfig &config) - { + PassHandle PassManager::createPass(const PassConfig &config) { // description of all {color, input, depth/stencil} attachments of the render pass std::vector<vk::AttachmentDescription> attachmentDescriptions{}; @@ -106,50 +117,19 @@ namespace vkcv 0, {}); - vk::RenderPass renderPass = m_Device.createRenderPass(passInfo); + vk::RenderPass renderPass = getCore().getContext().getDevice().createRenderPass(passInfo); - const uint64_t id = m_Passes.size(); - m_Passes.push_back({ renderPass, config }); - return PassHandle(id, [&](uint64_t id) { destroyPassById(id); }); + return add({ renderPass, config }); } - vk::RenderPass PassManager::getVkPass(const PassHandle &handle) const - { - const uint64_t id = handle.getId(); - - if (id >= m_Passes.size()) { - return nullptr; - } - - auto& pass = m_Passes[id]; - + vk::RenderPass PassManager::getVkPass(const PassHandle &handle) const { + auto& pass = (*this)[handle]; return pass.m_Handle; } const PassConfig& PassManager::getPassConfig(const PassHandle &handle) const { - const uint64_t id = handle.getId(); - - if (id >= m_Passes.size()) { - static PassConfig emptyConfig = PassConfig({}); - return emptyConfig; - } - - auto& pass = m_Passes[id]; - + auto& pass = (*this)[handle]; return pass.m_Config; } - void PassManager::destroyPassById(uint64_t id) { - if (id >= m_Passes.size()) { - return; - } - - auto& pass = m_Passes[id]; - - if (pass.m_Handle) { - m_Device.destroy(pass.m_Handle); - pass.m_Handle = nullptr; - } - } - } diff --git a/src/vkcv/PassManager.hpp b/src/vkcv/PassManager.hpp index 1ef976e0482ea39afad33346068f2a168eac70d8..3ab69b0c5de8ef5cee4297831d6df7aa405237cc 100644 --- a/src/vkcv/PassManager.hpp +++ b/src/vkcv/PassManager.hpp @@ -2,39 +2,44 @@ #include <vulkan/vulkan.hpp> #include <vector> -#include "vkcv/Handles.hpp" + +#include "HandleManager.hpp" #include "vkcv/PassConfig.hpp" namespace vkcv { + struct PassEntry { + vk::RenderPass m_Handle; + PassConfig m_Config; + }; + /** * @brief Class to manage the creation and destruction of passes. */ - class PassManager - { + class PassManager : public HandleManager<PassEntry, PassHandle> { + friend class Core; private: - struct Pass { - vk::RenderPass m_Handle; - PassConfig m_Config; - }; - - vk::Device m_Device; - std::vector<Pass> m_Passes; - - void destroyPassById(uint64_t id); + [[nodiscard]] + uint64_t getIdFrom(const PassHandle& handle) const override; + + [[nodiscard]] + PassHandle createById(uint64_t id, const HandleDestroyFunction& destroy) override; + + /** + * Destroys and deallocates pass represented by a given + * pass handle id. + * + * @param id Pass handle id + */ + void destroyById(uint64_t id) override; public: - PassManager() = delete; // no default ctor - explicit PassManager(vk::Device device) noexcept; // ctor - ~PassManager() noexcept; // dtor - - PassManager(const PassManager &other) = delete; // copy-ctor - PassManager(PassManager &&other) = delete; // move-ctor; - - PassManager & operator=(const PassManager &other) = delete; // copy-assign op - PassManager & operator=(PassManager &&other) = delete; // move-assign op - + PassManager() noexcept; + + ~PassManager() noexcept override; // dtor + + [[nodiscard]] PassHandle createPass(const PassConfig &config); [[nodiscard]]