Now render passes have execution order and building process

This commit is contained in:
antopilo
2025-01-07 19:19:17 -05:00
parent 0f5172eb04
commit d69c56bed8
11 changed files with 495 additions and 248 deletions

View File

@@ -0,0 +1,39 @@
#include "DescriptorLayoutBuilder.h"
#include "VulkanCheck.h"
using namespace Nuake;
void DescriptorLayoutBuilder::AddBinding(uint32_t binding, VkDescriptorType type)
{
VkDescriptorSetLayoutBinding newbind{};
newbind.binding = binding;
newbind.descriptorCount = 1;
newbind.descriptorType = type;
Bindings.push_back(newbind);
}
void DescriptorLayoutBuilder::Clear()
{
Bindings.clear();
}
VkDescriptorSetLayout DescriptorLayoutBuilder::Build(VkDevice device, VkShaderStageFlags shaderStages, void * pNext, VkDescriptorSetLayoutCreateFlags flags)
{
for (auto& b : Bindings) {
b.stageFlags |= shaderStages;
}
VkDescriptorSetLayoutCreateInfo info = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
info.pNext = pNext;
info.pBindings = Bindings.data();
info.bindingCount = (uint32_t)Bindings.size();
info.flags = flags;
VkDescriptorSetLayout set;
VK_CALL(vkCreateDescriptorSetLayout(device, &info, nullptr, &set));
return set;
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include <volk/volk.h>
#include <vector>
namespace Nuake
{
struct DescriptorLayoutBuilder
{
std::vector<VkDescriptorSetLayoutBinding> Bindings;
void AddBinding(uint32_t binding, VkDescriptorType type);
void Clear();
VkDescriptorSetLayout Build(VkDevice device, VkShaderStageFlags shaderStages, void* pNext = nullptr, VkDescriptorSetLayoutCreateFlags flags = 0);
};
}

View File

@@ -1,9 +1,11 @@
#include "RenderPipeline.h"
#include "src/Rendering/Vulkan/PipelineBuilder.h"
#include "src/Rendering/Vulkan/VkResources.h"
#include "src/Rendering/Vulkan/VulkanCheck.h"
#include "src/Rendering/Vulkan/VulkanInit.h"
#include "src/Rendering/Vulkan/VulkanRenderer.h"
#include "src/Rendering/Vulkan/VulkanImage/VulkanImage.h"
using namespace Nuake;
@@ -18,6 +20,73 @@ RenderPass::RenderPass(const std::string& name) :
{
}
void RenderPass::ClearAttachments(PassRenderContext& ctx)
{
// Clear all color attachments
VkClearColorValue clearValue = { { 0.0f, 0.0f, 0.0f, 1.0f } };
VkImageSubresourceRange clearRange = VulkanInit::ImageSubResourceRange(VK_IMAGE_ASPECT_COLOR_BIT);
for (auto& attachment : Attachments)
{
vkCmdClearColorImage(ctx.commandBuffer,attachment.Image->GetImage(), VK_IMAGE_LAYOUT_GENERAL, &clearValue, 1, &clearRange);
}
// Clear depth?
}
void RenderPass::TransitionAttachments(PassRenderContext& ctx)
{
// Transition all color attachments
for (auto& attachment : Attachments)
{
VulkanUtil::TransitionImage(ctx.commandBuffer, attachment.Image->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
}
// Transition depth attachment
VulkanUtil::TransitionImage(ctx.commandBuffer, DepthAttachment.Image->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL);
}
void RenderPass::Render(PassRenderContext& ctx)
{
if (PreRender)
{
PreRender(ctx);
}
// Begin rendering and bind pipeline
std::vector<VkRenderingAttachmentInfo> renderAttachmentInfos;
renderAttachmentInfos.reserve(Attachments.size());
for (auto& attachment : Attachments)
{
VkRenderingAttachmentInfo attachmentInfo = VulkanInit::AttachmentInfo(attachment.Image->GetImageView(), nullptr, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
renderAttachmentInfos.push_back(attachmentInfo);
}
VkRenderingAttachmentInfo depthAttachmentInfo = VulkanInit::DepthAttachmentInfo(DepthAttachment.Image->GetImageView(), VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL);
VkRenderingInfo renderInfo = VulkanInit::RenderingInfo(ctx.resolution, renderAttachmentInfos, &depthAttachmentInfo);
renderInfo.colorAttachmentCount = std::size(renderAttachmentInfos);
renderInfo.pColorAttachments = renderAttachmentInfos.data();
// Begin render!
vkCmdBeginRendering(ctx.commandBuffer, &renderInfo);
{
vkCmdBindPipeline(ctx.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, Pipeline);
if (RenderCb)
{
RenderCb(ctx);
}
}
vkCmdEndRendering(ctx.commandBuffer);
// End rendering
if (PostRender)
{
PostRender(ctx);
}
}
TextureAttachment& RenderPass::AddAttachment(const std::string& name, ImageFormat format, ImageUsage usage)
{
auto newAttachment = TextureAttachment(name, format);
@@ -43,14 +112,16 @@ void RenderPass::SetShaders(Ref<VulkanShader> vertShader, Ref<VulkanShader> frag
void RenderPass::Build()
{
// Push constant range
VkPushConstantRange bufferRange{};
bufferRange.offset = 0;
bufferRange.size = 128; // For now we assume we use 128 bytes
bufferRange.size = PushConstantSize;
bufferRange.stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS;
// TODO: Get the bindless descriptor layout
std::vector<VkDescriptorSetLayout> layouts = { 0 };
std::vector<VkDescriptorSetLayout> layouts = GPUResources::Get().GetBindlessLayout();
// Create pipeline layout
VkPipelineLayoutCreateInfo pipeline_layout_info = VulkanInit::PipelineLayoutCreateInfo();
pipeline_layout_info.pPushConstantRanges = &bufferRange;
pipeline_layout_info.pushConstantRangeCount = 1;
@@ -60,6 +131,9 @@ void RenderPass::Build()
VkPipelineLayout pipelineLayout;
VK_CALL(vkCreatePipelineLayout(VkRenderer::Get().GetDevice(), &pipeline_layout_info, nullptr, &pipelineLayout));
// Create pipeline
const size_t attachmentCount = Attachments.size();
PipelineBuilder pipelineBuilder;
pipelineBuilder.PipelineLayout = pipelineLayout;
pipelineBuilder.SetShaders(VertShader->GetModule(), FragShader->GetModule());
@@ -67,12 +141,26 @@ void RenderPass::Build()
pipelineBuilder.SetPolygonMode(VK_POLYGON_MODE_FILL);
pipelineBuilder.SetCullMode(VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_CLOCKWISE);
pipelineBuilder.SetMultiSamplingNone();
pipelineBuilder.EnableBlendingAlphaBlend(attachmentCount);
for (int i = 0; i < Attachments.size(); i++)
// Set color attachments
std::vector<VkFormat> formats;
formats.reserve(attachmentCount);
for (int i = 0; i < attachmentCount; i++)
{
pipelineBuilder.EnableBlendingAlphaBlend();
formats.push_back(static_cast<VkFormat>(Attachments[i].Format));
}
// Set depth attachment, for now we assume every pass has a depth attachment
pipelineBuilder.SetDepthFormat(static_cast<VkFormat>(DepthAttachment.Format));
pipelineBuilder.EnableDepthTest(true, VK_COMPARE_OP_GREATER_OR_EQUAL);
Pipeline = pipelineBuilder.BuildPipeline(VkRenderer::Get().GetDevice());
}
void RenderPass::SetPushConstant(std::any data, size_t size)
{
PushConstant = data;
PushConstantSize = size;
}
RenderPipeline::RenderPipeline() :
@@ -91,11 +179,23 @@ void RenderPipeline::Build()
{
pass.Build();
}
Built = true;
}
void RenderPipeline::Execute(std::span<std::string> inputs)
void RenderPipeline::Execute(PassRenderContext& ctx)
{
if (!Built)
{
Logger::Log("Pipeline not built", "vulkan", CRITICAL);
return;
}
for (auto& pass : RenderPasses)
{
pass.ClearAttachments(ctx);
pass.TransitionAttachments(ctx);
pass.Render(ctx);
}
}

View File

@@ -2,11 +2,12 @@
#include "src/Core/Core.h"
#include "src/Core/Maths.h"
#include "src/Rendering/Vulkan/VulkanImage/VulkanImage.h"
#include "src/Rendering/Vulkan/VulkanShader.h"
#include <any>
#include <functional>
#include <vector>
#include <span>
#include <src/Rendering/Vulkan/VulkanShader.h>
#include <vector>
namespace Nuake
@@ -17,6 +18,7 @@ namespace Nuake
{
Ref<Scene> scene;
VkCommandBuffer commandBuffer;
Vector2 resolution;
};
class TextureAttachment
@@ -24,6 +26,7 @@ namespace Nuake
public:
std::string Name;
ImageFormat Format;
Ref<VulkanImage> Image;
public:
TextureAttachment(const std::string& name, ImageFormat format);
@@ -48,24 +51,45 @@ namespace Nuake
TextureAttachment DepthAttachment;
std::vector<TextureAttachment> Inputs;
std::any PushConstant;
size_t PushConstantSize;
std::function<void(PassRenderContext& ctx)> PreRender;
std::function<void(PassRenderContext& ctx)> Render;
std::function<void(PassRenderContext& ctx)> RenderCb;
std::function<void(PassRenderContext& ctx)> PostRender;
// Vulkan structs
VkPipeline Pipeline;
public:
RenderPass(const std::string& name);
~RenderPass() = default;
void ClearAttachments(PassRenderContext& ctx);
void TransitionAttachments(PassRenderContext& ctx);
void Render(PassRenderContext& ctx);
public:
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);
template<typename T>
void SetPushConstant(T& pushConstant)
{
SetPushConstant(&pushConstant, sizeof(T));
}
void Build();
// Callbacks
void SetPreRender(const std::function<void(PassRenderContext& ctx)>& func) { PreRender = func; }
void SetRender(const std::function<void(PassRenderContext& ctx)>& func) { Render = func; }
void SetRender(const std::function<void(PassRenderContext& ctx)>& func) { RenderCb = func; }
void SetPostRender(const std::function<void(PassRenderContext& ctx)>& func) { PostRender = func; }
private:
void SetPushConstant(std::any data, size_t size);
};
class RenderPipeline
@@ -84,6 +108,6 @@ namespace Nuake
void Build();
void Execute(std::span<std::string> inputs);
void Execute(PassRenderContext& ctx);
};
}

View File

@@ -209,17 +209,20 @@ void PipelineBuilder::EnableBlendingAdditive()
ColorBlendAttachment.push_back(colorBlend);
}
void PipelineBuilder::EnableBlendingAlphaBlend()
void PipelineBuilder::EnableBlendingAlphaBlend(size_t count)
{
VkPipelineColorBlendAttachmentState colorBlend = {};
colorBlend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
colorBlend.blendEnable = VK_TRUE;
colorBlend.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
colorBlend.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
colorBlend.colorBlendOp = VK_BLEND_OP_ADD;
colorBlend.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
colorBlend.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
colorBlend.alphaBlendOp = VK_BLEND_OP_ADD;
for (size_t i = 0; i < count; i++)
{
VkPipelineColorBlendAttachmentState colorBlend = {};
colorBlend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
colorBlend.blendEnable = VK_TRUE;
colorBlend.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
colorBlend.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
colorBlend.colorBlendOp = VK_BLEND_OP_ADD;
colorBlend.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
colorBlend.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
colorBlend.alphaBlendOp = VK_BLEND_OP_ADD;
ColorBlendAttachment.push_back(colorBlend);
ColorBlendAttachment.push_back(colorBlend);
}
}

View File

@@ -40,7 +40,7 @@ namespace Nuake
void EnableDepthTest(bool depthWriteEnable, VkCompareOp op);
void EnableBlendingAdditive();
void EnableBlendingAlphaBlend();
void EnableBlendingAlphaBlend(size_t count = 1);
void EnableMultiAlphaBlend(size_t count);
};
}

View File

@@ -9,6 +9,11 @@
#include "src/Rendering/Vulkan/VkMesh.h"
#include "src/Rendering/Textures/TextureManager.h"
#include "src/Rendering/Vulkan/DescriptorLayoutBuilder.h"
#include "src/Rendering/Vulkan/VulkanRenderer.h"
#include <volk/volk.h>
namespace Nuake
{
class GPUResources
@@ -18,6 +23,19 @@ namespace Nuake
std::map<UUID, Ref<VkMesh>> Meshes;
std::map<UUID, Ref<VulkanImage>> Images;
// Bindless buffer layouts
VkDescriptorSetLayout CameraDescriptorLayout;
VkDescriptorSetLayout TriangleBufferDescriptorLayout;
VkDescriptorSetLayout ModelBufferDescriptorLayout;
VkDescriptorSetLayout ImageDescriptorLayout;
VkDescriptorSetLayout SamplerDescriptorLayout;
VkDescriptorSetLayout MaterialDescriptorLayout;
VkDescriptorSet CameraDescriptor;
VkDescriptorSet ModelDescriptor;
VkDescriptorSet SamplerDescriptor;
VkDescriptorSet MaterialDescriptor;
public:
static GPUResources& Get()
{
@@ -25,102 +43,27 @@ namespace Nuake
return instance;
};
GPUResources() = default;
GPUResources();
~GPUResources() = default;
Ref<AllocatedBuffer> CreateBuffer(size_t size, BufferUsage flags, MemoryUsage usage, const std::string& name = "")
{
Ref<AllocatedBuffer> buffer = CreateRef<AllocatedBuffer>(name, size, flags, usage);
Buffers[buffer->GetID()] = buffer;
return buffer;
}
public:
void Init();
bool AddBuffer(const Ref<AllocatedBuffer>& buffer)
{
const UUID id = buffer->GetID();
if (Buffers.find(id) == Buffers.end())
{
Buffers[id] = buffer;
return true;
}
Ref<AllocatedBuffer> CreateBuffer(size_t size, BufferUsage flags, MemoryUsage usage, const std::string& name = "");
bool AddBuffer(const Ref<AllocatedBuffer>& buffer);
Ref<AllocatedBuffer> GetBuffer(const UUID& id);
std::vector<Ref<AllocatedBuffer>> GetAllBuffers();
Logger::Log("Buffer with ID already exists", "vulkan", CRITICAL);
return false;
}
Ref<VkMesh> CreateMesh(const std::vector<Vertex>& vertices, const std::vector<uint32_t>& indices);
bool AddMesh(const Ref<VkMesh>& mesh);
Ref<VkMesh> GetMesh(const UUID& id);
Ref<AllocatedBuffer> GetBuffer(const UUID& id)
{
if (Buffers.find(id) != Buffers.end())
{
return Buffers[id];
}
bool AddTexture(Ref<VulkanImage> image);
Ref<VulkanImage> GetTexture(const UUID& id);
Logger::Log("Buffer with ID does not exist", "vulkan", CRITICAL);
return nullptr;
}
std::vector<VkDescriptorSetLayout> GetBindlessLayout();
std::vector<Ref<AllocatedBuffer>> GetAllBuffers()
{
std::vector<Ref<AllocatedBuffer>> allBuffers;
allBuffers.reserve(Buffers.size());
for (const auto& [id, buffer] : Buffers)
{
allBuffers.push_back(buffer);
}
return allBuffers;
}
Ref<VkMesh> CreateMesh(const std::vector<Vertex>& vertices, const std::vector<uint32_t>& indices)
{
Ref<VkMesh> mesh = CreateRef<VkMesh>(vertices, indices);
Meshes[mesh->GetID()] = mesh;
return mesh;
}
bool AddMesh(const Ref<VkMesh>& mesh)
{
const UUID id = mesh->GetID();
if (Meshes.find(id) == Meshes.end())
{
Meshes[id] = mesh;
return true;
}
Logger::Log("Mesh with ID already exists", "vulkan", CRITICAL);
return false;
}
Ref<VkMesh> GetMesh(const UUID& id)
{
if (Meshes.find(id) != Meshes.end())
{
return Meshes[id];
}
Logger::Log("Mesh with ID does not exist", "vulkan", CRITICAL);
return nullptr;
}
bool AddTexture(Ref<VulkanImage> image)
{
const UUID id = image->GetID();
if (Images.find(id) == Images.end())
{
Images[id] = image;
return true;
}
Logger::Log("Buffer with ID already exists", "vulkan", CRITICAL);
return false;
}
Ref<VulkanImage> GetTexture(const UUID& id)
{
if (Images.find(id) != Images.end())
{
return Images[id];
}
Logger::Log("Mesh with ID does not exist", "vulkan", CRITICAL);
return TextureManager::Get()->GetTexture2("missing_texture");
}
private:
void CreateBindlessLayout();
};
}

View File

@@ -6,11 +6,7 @@
#include "VulkanShader.h"
#include "src/Window.h"
#include <GLFW/glfw3.h>
#include "imgui/imgui.h"
#include "imgui/imgui_impl_vulkan.h"
#include <imgui/imgui_impl_glfw.h>
#include "src/Resource/StaticResources.h"
#include "VulkanInit.h"
#include "VulkanAllocator.h"
@@ -18,17 +14,28 @@
#include "VulkanCheck.h"
#include "PipelineBuilder.h"
#include "VulkanAllocatedBuffer.h"
#include <array>
#include "VkResources.h"
using namespace Nuake;
#include "vk_mem_alloc.h"
#include <src/Rendering/Vertex.h>
#include "src/Rendering/Vertex.h"
#include "VulkanSceneRenderer.h"
#include "DescriptorLayoutBuilder.h"
#include "imgui/imgui.h"
#include "imgui/imgui_impl_vulkan.h"
#include "imgui/imgui_impl_glfw.h"
#include "GLFW/glfw3.h"
#include "vk_mem_alloc.h"
#include <array>
bool NKUseValidationLayer = true;
using namespace Nuake;
VkRenderer::~VkRenderer()
{
CleanUp();
@@ -911,39 +918,7 @@ void VkRenderer::UploadCameraData(const CameraData& data)
vmaUnmapMemory(VulkanAllocator::Get().GetAllocator(), GetCurrentFrame().CameraStagingBuffer->GetAllocation());
}
void DescriptorLayoutBuilder::AddBinding(uint32_t binding, VkDescriptorType type)
{
VkDescriptorSetLayoutBinding newbind{};
newbind.binding = binding;
newbind.descriptorCount = 1;
newbind.descriptorType = type;
Bindings.push_back(newbind);
}
void DescriptorLayoutBuilder::Clear()
{
Bindings.clear();
}
VkDescriptorSetLayout DescriptorLayoutBuilder::Build(VkDevice device, VkShaderStageFlags shaderStages, void * pNext, VkDescriptorSetLayoutCreateFlags flags)
{
for (auto& b : Bindings) {
b.stageFlags |= shaderStages;
}
VkDescriptorSetLayoutCreateInfo info = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
info.pNext = pNext;
info.pBindings = Bindings.data();
info.bindingCount = (uint32_t)Bindings.size();
info.flags = flags;
VkDescriptorSetLayout set;
VK_CALL(vkCreateDescriptorSetLayout(device, &info, nullptr, &set));
return set;
}
void DescriptorAllocator::InitPool(VkDevice device, uint32_t maxSets, std::span<PoolSizeRatio> poolRatios)
{

View File

@@ -83,9 +83,9 @@ namespace Nuake
VkCommandPool CommandPool; // This is like the allocator for a buffer.
VkCommandBuffer CommandBuffer; // You send commands in there.
Ref<AllocatedBuffer> CameraStagingBuffer;
Ref<AllocatedBuffer> ModelStagingBuffer;
Ref<AllocatedBuffer> MaterialStagingBuffer;
Ref<AllocatedBuffer> CameraStagingBuffer; // Current camera
Ref<AllocatedBuffer> ModelStagingBuffer; // Matrices
Ref<AllocatedBuffer> MaterialStagingBuffer; // Materials
// Semaphore are for GPU -> GPU sync
// Fence are for CPU -> GPU
@@ -98,17 +98,6 @@ namespace Nuake
DeletionQueue LocalDeletionQueue; // Local when destroying this frame
};
struct DescriptorLayoutBuilder
{
std::vector<VkDescriptorSetLayoutBinding> Bindings;
void AddBinding(uint32_t binding, VkDescriptorType type);
void Clear();
VkDescriptorSetLayout Build(VkDevice device, VkShaderStageFlags shaderStages, void* pNext = nullptr, VkDescriptorSetLayoutCreateFlags flags = 0);
};
struct DescriptorAllocator
{
struct PoolSizeRatio
@@ -126,7 +115,6 @@ namespace Nuake
VkDescriptorSet Allocate(VkDevice device, VkDescriptorSetLayout layout);
};
struct CameraData
{
Matrix4 View;

View File

@@ -0,0 +1,169 @@
#include "VkResources.h"
using namespace Nuake;
GPUResources::GPUResources()
{
Init();
}
void GPUResources::Init()
{
CreateBindlessLayout();
}
Ref<AllocatedBuffer> GPUResources::CreateBuffer(size_t size, BufferUsage flags, MemoryUsage usage, const std::string& name)
{
Ref<AllocatedBuffer> buffer = CreateRef<AllocatedBuffer>(name, size, flags, usage);
Buffers[buffer->GetID()] = buffer;
return buffer;
}
bool GPUResources::AddBuffer(const Ref<AllocatedBuffer>& buffer)
{
const UUID id = buffer->GetID();
if (Buffers.find(id) == Buffers.end())
{
Buffers[id] = buffer;
return true;
}
Logger::Log("Buffer with ID already exists", "vulkan", CRITICAL);
return false;
}
Ref<AllocatedBuffer> GPUResources::GetBuffer(const UUID& id)
{
if (Buffers.find(id) != Buffers.end())
{
return Buffers[id];
}
Logger::Log("Buffer with ID does not exist", "vulkan", CRITICAL);
return nullptr;
}
std::vector<Ref<AllocatedBuffer>> GPUResources::GetAllBuffers()
{
std::vector<Ref<AllocatedBuffer>> allBuffers;
allBuffers.reserve(Buffers.size());
for (const auto& [id, buffer] : Buffers)
{
allBuffers.push_back(buffer);
}
return allBuffers;
}
Ref<VkMesh> GPUResources::CreateMesh(const std::vector<Vertex>& vertices, const std::vector<uint32_t>& indices)
{
Ref<VkMesh> mesh = CreateRef<VkMesh>(vertices, indices);
Meshes[mesh->GetID()] = mesh;
return mesh;
}
bool GPUResources::AddMesh(const Ref<VkMesh>& mesh)
{
const UUID id = mesh->GetID();
if (Meshes.find(id) == Meshes.end())
{
Meshes[id] = mesh;
return true;
}
Logger::Log("Mesh with ID already exists", "vulkan", CRITICAL);
return false;
}
Ref<VkMesh> GPUResources::GetMesh(const UUID& id)
{
if (Meshes.find(id) != Meshes.end())
{
return Meshes[id];
}
Logger::Log("Mesh with ID does not exist", "vulkan", CRITICAL);
return nullptr;
}
bool GPUResources::AddTexture(Ref<VulkanImage> image)
{
const UUID id = image->GetID();
if (Images.find(id) == Images.end())
{
Images[id] = image;
return true;
}
Logger::Log("Buffer with ID already exists", "vulkan", CRITICAL);
return false;
}
Ref<VulkanImage> GPUResources::GetTexture(const UUID& id)
{
if (Images.find(id) != Images.end())
{
return Images[id];
}
Logger::Log("Mesh with ID does not exist", "vulkan", CRITICAL);
return TextureManager::Get()->GetTexture2("missing_texture");
}
void GPUResources::CreateBindlessLayout()
{
auto& vk = VkRenderer::Get();
auto device = vk.GetDevice();
// Camera
{
DescriptorLayoutBuilder builder;
builder.AddBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
CameraDescriptorLayout = builder.Build(device, VK_SHADER_STAGE_VERTEX_BIT);
}
{
// Triangle vertex buffer layout
DescriptorLayoutBuilder builder;
builder.AddBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
TriangleBufferDescriptorLayout = builder.Build(device, VK_SHADER_STAGE_VERTEX_BIT);
}
{
// Matrices
DescriptorLayoutBuilder builder;
builder.AddBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
ModelBufferDescriptorLayout = builder.Build(device, VK_SHADER_STAGE_VERTEX_BIT);
}
// Textures
{
DescriptorLayoutBuilder builder;
builder.AddBinding(0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
ImageDescriptorLayout = builder.Build(device, VK_SHADER_STAGE_FRAGMENT_BIT);
}
{
DescriptorLayoutBuilder builder;
builder.AddBinding(0, VK_DESCRIPTOR_TYPE_SAMPLER);
SamplerDescriptorLayout = builder.Build(device, VK_SHADER_STAGE_FRAGMENT_BIT);
}
// Material
{
DescriptorLayoutBuilder builder;
builder.AddBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
MaterialDescriptorLayout = builder.Build(device, VK_SHADER_STAGE_FRAGMENT_BIT);
}
}
std::vector<VkDescriptorSetLayout> GPUResources::GetBindlessLayout()
{
std::vector<VkDescriptorSetLayout> layouts = {
CameraDescriptorLayout,
ModelBufferDescriptorLayout,
TriangleBufferDescriptorLayout,
ImageDescriptorLayout,
SamplerDescriptorLayout,
MaterialDescriptorLayout
};
return layouts;
}

View File

@@ -17,6 +17,7 @@
#include <src/Scene/Components/ModelComponent.h>
#include "Pipeline/RenderPipeline.h"
#include "src/Rendering/Vulkan/DescriptorLayoutBuilder.h"
using namespace Nuake;
@@ -38,88 +39,72 @@ void VkSceneRenderer::Init()
SetGBufferSize({ 1280, 720 });
CreateBasicPipeline();
CreatePipelines();
ModelMatrixMapping.clear();
MeshMaterialMapping.clear();
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) {
});
gBufferPass.SetPostRender([](PassRenderContext& context) {
});
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);
//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)
@@ -144,7 +129,8 @@ void VkSceneRenderer::BeginScene(RenderContext inContext)
throw std::runtime_error("Draw image is not initialized");
}
PassRenderContext passCtx = { inContext.CurrentScene, inContext.CommandBuffer };
GBufferPipeline.Execute(passCtx);
// Ensure the pipeline is valid
if (BasicPipeline == VK_NULL_HANDLE) {
@@ -249,7 +235,7 @@ void VkSceneRenderer::BeginScene(RenderContext inContext)
scissor.extent.height = GBufferAlbedo->GetWidth();
vkCmdSetScissor(cmd, 0, 1, &scissor);
}
ModelPushConstant modelPushConstant{};
void VkSceneRenderer::DrawScene()
{
ZoneScoped;
@@ -305,7 +291,7 @@ void VkSceneRenderer::DrawScene()
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, BasicPipelineLayout, 4, 1, &SamplerDescriptor, 0, nullptr);
ModelPushConstant modelPushConstant{};
modelPushConstant.Index = ModelMatrixMapping[entity.GetID()];
modelPushConstant.MaterialIndex = MeshMaterialMapping[vkMesh->GetID()];
@@ -511,12 +497,15 @@ void VkSceneRenderer::CreateDescriptors()
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);
gBufferPass.SetPushConstant<ModelPushConstant>(modelPushConstant);
GBufferPipeline.Build();
}