mirror of
https://github.com/antopilo/Nuake.git
synced 2026-09-15 20:08:54 +03:00
Now render passes have execution order and building process
This commit is contained in:
39
Nuake/src/Rendering/Vulkan/DescriptorLayoutBuilder.cpp
Normal file
39
Nuake/src/Rendering/Vulkan/DescriptorLayoutBuilder.cpp
Normal 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;
|
||||
}
|
||||
17
Nuake/src/Rendering/Vulkan/DescriptorLayoutBuilder.h
Normal file
17
Nuake/src/Rendering/Vulkan/DescriptorLayoutBuilder.h
Normal 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);
|
||||
};
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
169
Nuake/src/Rendering/Vulkan/VulkanResources.cpp
Normal file
169
Nuake/src/Rendering/Vulkan/VulkanResources.cpp
Normal 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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user