From 0f5172eb04ecd9fc06d0882eae878debe1a5a60b Mon Sep 17 00:00:00 2001 From: antopilo Date: Mon, 6 Jan 2025 14:53:13 -0500 Subject: [PATCH] Progress on render pipeline and render pass abstraction --- .../Vulkan/Pipeline/RenderPipeline.cpp | 83 ++++++++++++++-- .../Vulkan/Pipeline/RenderPipeline.h | 32 +++++-- .../Rendering/Vulkan/VulkanSceneRenderer.cpp | 95 ++++++++++++++++--- .../Rendering/Vulkan/VulkanSceneRenderer.h | 5 + 4 files changed, 182 insertions(+), 33 deletions(-) diff --git a/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.cpp b/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.cpp index ff6a5591..536386ca 100644 --- a/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.cpp +++ b/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.cpp @@ -1,38 +1,101 @@ #include "RenderPipeline.h" +#include "src/Rendering/Vulkan/PipelineBuilder.h" +#include "src/Rendering/Vulkan/VulkanCheck.h" +#include "src/Rendering/Vulkan/VulkanInit.h" +#include "src/Rendering/Vulkan/VulkanRenderer.h" + using namespace Nuake; +TextureAttachment::TextureAttachment(const std::string& name, ImageFormat format) : + Name(name), + Format(format) +{ +} + RenderPass::RenderPass(const std::string& name) : Name(name) { } -PassAttachment& RenderPass::AddAttachment(const std::string& name, ImageFormat format) +TextureAttachment& RenderPass::AddAttachment(const std::string& name, ImageFormat format, ImageUsage usage) { - auto newAttachment = PassAttachment(name, format); - PassAttachment& newAttachmentRef = Attachments.emplace_back(std::move(newAttachment)); + auto newAttachment = TextureAttachment(name, format); + if (usage == ImageUsage::Depth) + { + DepthAttachment = newAttachment; + } + + TextureAttachment& newAttachmentRef = Attachments.emplace_back(std::move(newAttachment)); return newAttachmentRef; } -void RenderPass::AddInput(const std::string& name) +void RenderPass::AddInput(const TextureAttachment& name) { Inputs.push_back(name); } -RenderPipeline::RenderPipeline(const Vector2& size) : - Size(size) +void RenderPass::SetShaders(Ref vertShader, Ref fragShader) { + VertShader = vertShader; + FragShader = fragShader; } +void RenderPass::Build() +{ + VkPushConstantRange bufferRange{}; + bufferRange.offset = 0; + bufferRange.size = 128; // For now we assume we use 128 bytes + bufferRange.stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS; + + // TODO: Get the bindless descriptor layout + std::vector layouts = { 0 }; + + VkPipelineLayoutCreateInfo pipeline_layout_info = VulkanInit::PipelineLayoutCreateInfo(); + pipeline_layout_info.pPushConstantRanges = &bufferRange; + pipeline_layout_info.pushConstantRangeCount = 1; + pipeline_layout_info.pSetLayouts = layouts.data(); + pipeline_layout_info.setLayoutCount = layouts.size(); + + VkPipelineLayout pipelineLayout; + VK_CALL(vkCreatePipelineLayout(VkRenderer::Get().GetDevice(), &pipeline_layout_info, nullptr, &pipelineLayout)); + + PipelineBuilder pipelineBuilder; + pipelineBuilder.PipelineLayout = pipelineLayout; + pipelineBuilder.SetShaders(VertShader->GetModule(), FragShader->GetModule()); + pipelineBuilder.SetInputTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); + pipelineBuilder.SetPolygonMode(VK_POLYGON_MODE_FILL); + pipelineBuilder.SetCullMode(VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_CLOCKWISE); + pipelineBuilder.SetMultiSamplingNone(); + + for (int i = 0; i < Attachments.size(); i++) + { + pipelineBuilder.EnableBlendingAlphaBlend(); + } + +} + +RenderPipeline::RenderPipeline() : + Built(false) +{ } + RenderPass& RenderPipeline::AddPass(const std::string& name) { auto newPass = RenderPass(name); - RenderPasses.push_back(std::move(newPass)); + return RenderPasses.emplace_back(std::move(newPass)); } -PassAttachment::PassAttachment(const std::string& name, ImageFormat format) : - Name(name), - Format(format) +void RenderPipeline::Build() { + for (auto& pass : RenderPasses) + { + pass.Build(); + } + Built = true; +} + +void RenderPipeline::Execute(std::span inputs) +{ + } diff --git a/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.h b/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.h index 473269db..03e7ebcf 100644 --- a/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.h +++ b/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.h @@ -5,6 +5,8 @@ #include #include +#include +#include namespace Nuake @@ -17,15 +19,16 @@ namespace Nuake VkCommandBuffer commandBuffer; }; - class PassAttachment + class TextureAttachment { public: std::string Name; ImageFormat Format; public: - PassAttachment(const std::string& name, ImageFormat format); - ~PassAttachment() = default; + TextureAttachment(const std::string& name, ImageFormat format); + TextureAttachment() = default; + ~TextureAttachment() = default; }; struct RenderPassSpec @@ -38,8 +41,12 @@ namespace Nuake { private: std::string Name; - std::vector Attachments; - std::vector Inputs; + Ref VertShader; + Ref FragShader; + + std::vector Attachments; + TextureAttachment DepthAttachment; + std::vector Inputs; std::function PreRender; std::function Render; @@ -50,8 +57,10 @@ namespace Nuake ~RenderPass() = default; public: - PassAttachment& AddAttachment(const std::string& name, ImageFormat format); - void AddInput(const std::string& name); + TextureAttachment& AddAttachment(const std::string& name, ImageFormat format, ImageUsage usage = ImageUsage::Default); + void AddInput(const TextureAttachment& attachment); + void SetShaders(Ref vertShader, Ref fragShader); + void Build(); // Callbacks void SetPreRender(const std::function& func) { PreRender = func; } @@ -62,14 +71,19 @@ namespace Nuake class RenderPipeline { private: + bool Built; + std::vector RenderPasses; - Vector2 Size; public: - RenderPipeline(const Vector2& size); + RenderPipeline(); ~RenderPipeline() = default; public: RenderPass& AddPass(const std::string& name); + + void Build(); + + void Execute(std::span inputs); }; } \ No newline at end of file diff --git a/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp b/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp index 781bd0eb..e41834f4 100644 --- a/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp +++ b/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp @@ -42,29 +42,84 @@ void VkSceneRenderer::Init() ModelMatrixMapping.clear(); MeshMaterialMapping.clear(); - - auto renderPipelineOpaque = RenderPipeline({1280, 720}); - + auto renderPipelineOpaque = RenderPipeline(); auto& gBufferPass = renderPipelineOpaque.AddPass("GBuffer"); gBufferPass.AddAttachment("Albedo", ImageFormat::RGBA8); gBufferPass.AddAttachment("Normal", ImageFormat::RGBA8); gBufferPass.AddAttachment("Material", ImageFormat::RGBA8); gBufferPass.AddAttachment("Depth", ImageFormat::D32F); + gBufferPass.SetPreRender([](PassRenderContext& context) { + + }); + gBufferPass.SetRender([](PassRenderContext& context) { - auto& ssaoPass = renderPipelineOpaque.AddPass("SSAO"); - ssaoPass.AddInput("Normal"); - ssaoPass.AddInput("Depth"); - ssaoPass.AddAttachment("SSAO", ImageFormat::RGBA8); + }); + gBufferPass.SetPostRender([](PassRenderContext& context) { - auto& shadingPass = renderPipelineOpaque.AddPass("Shading"); - shadingPass.AddInput("Albedo"); - shadingPass.AddInput("Normal"); - shadingPass.AddInput("Material"); - shadingPass.AddInput("SSAO"); - shadingPass.AddInput("Depth"); - shadingPass.AddAttachment("Output", ImageFormat::RGBA16F); + }); + renderPipelineOpaque.Execute({}); + RenderPipeline bloomPipeline = RenderPipeline(); + auto& thresholdPass = bloomPipeline.AddPass("Threshold"); + auto& thresholdOuput = thresholdPass.AddAttachment("ThresholdOutput", ImageFormat::RGBA16F); + //thresholdPass.AddInput("Source"); + // Downsample + const uint32_t iterationCount = 4; + std::vector downsampleAttachments; + for (int i = 0; i < iterationCount; i++) + { + const std::string passName = "Downsample" + std::to_string(i); + auto& downsamplePass = bloomPipeline.AddPass(passName); + auto& downsampleOutput = downsamplePass.AddAttachment("DownsampleOutput", ImageFormat::RGBA16F); + downsampleAttachments.push_back(downsampleOutput); + + if (i == 0) + { // Initial downsample from source + downsamplePass.AddInput(thresholdOuput); + } + else + { // Downsample previous pass + const uint32_t previousIndex = iterationCount - i - 1; +; downsamplePass.AddInput(downsampleAttachments[previousIndex]); + } + } + + // Blur & Upsample + std::vector upsampleAttachments; + for (int i = 0; i < iterationCount; i++) + { + auto& blurHPass = bloomPipeline.AddPass("BlurH" + std::to_string(i)); + auto& blurHOutput = blurHPass.AddAttachment("BlurHOutput", ImageFormat::RGBA16F); + + blurHPass.AddInput(downsampleAttachments[4 - i - 1]); + + auto& blurVPass = bloomPipeline.AddPass("BlurV" + std::to_string(i)); + auto& blurVOutput = blurVPass.AddAttachment("BlurVOutput", ImageFormat::RGBA16F); + blurVPass.AddInput(blurHOutput); + + auto& upsamplePass = bloomPipeline.AddPass("Upsample" + std::to_string(i)); + auto& upsampleOutput = upsamplePass.AddAttachment("UpsampleOutput", ImageFormat::RGBA16F); + + if (i == 0) + { + upsamplePass.AddInput(upsampleAttachments[i - 1]); + } + else + { + upsamplePass.AddInput(upsampleAttachments[i - 1]); + } + upsamplePass.AddInput(blurVOutput); + + upsampleAttachments.push_back(upsampleOutput); + } + + // Final composition + auto& finalPass = bloomPipeline.AddPass("Final"); + finalPass.AddAttachment("FinalOutput", ImageFormat::RGBA16F); + + std::vector inputs = { "Source", "Lens"}; + bloomPipeline.Execute(inputs); } void VkSceneRenderer::BeginScene(RenderContext inContext) @@ -453,6 +508,18 @@ void VkSceneRenderer::CreateDescriptors() vkUpdateDescriptorSets(device, 1, &samplerWrite, 0, nullptr); } +void VkSceneRenderer::CreatePipelines() +{ + GBufferPipeline = RenderPipeline(); + auto& gBufferPass = GBufferPipeline.AddPass("GBuffer"); + gBufferPass.SetShaders(Shaders["basic_vert"], Shaders["basic_frag"]); + gBufferPass.AddAttachment("Albedo", ImageFormat::RGBA8); + gBufferPass.AddAttachment("Normal", ImageFormat::RGBA16F); + gBufferPass.AddAttachment("Material", ImageFormat::RGBA8); + gBufferPass.AddAttachment("Depth", ImageFormat::D32F, ImageUsage::Depth); + GBufferPipeline.Build(); +} + void VkSceneRenderer::SetGBufferSize(const Vector2& size) { GBufferAlbedo = CreateRef(ImageFormat::RGBA16F, size); diff --git a/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.h b/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.h index e4e5551b..e4af918b 100644 --- a/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.h +++ b/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.h @@ -5,6 +5,7 @@ #include "src/Rendering/Vulkan/VulkanShader.h" #include "src/Rendering/Vulkan/VulkanAllocatedBuffer.h" #include "src/Rendering/Vulkan/VulkanImage/VulkanImage.h" +#include "src/Rendering/Vulkan/Pipeline/RenderPipeline.h" #include @@ -95,6 +96,9 @@ namespace Nuake Ref GBufferMaterial; Ref GBufferDepthImage; + // New pipeline stuff + RenderPipeline GBufferPipeline; + public: VkSceneRenderer(); ~VkSceneRenderer(); @@ -114,6 +118,7 @@ namespace Nuake void CreateBasicPipeline(); void CreateSamplers(); void CreateDescriptors(); + void CreatePipelines(); void BuildMatrixBuffer(); void UpdateTransformBuffer();