mirror of
https://github.com/antopilo/Nuake.git
synced 2026-01-03 14:09:46 +03:00
Progress on render pipeline and render pass abstraction
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user