Progress on render pipeline and render pass abstraction

This commit is contained in:
antopilo
2025-01-06 14:53:13 -05:00
parent ab09f8efb5
commit 0f5172eb04
4 changed files with 182 additions and 33 deletions

View File

@@ -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<VulkanShader> vertShader, Ref<VulkanShader> 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<VkDescriptorSetLayout> 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<std::string> inputs)
{
}

View File

@@ -5,6 +5,8 @@
#include <functional>
#include <vector>
#include <span>
#include <src/Rendering/Vulkan/VulkanShader.h>
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<PassAttachment> Attachments;
std::vector<std::string> Inputs;
Ref<VulkanShader> VertShader;
Ref<VulkanShader> FragShader;
std::vector<TextureAttachment> Attachments;
TextureAttachment DepthAttachment;
std::vector<TextureAttachment> Inputs;
std::function<void(PassRenderContext& ctx)> PreRender;
std::function<void(PassRenderContext& ctx)> 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<VulkanShader> vertShader, Ref<VulkanShader> fragShader);
void Build();
// Callbacks
void SetPreRender(const std::function<void(PassRenderContext& ctx)>& func) { PreRender = func; }
@@ -62,14 +71,19 @@ namespace Nuake
class RenderPipeline
{
private:
bool Built;
std::vector<RenderPass> RenderPasses;
Vector2 Size;
public:
RenderPipeline(const Vector2& size);
RenderPipeline();
~RenderPipeline() = default;
public:
RenderPass& AddPass(const std::string& name);
void Build();
void Execute(std::span<std::string> inputs);
};
}

View File

@@ -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<TextureAttachment> 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<TextureAttachment> 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<std::string> 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<VulkanImage>(ImageFormat::RGBA16F, size);

View File

@@ -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 <volk/volk.h>
@@ -95,6 +96,9 @@ namespace Nuake
Ref<VulkanImage> GBufferMaterial;
Ref<VulkanImage> 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();