From fc5b7930f426d173cd9a248c9bcd972d3be53ef9 Mon Sep 17 00:00:00 2001 From: Tobias Frisch <tfrisch@uni-koblenz.de> Date: Sat, 26 Nov 2022 22:53:05 +0100 Subject: [PATCH] Implement ray tracing pipeline inside of framework with own pipeline manager Signed-off-by: Tobias Frisch <tfrisch@uni-koblenz.de> --- config/Sources.cmake | 6 + include/vkcv/BufferTypes.hpp | 1 + include/vkcv/Context.hpp | 8 + include/vkcv/Core.hpp | 40 +- include/vkcv/GraphicsPipelineConfig.hpp | 3 +- include/vkcv/Handles.hpp | 10 + include/vkcv/RayTracingPipelineConfig.hpp | 31 ++ projects/rtx_ambient_occlusion/src/main.cpp | 23 +- src/vkcv/BufferManager.cpp | 4 + src/vkcv/Context.cpp | 32 +- src/vkcv/Core.cpp | 92 +++- src/vkcv/GraphicsPipelineConfig.cpp | 7 +- src/vkcv/GraphicsPipelineManager.cpp | 37 +- src/vkcv/GraphicsPipelineManager.hpp | 6 +- src/vkcv/RayTracingPipelineConfig.cpp | 14 + src/vkcv/RayTracingPipelineManager.cpp | 533 ++++++++++++++++++++ src/vkcv/RayTracingPipelineManager.hpp | 118 +++++ 17 files changed, 880 insertions(+), 85 deletions(-) create mode 100644 include/vkcv/RayTracingPipelineConfig.hpp create mode 100644 src/vkcv/RayTracingPipelineConfig.cpp create mode 100644 src/vkcv/RayTracingPipelineManager.cpp create mode 100644 src/vkcv/RayTracingPipelineManager.hpp diff --git a/config/Sources.cmake b/config/Sources.cmake index 1b3af31e..8c13596c 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -73,6 +73,9 @@ set(vkcv_sources ${vkcv_source}/vkcv/GraphicsPipelineManager.hpp ${vkcv_source}/vkcv/GraphicsPipelineManager.cpp + + ${vkcv_source}/vkcv/RayTracingPipelineManager.hpp + ${vkcv_source}/vkcv/RayTracingPipelineManager.cpp ${vkcv_include}/vkcv/QueueManager.hpp ${vkcv_source}/vkcv/QueueManager.cpp @@ -140,6 +143,9 @@ set(vkcv_sources ${vkcv_source}/vkcv/VertexData.cpp ${vkcv_include}/vkcv/Result.hpp + + ${vkcv_include}/vkcv/RayTracingPipelineConfig.hpp + ${vkcv_source}/vkcv/RayTracingPipelineConfig.cpp ) if (BUILD_CLANG_FORMAT) diff --git a/include/vkcv/BufferTypes.hpp b/include/vkcv/BufferTypes.hpp index 85bc0f2a..78f2d167 100644 --- a/include/vkcv/BufferTypes.hpp +++ b/include/vkcv/BufferTypes.hpp @@ -17,6 +17,7 @@ namespace vkcv { STORAGE, STAGING, INDIRECT, + SHADER_BINDING, UNKNOWN }; diff --git a/include/vkcv/Context.hpp b/include/vkcv/Context.hpp index 9146c591..ce56589d 100644 --- a/include/vkcv/Context.hpp +++ b/include/vkcv/Context.hpp @@ -58,6 +58,13 @@ namespace vkcv { * @return Vulkan device */ [[nodiscard]] const vk::Device &getDevice() const; + + /** + * @brief Returns a dynamic dispatch loader of the context. + * + * @return Dynamic dispatch loader + */ + [[nodiscard]] const vk::DispatchLoaderDynamic &getDispatchLoaderDynamic() const; /** * @brief Returns the feature manager of the context. @@ -113,6 +120,7 @@ namespace vkcv { vk::Instance m_Instance; vk::PhysicalDevice m_PhysicalDevice; vk::Device m_Device; + vk::DispatchLoaderDynamic m_DispatchDynamic; FeatureManager m_FeatureManager; QueueManager m_QueueManager; vma::Allocator m_Allocator; diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index 1cec2a71..ce5389f8 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -24,6 +24,7 @@ #include "ImageConfig.hpp" #include "PassConfig.hpp" #include "PushConstants.hpp" +#include "RayTracingPipelineConfig.hpp" #include "Result.hpp" #include "SamplerTypes.hpp" #include "Window.hpp" @@ -37,6 +38,7 @@ namespace vkcv { class PassManager; class GraphicsPipelineManager; class ComputePipelineManager; + class RayTracingPipelineManager; class DescriptorSetLayoutManager; class DescriptorSetManager; class BufferManager; @@ -71,6 +73,7 @@ namespace vkcv { std::unique_ptr<PassManager> m_PassManager; std::unique_ptr<GraphicsPipelineManager> m_GraphicsPipelineManager; std::unique_ptr<ComputePipelineManager> m_ComputePipelineManager; + std::unique_ptr<RayTracingPipelineManager> m_RayTracingPipelineManager; std::unique_ptr<DescriptorSetLayoutManager> m_DescriptorSetLayoutManager; std::unique_ptr<DescriptorSetManager> m_DescriptorSetManager; std::unique_ptr<BufferManager> m_BufferManager; @@ -180,6 +183,17 @@ namespace vkcv { */ [[nodiscard]] ComputePipelineHandle createComputePipeline(const ComputePipelineConfig &config); + + /** + * Creates a basic vulkan ray tracing pipeline using @p shader program and returns it using + * the @p handle. Fixed Functions for pipeline are set with standard values. + * + * @param config a pipeline config object from the pipeline config class + * layout + * @return True if pipeline creation was successful, False if not + */ + [[nodiscard]] RayTracingPipelineHandle + createRayTracingPipeline(const RayTracingPipelineConfig &config); /** * Creates a basic vulkan render pass using @p config from the render pass config class and @@ -553,29 +567,23 @@ namespace vkcv { const WindowHandle &windowHandle); /** - * Records the rtx ray generation to the @p cmdStreamHandle. - * Currently only supports @p closestHit, @p rayGen and @c miss shaderstages @c. + * Records the ray generation via ray tracing pipeline to the @p cmdStreamHandle. * * @param cmdStreamHandle The command stream handle which receives relevant commands for * drawing. - * @param rtxPipeline The raytracing pipeline from the RTXModule. - * @param rtxPipelineLayout The raytracing pipeline layout from the RTXModule. - * @param rgenRegion The shader binding table region for ray generation shaders. - * @param rmissRegion The shader binding table region for ray miss shaders. - * @param rchitRegion The shader binding table region for ray closest hit shaders. - * @param rcallRegion The shader binding table region for callable shaders. + * @param rayTracingPipeline The raytracing pipeline + * @param dispatchSize How many work groups are dispatched * @param descriptorSetUsages The descriptor set usages. * @param pushConstants The push constants. * @param windowHandle The window handle defining in which window to render. */ - void recordRayGenerationToCmdStream( - CommandStreamHandle cmdStreamHandle, vk::Pipeline rtxPipeline, - vk::PipelineLayout rtxPipelineLayout, vk::StridedDeviceAddressRegionKHR rgenRegion, - vk::StridedDeviceAddressRegionKHR rmissRegion, - vk::StridedDeviceAddressRegionKHR rchitRegion, - vk::StridedDeviceAddressRegionKHR rcallRegion, - const std::vector<DescriptorSetUsage> &descriptorSetUsages, - const PushConstants &pushConstants, const WindowHandle &windowHandle); + void recordRayGenerationToCmdStream(const CommandStreamHandle &cmdStreamHandle, + const RayTracingPipelineHandle &rayTracingPipeline, + const DispatchSize &dispatchSize, + const std::vector<DescriptorSetUsage> + &descriptorSetUsages, + const PushConstants &pushConstants, + const vkcv::WindowHandle &windowHandle); /** * @brief Record a compute shader dispatch into a command stream diff --git a/include/vkcv/GraphicsPipelineConfig.hpp b/include/vkcv/GraphicsPipelineConfig.hpp index 80084cb1..2d67501b 100644 --- a/include/vkcv/GraphicsPipelineConfig.hpp +++ b/include/vkcv/GraphicsPipelineConfig.hpp @@ -80,7 +80,8 @@ namespace vkcv { public: GraphicsPipelineConfig(); - GraphicsPipelineConfig(const ShaderProgram &program, const PassHandle &pass, + GraphicsPipelineConfig(const ShaderProgram &program, + const PassHandle &pass, const VertexLayout &vertexLayout, const std::vector<DescriptorSetLayoutHandle> &layouts); diff --git a/include/vkcv/Handles.hpp b/include/vkcv/Handles.hpp index 3e92ee15..c814bdea 100644 --- a/include/vkcv/Handles.hpp +++ b/include/vkcv/Handles.hpp @@ -130,6 +130,16 @@ namespace vkcv { private: using Handle::Handle; }; + + /** + * @brief Handle class for ray tracing pipelines. + */ + class RayTracingPipelineHandle : public Handle { + friend class RayTracingPipelineManager; + + private: + using Handle::Handle; + }; /** * @brief Handle class for descriptor set layouts. diff --git a/include/vkcv/RayTracingPipelineConfig.hpp b/include/vkcv/RayTracingPipelineConfig.hpp new file mode 100644 index 00000000..37ca1c4e --- /dev/null +++ b/include/vkcv/RayTracingPipelineConfig.hpp @@ -0,0 +1,31 @@ +#pragma once +/** + * @authors Tobias Frisch + * @file vkcv/RayTracingPipelineConfig.hpp + * @brief Ray tracing pipeline config struct to hand over required information to pipeline creation. + */ + +#include "PipelineConfig.hpp" + +namespace vkcv { + + /** + * @brief Class to configure a ray tracing pipeline before its creation. + */ + class RayTracingPipelineConfig : public PipelineConfig { + public: + RayTracingPipelineConfig(); + + RayTracingPipelineConfig(const ShaderProgram &program, + const std::vector<DescriptorSetLayoutHandle> &layouts); + + RayTracingPipelineConfig(const RayTracingPipelineConfig &other) = default; + RayTracingPipelineConfig(RayTracingPipelineConfig &&other) = default; + + ~RayTracingPipelineConfig() = default; + + RayTracingPipelineConfig &operator=(const RayTracingPipelineConfig &other) = default; + RayTracingPipelineConfig &operator=(RayTracingPipelineConfig &&other) = default; + }; + +} diff --git a/projects/rtx_ambient_occlusion/src/main.cpp b/projects/rtx_ambient_occlusion/src/main.cpp index 2a9d5d20..8845a7f2 100644 --- a/projects/rtx_ambient_occlusion/src/main.cpp +++ b/projects/rtx_ambient_occlusion/src/main.cpp @@ -80,15 +80,11 @@ int main(int argc, const char** argv) { glm::vec4 camera_up; // for computing ray direction glm::vec4 camera_forward; // for computing ray direction }; - - uint32_t pushConstantSize = sizeof(RaytracingPushConstantData); - - rtxModule.createRTXPipelineAndLayout(pushConstantSize, descriptorSetLayoutHandles, rtxShaderProgram); - - vk::Pipeline rtxPipeline = rtxModule.getPipeline(); - vk::PipelineLayout rtxPipelineLayout = rtxModule.getPipelineLayout(); - - vkcv::rtx::ShaderBindingTableRegions rtxRegions = rtxModule.createRegions(); + + auto rtxPipeline = core.createRayTracingPipeline(vkcv::RayTracingPipelineConfig( + rtxShaderProgram, + descriptorSetLayoutHandles + )); vkcv::ImageHandle depthBuffer; @@ -133,14 +129,11 @@ int main(int argc, const char** argv) { core.recordRayGenerationToCmdStream( cmdStream, rtxPipeline, - rtxPipelineLayout, - rtxRegions.rgenRegion, - rtxRegions.rmissRegion, - rtxRegions.rchitRegion, - rtxRegions.rcallRegion, + vkcv::DispatchSize(swapchainWidth, swapchainHeight), { vkcv::useDescriptorSet(0, rtxShaderDescriptorSet) }, pushConstantsRTX, - windowHandle); + windowHandle + ); core.prepareSwapchainImageForPresent(cmdStream); core.submitCommandStream(cmdStream); diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp index b443f8ca..0c605d66 100644 --- a/src/vkcv/BufferManager.cpp +++ b/src/vkcv/BufferManager.cpp @@ -129,6 +129,10 @@ namespace vkcv { usageFlags = vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndirectBuffer; break; + case BufferType::SHADER_BINDING: + usageFlags = vk::BufferUsageFlagBits::eShaderBindingTableKHR + | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR; + break; default: vkcv_log(LogLevel::WARNING, "Unknown buffer type"); break; diff --git a/src/vkcv/Context.cpp b/src/vkcv/Context.cpp index 1d92268e..43bf5de2 100644 --- a/src/vkcv/Context.cpp +++ b/src/vkcv/Context.cpp @@ -6,9 +6,13 @@ namespace vkcv { Context::Context(Context &&other) noexcept : - m_Instance(other.m_Instance), m_PhysicalDevice(other.m_PhysicalDevice), - m_Device(other.m_Device), m_FeatureManager(std::move(other.m_FeatureManager)), - m_QueueManager(std::move(other.m_QueueManager)), m_Allocator(other.m_Allocator) { + m_Instance(other.m_Instance), + m_PhysicalDevice(other.m_PhysicalDevice), + m_Device(other.m_Device), + m_DispatchDynamic(other.m_DispatchDynamic), + m_FeatureManager(std::move(other.m_FeatureManager)), + m_QueueManager(std::move(other.m_QueueManager)), + m_Allocator(other.m_Allocator) { other.m_Instance = nullptr; other.m_PhysicalDevice = nullptr; other.m_Device = nullptr; @@ -19,6 +23,7 @@ namespace vkcv { m_Instance = other.m_Instance; m_PhysicalDevice = other.m_PhysicalDevice; m_Device = other.m_Device; + m_DispatchDynamic = other.m_DispatchDynamic; m_FeatureManager = std::move(other.m_FeatureManager); m_QueueManager = std::move(other.m_QueueManager); m_Allocator = other.m_Allocator; @@ -35,9 +40,18 @@ namespace vkcv { FeatureManager &&featureManager, QueueManager &&queueManager, vma::Allocator &&allocator) noexcept : m_Instance(instance), - m_PhysicalDevice(physicalDevice), m_Device(device), - m_FeatureManager(std::move(featureManager)), m_QueueManager(std::move(queueManager)), - m_Allocator(allocator) {} + m_PhysicalDevice(physicalDevice), + m_Device(device), + m_DispatchDynamic(), + m_FeatureManager(std::move(featureManager)), + m_QueueManager(std::move(queueManager)), + m_Allocator(allocator) { + m_DispatchDynamic.init( + m_Instance, + (PFN_vkGetInstanceProcAddr) m_Instance.getProcAddr("vkGetInstanceProcAddr"), + m_Device + ); + } Context::~Context() noexcept { m_Allocator.destroy(); @@ -56,6 +70,10 @@ namespace vkcv { const vk::Device &Context::getDevice() const { return m_Device; } + + const vk::DispatchLoaderDynamic &Context::getDispatchLoaderDynamic() const { + return m_DispatchDynamic; + } const FeatureManager &Context::getFeatureManager() const { return m_FeatureManager; @@ -453,6 +471,8 @@ namespace vkcv { vmaFlags |= vma::AllocatorCreateFlagBits::eAmdDeviceCoherentMemory; } + vmaFlags |= vma::AllocatorCreateFlagBits::eBufferDeviceAddress; + const vma::AllocatorCreateInfo allocatorCreateInfo( vmaFlags, physicalDevice, diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 7fde9196..9b4639f9 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -15,6 +15,7 @@ #include "GraphicsPipelineManager.hpp" #include "ImageManager.hpp" #include "PassManager.hpp" +#include "RayTracingPipelineManager.hpp" #include "SamplerManager.hpp" #include "WindowManager.hpp" #include "vkcv/BlitDownsampler.hpp" @@ -90,6 +91,7 @@ namespace vkcv { m_Context(std::move(context)), m_PassManager(std::make_unique<PassManager>()), m_GraphicsPipelineManager(std::make_unique<GraphicsPipelineManager>()), m_ComputePipelineManager(std::make_unique<ComputePipelineManager>()), + m_RayTracingPipelineManager(std::make_unique<RayTracingPipelineManager>()), m_DescriptorSetLayoutManager(std::make_unique<DescriptorSetLayoutManager>()), m_DescriptorSetManager(std::make_unique<DescriptorSetManager>()), m_BufferManager(std::make_unique<BufferManager>()), @@ -108,6 +110,7 @@ namespace vkcv { m_PassManager->init(*this); m_GraphicsPipelineManager->init(*this); m_ComputePipelineManager->init(*this); + m_RayTracingPipelineManager->init(*this); m_DescriptorSetLayoutManager->init(*this); m_DescriptorSetManager->init(*this, *m_DescriptorSetLayoutManager); m_BufferManager->init(*this); @@ -146,6 +149,13 @@ namespace vkcv { return m_ComputePipelineManager->createComputePipeline(config.getShaderProgram(), layouts); } + + RayTracingPipelineHandle Core::createRayTracingPipeline( + const vkcv::RayTracingPipelineConfig &config) { + return m_RayTracingPipelineManager->createPipeline(config, + *m_DescriptorSetLayoutManager, + *m_BufferManager); + } PassHandle Core::createPass(const PassConfig &config) { return m_PassManager->createPass(config); @@ -624,46 +634,80 @@ namespace vkcv { } void Core::recordRayGenerationToCmdStream( - CommandStreamHandle cmdStreamHandle, vk::Pipeline rtxPipeline, - vk::PipelineLayout rtxPipelineLayout, vk::StridedDeviceAddressRegionKHR rgenRegion, - vk::StridedDeviceAddressRegionKHR rmissRegion, - vk::StridedDeviceAddressRegionKHR rchitRegion, - vk::StridedDeviceAddressRegionKHR rcallRegion, + const CommandStreamHandle &cmdStreamHandle, + const RayTracingPipelineHandle &rayTracingPipeline, + const DispatchSize &dispatchSize, const std::vector<DescriptorSetUsage> &descriptorSetUsages, - const PushConstants &pushConstants, const WindowHandle &windowHandle) { + const PushConstants &pushConstants, + const vkcv::WindowHandle &windowHandle) { + + const SwapchainHandle swapchainHandle = getWindow(windowHandle).getSwapchain(); + + const vk::Pipeline pipeline = m_RayTracingPipelineManager->getVkPipeline( + rayTracingPipeline + ); + + const vk::PipelineLayout pipelineLayout = m_RayTracingPipelineManager->getVkPipelineLayout( + rayTracingPipeline + ); + + const vk::StridedDeviceAddressRegionKHR *rayGenAddress = ( + m_RayTracingPipelineManager->getRayGenShaderBindingTableAddress(rayTracingPipeline) + ); + + const vk::StridedDeviceAddressRegionKHR *rayMissAddress = ( + m_RayTracingPipelineManager->getMissShaderBindingTableAddress(rayTracingPipeline) + ); + + const vk::StridedDeviceAddressRegionKHR *rayHitAddress = ( + m_RayTracingPipelineManager->getHitShaderBindingTableAddress(rayTracingPipeline) + ); + + const vk::StridedDeviceAddressRegionKHR *rayCallAddress = ( + m_RayTracingPipelineManager->getCallShaderBindingTableAddress(rayTracingPipeline) + ); auto submitFunction = [&](const vk::CommandBuffer &cmdBuffer) { - cmdBuffer.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, rtxPipeline); + cmdBuffer.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, pipeline); + for (const auto &usage : descriptorSetUsages) { cmdBuffer.bindDescriptorSets( - vk::PipelineBindPoint::eRayTracingKHR, rtxPipelineLayout, usage.location, + vk::PipelineBindPoint::eRayTracingKHR, + pipelineLayout, + usage.location, { m_DescriptorSetManager->getDescriptorSet(usage.descriptorSet).vulkanHandle }, - usage.dynamicOffsets); + usage.dynamicOffsets + ); } if (pushConstants.getSizePerDrawcall() > 0) { cmdBuffer.pushConstants( - rtxPipelineLayout, - (vk::ShaderStageFlagBits::eClosestHitKHR | vk::ShaderStageFlagBits::eMissKHR - | vk::ShaderStageFlagBits::eRaygenKHR), // TODO: add Support for eAnyHitKHR, - // eCallableKHR, eIntersectionKHR - 0, pushConstants.getSizePerDrawcall(), pushConstants.getData()); + pipelineLayout, + vk::ShaderStageFlagBits::eAll, + 0, + pushConstants.getSizePerDrawcall(), + pushConstants.getData() + ); } - - auto m_rtxDispatcher = vk::DispatchLoaderDynamic( - (PFN_vkGetInstanceProcAddr)m_Context.getInstance().getProcAddr( - "vkGetInstanceProcAddr")); - m_rtxDispatcher.init(m_Context.getInstance()); - - cmdBuffer.traceRaysKHR(&rgenRegion, &rmissRegion, &rchitRegion, &rcallRegion, - getWindow(windowHandle).getWidth(), - getWindow(windowHandle).getHeight(), 1, m_rtxDispatcher); + + cmdBuffer.traceRaysKHR( + rayGenAddress, + rayMissAddress, + rayHitAddress, + rayCallAddress, + dispatchSize.x(), + dispatchSize.y(), + dispatchSize.z(), + m_Context.getDispatchLoaderDynamic() + ); }; + recordCommandsToStream(cmdStreamHandle, submitFunction, nullptr); } void Core::recordComputeDispatchToCmdStream( - const CommandStreamHandle &cmdStreamHandle, const ComputePipelineHandle &computePipeline, + const CommandStreamHandle &cmdStreamHandle, + const ComputePipelineHandle &computePipeline, const DispatchSize &dispatchSize, const std::vector<DescriptorSetUsage> &descriptorSetUsages, const PushConstants &pushConstants) { diff --git a/src/vkcv/GraphicsPipelineConfig.cpp b/src/vkcv/GraphicsPipelineConfig.cpp index 987cd3a7..383c0de1 100644 --- a/src/vkcv/GraphicsPipelineConfig.cpp +++ b/src/vkcv/GraphicsPipelineConfig.cpp @@ -9,10 +9,13 @@ namespace vkcv { m_Height(std::numeric_limits<uint32_t>::max()) {} GraphicsPipelineConfig::GraphicsPipelineConfig( - const ShaderProgram &program, const PassHandle &pass, const VertexLayout &vertexLayout, + const ShaderProgram &program, + const PassHandle &pass, + const VertexLayout &vertexLayout, const std::vector<DescriptorSetLayoutHandle> &layouts) : PipelineConfig(program, layouts), - m_PassHandle(pass), m_VertexLayout(vertexLayout), + m_PassHandle(pass), + m_VertexLayout(vertexLayout), m_Width(std::numeric_limits<uint32_t>::max()), m_Height(std::numeric_limits<uint32_t>::max()) {} diff --git a/src/vkcv/GraphicsPipelineManager.cpp b/src/vkcv/GraphicsPipelineManager.cpp index 9e1af7f7..4ac862e4 100644 --- a/src/vkcv/GraphicsPipelineManager.cpp +++ b/src/vkcv/GraphicsPipelineManager.cpp @@ -100,7 +100,7 @@ namespace vkcv { } } - vk::ShaderStageFlagBits shaderStageToVkShaderStage(ShaderStage stage) { + static vk::ShaderStageFlagBits shaderStageToVkShaderStage(ShaderStage stage) { switch (stage) { case ShaderStage::VERTEX: return vk::ShaderStageFlagBits::eVertex; @@ -123,10 +123,12 @@ namespace vkcv { return vk::ShaderStageFlagBits::eAll; } } - - bool createPipelineShaderStageCreateInfo(const ShaderProgram &shaderProgram, ShaderStage stage, - vk::Device device, - vk::PipelineShaderStageCreateInfo* outCreateInfo) { + + static bool createPipelineShaderStageCreateInfo( + const ShaderProgram &shaderProgram, + ShaderStage stage, + vk::Device device, + vk::PipelineShaderStageCreateInfo* outCreateInfo) { assert(outCreateInfo); std::vector<uint32_t> code = shaderProgram.getShaderBinary(stage); @@ -152,7 +154,7 @@ namespace vkcv { * @param existsVertexShader * @param config */ - void fillVertexInputDescription( + static void fillVertexInputDescription( std::vector<vk::VertexInputAttributeDescription> &vertexAttributeDescriptions, std::vector<vk::VertexInputBindingDescription> &vertexBindingDescriptions, const bool existsVertexShader, const GraphicsPipelineConfig &config) { @@ -186,7 +188,7 @@ namespace vkcv { * @param vertexBindingDescriptions * @return Pipeline Vertex Input State Create Info Struct */ - vk::PipelineVertexInputStateCreateInfo createPipelineVertexInputStateCreateInfo( + static vk::PipelineVertexInputStateCreateInfo createPipelineVertexInputStateCreateInfo( std::vector<vk::VertexInputAttributeDescription> &vertexAttributeDescriptions, std::vector<vk::VertexInputBindingDescription> &vertexBindingDescriptions) { @@ -201,15 +203,15 @@ namespace vkcv { * @param config provides data for primitive topology. * @return Pipeline Input Assembly State Create Info Struct */ - vk::PipelineInputAssemblyStateCreateInfo + static vk::PipelineInputAssemblyStateCreateInfo createPipelineInputAssemblyStateCreateInfo(const GraphicsPipelineConfig &config) { vk::PipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo( {}, primitiveTopologyToVulkanPrimitiveTopology(config.getPrimitiveTopology()), false); return pipelineInputAssemblyStateCreateInfo; } - - vk::PipelineTessellationStateCreateInfo + + static vk::PipelineTessellationStateCreateInfo createPipelineTessellationStateCreateInfo(const GraphicsPipelineConfig &config) { vk::PipelineTessellationStateCreateInfo pipelineTessellationStateCreateInfo( {}, config.getTesselationControlPoints()); @@ -223,7 +225,7 @@ namespace vkcv { * @param config provides with and height of the output window * @return Pipeline Viewport State Create Info Struct */ - vk::PipelineViewportStateCreateInfo + static vk::PipelineViewportStateCreateInfo createPipelineViewportStateCreateInfo(const GraphicsPipelineConfig &config) { static vk::Viewport viewport; static vk::Rect2D scissor; @@ -250,7 +252,7 @@ namespace vkcv { * @param config sets Depth Clamping and Culling Mode * @return Pipeline Rasterization State Create Info Struct */ - vk::PipelineRasterizationStateCreateInfo createPipelineRasterizationStateCreateInfo( + static vk::PipelineRasterizationStateCreateInfo createPipelineRasterizationStateCreateInfo( const GraphicsPipelineConfig &config, const vk::PhysicalDeviceConservativeRasterizationPropertiesEXT &conservativeRasterProperties) { @@ -300,7 +302,7 @@ namespace vkcv { * @param config set MSAA Sample Count Flag * @return Pipeline Multisample State Create Info Struct */ - vk::PipelineMultisampleStateCreateInfo + static vk::PipelineMultisampleStateCreateInfo createPipelineMultisampleStateCreateInfo(const GraphicsPipelineConfig &config, const PassConfig &passConfig) { vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo( @@ -316,7 +318,7 @@ namespace vkcv { * @param config sets blend mode * @return */ - vk::PipelineColorBlendStateCreateInfo + static vk::PipelineColorBlendStateCreateInfo createPipelineColorBlendStateCreateInfo(const GraphicsPipelineConfig &config, const PassConfig &passConfig) { static std::vector<vk::PipelineColorBlendAttachmentState> colorBlendAttachmentStates; @@ -368,7 +370,7 @@ namespace vkcv { * @param config sets Push Constant Size and Descriptor Layouts. * @return Pipeline Layout Create Info Struct */ - vk::PipelineLayoutCreateInfo createPipelineLayoutCreateInfo( + static vk::PipelineLayoutCreateInfo createPipelineLayoutCreateInfo( const GraphicsPipelineConfig &config, const std::vector<vk::DescriptorSetLayout> &descriptorSetLayouts) { static vk::PushConstantRange pushConstantRange; @@ -392,7 +394,7 @@ namespace vkcv { * @param config sets if depth test in enabled or not. * @return Pipeline Layout Create Info Struct */ - vk::PipelineDepthStencilStateCreateInfo + static vk::PipelineDepthStencilStateCreateInfo createPipelineDepthStencilStateCreateInfo(const GraphicsPipelineConfig &config) { const vk::PipelineDepthStencilStateCreateInfo pipelineDepthStencilCreateInfo( vk::PipelineDepthStencilStateCreateFlags(), config.getDepthTest() != DepthTest::None, @@ -407,7 +409,7 @@ namespace vkcv { * @param config sets whenever a dynamic viewport is used or not. * @return Pipeline Dynamic State Create Info Struct */ - vk::PipelineDynamicStateCreateInfo + static vk::PipelineDynamicStateCreateInfo createPipelineDynamicStateCreateInfo(const GraphicsPipelineConfig &config) { static std::vector<vk::DynamicState> dynamicStates; dynamicStates.clear(); @@ -651,6 +653,7 @@ namespace vkcv { != vk::Result::eSuccess) { // Catch runtime error if the creation of the pipeline fails. // Destroy everything to keep the memory clean. + getCore().getContext().getDevice().destroy(vkPipelineLayout); destroyShaderModules(); return {}; } diff --git a/src/vkcv/GraphicsPipelineManager.hpp b/src/vkcv/GraphicsPipelineManager.hpp index 602e1a96..867bd46f 100644 --- a/src/vkcv/GraphicsPipelineManager.hpp +++ b/src/vkcv/GraphicsPipelineManager.hpp @@ -2,11 +2,9 @@ /** * @authors Mark Mints - * @file src/vkcv/PipelineManager.hpp - * @brief Creation and handling of Graphic Pipelines + * @file src/vkcv/GraphicsPipelineManager.hpp + * @brief Creation and handling of graphic pipelines */ -// TODO: Edit @brief: add graphics pipeline, but only then when the compute part is in an own class. -// TODO: More authors? Do we need authors (general question)? #include "DescriptorSetLayoutManager.hpp" #include "HandleManager.hpp" diff --git a/src/vkcv/RayTracingPipelineConfig.cpp b/src/vkcv/RayTracingPipelineConfig.cpp new file mode 100644 index 00000000..cec0bdec --- /dev/null +++ b/src/vkcv/RayTracingPipelineConfig.cpp @@ -0,0 +1,14 @@ + +#include "vkcv/RayTracingPipelineConfig.hpp" + +namespace vkcv { + + RayTracingPipelineConfig::RayTracingPipelineConfig() : + PipelineConfig() {} + + RayTracingPipelineConfig::RayTracingPipelineConfig( + const ShaderProgram &program, + const std::vector<DescriptorSetLayoutHandle> &layouts) : + PipelineConfig(program, layouts) {} + +} diff --git a/src/vkcv/RayTracingPipelineManager.cpp b/src/vkcv/RayTracingPipelineManager.cpp new file mode 100644 index 00000000..010d234a --- /dev/null +++ b/src/vkcv/RayTracingPipelineManager.cpp @@ -0,0 +1,533 @@ + +#include "RayTracingPipelineManager.hpp" + +#include "vkcv/Core.hpp" +#include "vkcv/Logger.hpp" + +namespace vkcv { + + uint64_t RayTracingPipelineManager::getIdFrom(const RayTracingPipelineHandle &handle) const { + return handle.getId(); + } + + RayTracingPipelineHandle RayTracingPipelineManager::createById(uint64_t id, const HandleDestroyFunction &destroy) { + return RayTracingPipelineHandle(id, destroy); + } + + void RayTracingPipelineManager::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; + } + } + + RayTracingPipelineManager::RayTracingPipelineManager() noexcept : + HandleManager<RayTracingPipelineEntry, RayTracingPipelineHandle>() {} + + RayTracingPipelineManager::~RayTracingPipelineManager() noexcept { + clear(); + } + + static vk::ShaderStageFlagBits shaderStageToVkShaderStage(ShaderStage stage) { + switch (stage) { + case ShaderStage::RAY_GEN: + return vk::ShaderStageFlagBits::eRaygenKHR; + case ShaderStage::RAY_ANY_HIT: + return vk::ShaderStageFlagBits::eAnyHitKHR; + case ShaderStage::RAY_CLOSEST_HIT: + return vk::ShaderStageFlagBits::eClosestHitKHR; + case ShaderStage::RAY_MISS: + return vk::ShaderStageFlagBits::eMissKHR; + case ShaderStage::RAY_INTERSECTION: + return vk::ShaderStageFlagBits::eIntersectionKHR; + case ShaderStage::RAY_CALLABLE: + return vk::ShaderStageFlagBits::eCallableKHR; + default: + vkcv_log(LogLevel::ERROR, "Unknown shader stage"); + return vk::ShaderStageFlagBits::eAll; + } + } + + static bool createPipelineShaderStageCreateInfo( + const ShaderProgram &shaderProgram, + ShaderStage stage, + vk::Device device, + vk::PipelineShaderStageCreateInfo* outCreateInfo) { + + assert(outCreateInfo); + std::vector<uint32_t> code = shaderProgram.getShaderBinary(stage); + vk::ShaderModuleCreateInfo vertexModuleInfo( + {}, + code.size() * sizeof(uint32_t), + code.data() + ); + + vk::ShaderModule shaderModule; + if (device.createShaderModule(&vertexModuleInfo, nullptr, &shaderModule) + != vk::Result::eSuccess) + return false; + + const static auto entryName = "main"; + + *outCreateInfo = vk::PipelineShaderStageCreateInfo( + {}, + shaderStageToVkShaderStage(stage), + shaderModule, + entryName, + nullptr + ); + + return true; + } + + /** + * Creates a Pipeline Layout Create Info Struct. + * @param config sets Push Constant Size and Descriptor Layouts. + * @return Pipeline Layout Create Info Struct + */ + static vk::PipelineLayoutCreateInfo createPipelineLayoutCreateInfo( + const RayTracingPipelineConfig &config, + const std::vector<vk::DescriptorSetLayout> &descriptorSetLayouts) { + static vk::PushConstantRange pushConstantRange; + + const size_t pushConstantsSize = config.getShaderProgram().getPushConstantsSize(); + pushConstantRange =vk::PushConstantRange( + vk::ShaderStageFlagBits::eAll, + 0, + pushConstantsSize + ); + + vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo({}, (descriptorSetLayouts), + (pushConstantRange)); + + if (pushConstantsSize == 0) { + pipelineLayoutCreateInfo.pushConstantRangeCount = 0; + } + + return pipelineLayoutCreateInfo; + } + + RayTracingPipelineHandle + RayTracingPipelineManager::createPipeline(const RayTracingPipelineConfig &config, + const DescriptorSetLayoutManager &descriptorManager, + BufferManager &bufferManager) { + const auto &program = config.getShaderProgram(); + + const auto &dynamicDispatch = getCore().getContext().getDispatchLoaderDynamic(); + + const bool existsRayGenShader = program.existsShader(ShaderStage::RAY_GEN); + const bool existsRayAnyHitShader = program.existsShader(ShaderStage::RAY_ANY_HIT); + const bool existsRayClosestHitShader = program.existsShader(ShaderStage::RAY_CLOSEST_HIT); + const bool existsRayMissShader = program.existsShader(ShaderStage::RAY_MISS); + const bool existsRayIntersectionShader = program.existsShader(ShaderStage::RAY_INTERSECTION); + const bool existsRayCallableShader = program.existsShader(ShaderStage::RAY_CALLABLE); + + if (!existsRayGenShader) { + vkcv_log(LogLevel::ERROR, "Requires ray generation shader code"); + return {}; + } + + uint32_t anyHitStageIndex = VK_SHADER_UNUSED_KHR; + uint32_t closestHitStageIndex = VK_SHADER_UNUSED_KHR; + uint32_t intersectionStageIndex = VK_SHADER_UNUSED_KHR; + + std::vector<vk::PipelineShaderStageCreateInfo> shaderStages; + shaderStages.reserve( + (existsRayGenShader? 1 : 0) + + (existsRayAnyHitShader? 1 : 0) + + (existsRayClosestHitShader? 1 : 0) + + (existsRayMissShader? 1 : 0) + + (existsRayIntersectionShader? 1 : 0) + + (existsRayCallableShader? 1 : 0) + ); + + auto destroyShaderModules = [&shaderStages, this] { + for (auto stage : shaderStages) { + getCore().getContext().getDevice().destroyShaderModule(stage.module); + } + shaderStages.clear(); + }; + + std::vector<vk::RayTracingShaderGroupCreateInfoKHR> shaderGroups; + shaderGroups.reserve( + (existsRayGenShader? 1 : 0) + + (existsRayMissShader? 1 : 0) + + (existsRayCallableShader? 1 : 0) + + (existsRayAnyHitShader + || existsRayClosestHitShader + || existsRayIntersectionShader? 1 : 0) + ); + + auto addGeneralShaderGroup = [&shaderGroups](size_t index) { + shaderGroups.emplace_back( + vk::RayTracingShaderGroupTypeKHR::eGeneral, + static_cast<uint32_t>(index), + VK_SHADER_UNUSED_KHR, + VK_SHADER_UNUSED_KHR, + VK_SHADER_UNUSED_KHR, + nullptr + ); + }; + + size_t genShaderGroupIndex = shaderGroups.capacity(); + size_t missShaderGroupIndex = genShaderGroupIndex; + size_t hitShaderGroupIndex = genShaderGroupIndex; + size_t callShaderGroupIndex = genShaderGroupIndex; + + if (existsRayGenShader) { + vk::PipelineShaderStageCreateInfo createInfo; + const bool success = createPipelineShaderStageCreateInfo( + program, + ShaderStage::RAY_GEN, + getCore().getContext().getDevice(), + &createInfo + ); + + if (success) { + genShaderGroupIndex = shaderGroups.size(); + addGeneralShaderGroup(shaderStages.size()); + shaderStages.push_back(createInfo); + } else { + destroyShaderModules(); + return {}; + } + } + + if (existsRayAnyHitShader) { + vk::PipelineShaderStageCreateInfo createInfo; + const bool success = createPipelineShaderStageCreateInfo( + program, + ShaderStage::RAY_ANY_HIT, + getCore().getContext().getDevice(), + &createInfo + ); + + if (success) { + anyHitStageIndex = static_cast<uint32_t>(shaderStages.size()); + shaderStages.push_back(createInfo); + } else { + destroyShaderModules(); + return {}; + } + } + + if (existsRayClosestHitShader) { + vk::PipelineShaderStageCreateInfo createInfo; + const bool success = createPipelineShaderStageCreateInfo( + program, + ShaderStage::RAY_CLOSEST_HIT, + getCore().getContext().getDevice(), + &createInfo + ); + + if (success) { + closestHitStageIndex = static_cast<uint32_t>(shaderStages.size()); + shaderStages.push_back(createInfo); + } else { + destroyShaderModules(); + return {}; + } + } + + if (existsRayMissShader) { + vk::PipelineShaderStageCreateInfo createInfo; + const bool success = createPipelineShaderStageCreateInfo( + program, + ShaderStage::RAY_MISS, + getCore().getContext().getDevice(), + &createInfo + ); + + if (success) { + missShaderGroupIndex = shaderGroups.size(); + addGeneralShaderGroup(shaderStages.size()); + shaderStages.push_back(createInfo); + } else { + destroyShaderModules(); + return {}; + } + } + + if (existsRayIntersectionShader) { + vk::PipelineShaderStageCreateInfo createInfo; + const bool success = createPipelineShaderStageCreateInfo( + program, + ShaderStage::RAY_INTERSECTION, + getCore().getContext().getDevice(), + &createInfo + ); + + if (success) { + intersectionStageIndex = static_cast<uint32_t>(shaderStages.size()); + shaderStages.push_back(createInfo); + } else { + destroyShaderModules(); + return {}; + } + } + + if (existsRayCallableShader) { + vk::PipelineShaderStageCreateInfo createInfo; + const bool success = createPipelineShaderStageCreateInfo( + program, + ShaderStage::RAY_CALLABLE, + getCore().getContext().getDevice(), + &createInfo + ); + + if (success) { + callShaderGroupIndex = shaderGroups.size(); + addGeneralShaderGroup(shaderStages.size()); + shaderStages.push_back(createInfo); + } else { + destroyShaderModules(); + return {}; + } + } + + if ((closestHitStageIndex != VK_SHADER_UNUSED_KHR) || + (anyHitStageIndex != VK_SHADER_UNUSED_KHR) || + (intersectionStageIndex != VK_SHADER_UNUSED_KHR)) { + hitShaderGroupIndex = shaderGroups.size(); + shaderGroups.emplace_back( + intersectionStageIndex != VK_SHADER_UNUSED_KHR? + vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup : + vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, + VK_SHADER_UNUSED_KHR, + closestHitStageIndex, + anyHitStageIndex, + intersectionStageIndex, + nullptr + ); + } + + std::vector<vk::DescriptorSetLayout> descriptorSetLayouts; + descriptorSetLayouts.reserve(config.getDescriptorSetLayouts().size()); + for (const auto &handle : config.getDescriptorSetLayouts()) { + descriptorSetLayouts.push_back( + descriptorManager.getDescriptorSetLayout(handle).vulkanHandle); + } + + vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = createPipelineLayoutCreateInfo( + config, + descriptorSetLayouts + ); + + vk::PipelineLayout pipelineLayout {}; + if (getCore().getContext().getDevice().createPipelineLayout(&pipelineLayoutCreateInfo, + nullptr, &pipelineLayout) + != vk::Result::eSuccess) { + destroyShaderModules(); + return {}; + } + + vk::PhysicalDeviceRayTracingPipelinePropertiesKHR rayTracingPipelineProperties; + + vk::PhysicalDeviceProperties2 physicalProperties2; + physicalProperties2.pNext = &rayTracingPipelineProperties; + + getCore().getContext().getPhysicalDevice().getProperties2(&physicalProperties2); + + vk::RayTracingPipelineCreateInfoKHR pipelineCreateInfo ( + vk::PipelineCreateFlags(), + static_cast<uint32_t>(shaderStages.size()), + shaderStages.data(), + static_cast<uint32_t>(shaderGroups.size()), + shaderGroups.data(), + rayTracingPipelineProperties.maxRayRecursionDepth, + nullptr, + nullptr, + nullptr, + pipelineLayout + ); + + const auto pipelineCreation = getCore().getContext().getDevice().createRayTracingPipelineKHR( + vk::DeferredOperationKHR(), + vk::PipelineCache(), + pipelineCreateInfo, + nullptr, + dynamicDispatch + ); + + // Clean Up + destroyShaderModules(); + + if (pipelineCreation.result != vk::Result::eSuccess) { + getCore().getContext().getDevice().destroy(pipelineLayout); + return {}; + } + + auto pipeline = pipelineCreation.value; + + const size_t shaderGroupHandlesSize = ( + rayTracingPipelineProperties.shaderGroupHandleSize * shaderGroups.size() + ); + + std::vector<uint8_t> shaderGroupHandleEntries; + shaderGroupHandleEntries.resize(shaderGroupHandlesSize); + + if (getCore().getContext().getDevice().getRayTracingShaderGroupHandlesKHR( + pipeline, + 0, + static_cast<uint32_t>(shaderGroups.size()), + static_cast<uint32_t>(shaderGroupHandlesSize), + shaderGroupHandleEntries.data(), + dynamicDispatch) != vk::Result::eSuccess) { + vkcv_log(LogLevel::ERROR, "Could not retrieve shader binding table group handles."); + + getCore().getContext().getDevice().destroy(pipeline); + getCore().getContext().getDevice().destroy(pipelineLayout); + return {}; + } + + const size_t tableSizeAlignment = std::max( + rayTracingPipelineProperties.shaderGroupBaseAlignment, + rayTracingPipelineProperties.shaderGroupHandleSize + ); + + const size_t shaderBindingTableSize = ( + tableSizeAlignment * shaderGroups.size() + ); + + const BufferHandle &shaderBindingTable = getCore().createBuffer( + BufferType::SHADER_BINDING, + shaderBindingTableSize + ); + + void* mappedBindingTable = bufferManager.mapBuffer( + shaderBindingTable, + 0, + shaderBindingTableSize + ); + + for (size_t i = 0; i < shaderGroups.size(); i++) { + memcpy( + reinterpret_cast<uint8_t*>(mappedBindingTable) + + i * tableSizeAlignment, + shaderGroupHandleEntries.data() + + i * rayTracingPipelineProperties.shaderGroupHandleSize, + rayTracingPipelineProperties.shaderGroupHandleSize + ); + } + + if (mappedBindingTable == nullptr) { + getCore().getContext().getDevice().destroy(pipeline); + getCore().getContext().getDevice().destroy(pipelineLayout); + return {}; + } + + bufferManager.unmapBuffer(shaderBindingTable); + + const vk::BufferDeviceAddressInfoKHR shaderBindingTableAddressInfo ( + bufferManager.getBuffer(shaderBindingTable) + ); + + const vk::DeviceAddress bufferBaseAddress = ( + getCore().getContext().getDevice().getBufferAddressKHR( + shaderBindingTableAddressInfo, + dynamicDispatch + ) + ); + + vk::StridedDeviceAddressRegionKHR rayGenAddress {}; + vk::StridedDeviceAddressRegionKHR rayMissAddress {}; + vk::StridedDeviceAddressRegionKHR rayHitAddress {}; + vk::StridedDeviceAddressRegionKHR rayCallAddress {}; + + if (genShaderGroupIndex < shaderGroups.size()) { + rayGenAddress = vk::StridedDeviceAddressRegionKHR( + bufferBaseAddress + genShaderGroupIndex * tableSizeAlignment, + shaderBindingTableSize, + shaderBindingTableSize + ); + } + + if (missShaderGroupIndex < shaderGroups.size()) { + rayMissAddress = vk::StridedDeviceAddressRegionKHR( + bufferBaseAddress + missShaderGroupIndex * tableSizeAlignment, + shaderBindingTableSize, + shaderBindingTableSize + ); + } + + if (hitShaderGroupIndex < shaderGroups.size()) { + rayHitAddress = vk::StridedDeviceAddressRegionKHR( + bufferBaseAddress + hitShaderGroupIndex * tableSizeAlignment, + shaderBindingTableSize, + shaderBindingTableSize + ); + } + + if (callShaderGroupIndex < shaderGroups.size()) { + rayCallAddress = vk::StridedDeviceAddressRegionKHR( + bufferBaseAddress + callShaderGroupIndex * tableSizeAlignment, + shaderBindingTableSize, + shaderBindingTableSize + ); + } + + return add({ + pipeline, + pipelineLayout, + config, + shaderBindingTable, + rayGenAddress, + rayMissAddress, + rayHitAddress, + rayCallAddress + }); + } + + vk::Pipeline RayTracingPipelineManager::getVkPipeline(const RayTracingPipelineHandle &handle) const { + auto &pipeline = (*this) [handle]; + return pipeline.m_handle; + } + + vk::PipelineLayout RayTracingPipelineManager::getVkPipelineLayout( + const RayTracingPipelineHandle &handle) const { + auto &pipeline = (*this) [handle]; + return pipeline.m_layout; + } + + const RayTracingPipelineConfig & + RayTracingPipelineManager::getPipelineConfig(const RayTracingPipelineHandle &handle) const { + auto &pipeline = (*this) [handle]; + return pipeline.m_config; + } + + const vk::StridedDeviceAddressRegionKHR * + RayTracingPipelineManager::getRayGenShaderBindingTableAddress( + const vkcv::RayTracingPipelineHandle &handle) const { + auto &pipeline = (*this) [handle]; + return &(pipeline.m_rayGenAddress); + } + + const vk::StridedDeviceAddressRegionKHR * + RayTracingPipelineManager::getMissShaderBindingTableAddress( + const vkcv::RayTracingPipelineHandle &handle) const { + auto &pipeline = (*this) [handle]; + return &(pipeline.m_rayMissAddress); + } + + const vk::StridedDeviceAddressRegionKHR * + RayTracingPipelineManager::getHitShaderBindingTableAddress( + const vkcv::RayTracingPipelineHandle &handle) const { + auto &pipeline = (*this) [handle]; + return &(pipeline.m_rayHitAddress); + } + + const vk::StridedDeviceAddressRegionKHR * + RayTracingPipelineManager::getCallShaderBindingTableAddress( + const vkcv::RayTracingPipelineHandle &handle) const { + auto &pipeline = (*this) [handle]; + return &(pipeline.m_rayCallAddress); + } + +} diff --git a/src/vkcv/RayTracingPipelineManager.hpp b/src/vkcv/RayTracingPipelineManager.hpp new file mode 100644 index 00000000..f2b9da8b --- /dev/null +++ b/src/vkcv/RayTracingPipelineManager.hpp @@ -0,0 +1,118 @@ +#pragma once + +/** + * @authors Tobias Frisch + * @file src/vkcv/PipelineManager.hpp + * @brief Creation and handling of ray tracing pipelines + */ + +#include "BufferManager.hpp" +#include "DescriptorSetLayoutManager.hpp" +#include "HandleManager.hpp" +#include "PassManager.hpp" +#include "vkcv/RayTracingPipelineConfig.hpp" +#include <vector> +#include <vulkan/vulkan.hpp> + +namespace vkcv { + + struct RayTracingPipelineEntry { + vk::Pipeline m_handle; + vk::PipelineLayout m_layout; + RayTracingPipelineConfig m_config; + BufferHandle m_shaderBindingTable; + vk::StridedDeviceAddressRegionKHR m_rayGenAddress; + vk::StridedDeviceAddressRegionKHR m_rayMissAddress; + vk::StridedDeviceAddressRegionKHR m_rayHitAddress; + vk::StridedDeviceAddressRegionKHR m_rayCallAddress; + }; + + /** + * @brief Class to manage ray tracing pipelines. + */ + class RayTracingPipelineManager : + public HandleManager<RayTracingPipelineEntry, RayTracingPipelineHandle> { + private: + [[nodiscard]] uint64_t getIdFrom(const RayTracingPipelineHandle &handle) const override; + + [[nodiscard]] RayTracingPipelineHandle + createById(uint64_t id, const HandleDestroyFunction &destroy) override; + + /** + * Destroys and deallocates ray tracing pipeline represented by a given + * ray tracing pipeline handle id. + * + * @param id Ray tracing pipeline handle id + */ + void destroyById(uint64_t id) override; + + public: + RayTracingPipelineManager() noexcept; + + ~RayTracingPipelineManager() noexcept override; // dtor + + RayTracingPipelineManager(const RayTracingPipelineManager &other) = delete; // copy-ctor + RayTracingPipelineManager(RayTracingPipelineManager &&other) = delete; // move-ctor; + + RayTracingPipelineManager & + operator=(const RayTracingPipelineManager &other) = delete; // copy-assign op + RayTracingPipelineManager & + operator=(RayTracingPipelineManager &&other) = delete; // move-assign op + + /** + * Creates a ray tracing pipeline based on the set shader stages in the config struct. + * This function is wrapped in /src/vkcv/Core.cpp by Core::createRayTracingPipeline(const + * PipelineConfig &config). Therefore the passManager is filled already by the overall + * context of an application. On application level it is necessary first to fill a + * pipeline config struct. + * + * @param config Hands over all needed information for pipeline creation. + * @param descriptorManager Hands over the corresponding descriptor set layouts + * @param bufferManager Allows managing the shader binding table + * @return A handler to the created ray tracing pipeline object. + */ + RayTracingPipelineHandle createPipeline(const RayTracingPipelineConfig &config, + const DescriptorSetLayoutManager &descriptorManager, + BufferManager &bufferManager); + + /** + * Returns a vk::Pipeline object by handle. + * + * @param handle Directing to the requested pipeline. + * @return vk::Pipeline. + */ + [[nodiscard]] vk::Pipeline getVkPipeline(const RayTracingPipelineHandle &handle) const; + + /** + * Returns a vk::PipelineLayout object by handle. + * + * @param handle Directing to the requested pipeline. + * @return vk::PipelineLayout. + */ + [[nodiscard]] vk::PipelineLayout + getVkPipelineLayout(const RayTracingPipelineHandle &handle) const; + + /** + * Returns the corresponding pipeline config struct of a pipeline object directed by the + * given handler. + * + * @param handle Directing to the requested pipeline. + * @return Pipeline config struct + */ + [[nodiscard]] const RayTracingPipelineConfig & + getPipelineConfig(const RayTracingPipelineHandle &handle) const; + + [[nodiscard]] const vk::StridedDeviceAddressRegionKHR* + getRayGenShaderBindingTableAddress(const RayTracingPipelineHandle &handle) const; + + [[nodiscard]] const vk::StridedDeviceAddressRegionKHR* + getMissShaderBindingTableAddress(const RayTracingPipelineHandle &handle) const; + + [[nodiscard]] const vk::StridedDeviceAddressRegionKHR* + getHitShaderBindingTableAddress(const RayTracingPipelineHandle &handle) const; + + [[nodiscard]] const vk::StridedDeviceAddressRegionKHR* + getCallShaderBindingTableAddress(const RayTracingPipelineHandle &handle) const; + }; + +} // namespace vkcv -- GitLab