diff --git a/Nuake/src/Rendering/Vulkan/DescriptorLayoutBuilder.cpp b/Nuake/src/Rendering/Vulkan/DescriptorLayoutBuilder.cpp new file mode 100644 index 00000000..26f938ed --- /dev/null +++ b/Nuake/src/Rendering/Vulkan/DescriptorLayoutBuilder.cpp @@ -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; +} \ No newline at end of file diff --git a/Nuake/src/Rendering/Vulkan/DescriptorLayoutBuilder.h b/Nuake/src/Rendering/Vulkan/DescriptorLayoutBuilder.h new file mode 100644 index 00000000..8b707e7f --- /dev/null +++ b/Nuake/src/Rendering/Vulkan/DescriptorLayoutBuilder.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +#include + +namespace Nuake +{ + struct DescriptorLayoutBuilder + { + std::vector Bindings; + + void AddBinding(uint32_t binding, VkDescriptorType type); + void Clear(); + VkDescriptorSetLayout Build(VkDevice device, VkShaderStageFlags shaderStages, void* pNext = nullptr, VkDescriptorSetLayoutCreateFlags flags = 0); + }; +} \ No newline at end of file diff --git a/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.cpp b/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.cpp index 536386ca..751c2de6 100644 --- a/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.cpp +++ b/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.cpp @@ -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 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 vertShader, Ref 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 layouts = { 0 }; + std::vector 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 formats; + formats.reserve(attachmentCount); + for (int i = 0; i < attachmentCount; i++) { - pipelineBuilder.EnableBlendingAlphaBlend(); + formats.push_back(static_cast(Attachments[i].Format)); } + // Set depth attachment, for now we assume every pass has a depth attachment + pipelineBuilder.SetDepthFormat(static_cast(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 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); + } } diff --git a/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.h b/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.h index 03e7ebcf..9bd8b180 100644 --- a/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.h +++ b/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.h @@ -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 #include -#include #include -#include +#include namespace Nuake @@ -17,6 +18,7 @@ namespace Nuake { Ref scene; VkCommandBuffer commandBuffer; + Vector2 resolution; }; class TextureAttachment @@ -24,6 +26,7 @@ namespace Nuake public: std::string Name; ImageFormat Format; + Ref Image; public: TextureAttachment(const std::string& name, ImageFormat format); @@ -48,24 +51,45 @@ namespace Nuake TextureAttachment DepthAttachment; std::vector Inputs; + std::any PushConstant; + size_t PushConstantSize; + std::function PreRender; - std::function Render; + std::function RenderCb; std::function 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 vertShader, Ref fragShader); + + template + void SetPushConstant(T& pushConstant) + { + SetPushConstant(&pushConstant, sizeof(T)); + } + void Build(); // Callbacks void SetPreRender(const std::function& func) { PreRender = func; } - void SetRender(const std::function& func) { Render = func; } + void SetRender(const std::function& func) { RenderCb = func; } void SetPostRender(const std::function& 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 inputs); + void Execute(PassRenderContext& ctx); }; } \ No newline at end of file diff --git a/Nuake/src/Rendering/Vulkan/PipelineBuilder.cpp b/Nuake/src/Rendering/Vulkan/PipelineBuilder.cpp index 1e0ab1a7..c588f709 100644 --- a/Nuake/src/Rendering/Vulkan/PipelineBuilder.cpp +++ b/Nuake/src/Rendering/Vulkan/PipelineBuilder.cpp @@ -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); + } } \ No newline at end of file diff --git a/Nuake/src/Rendering/Vulkan/PipelineBuilder.h b/Nuake/src/Rendering/Vulkan/PipelineBuilder.h index 230d4e4d..e107dbe2 100644 --- a/Nuake/src/Rendering/Vulkan/PipelineBuilder.h +++ b/Nuake/src/Rendering/Vulkan/PipelineBuilder.h @@ -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); }; } \ No newline at end of file diff --git a/Nuake/src/Rendering/Vulkan/VkResources.h b/Nuake/src/Rendering/Vulkan/VkResources.h index 4726abce..57c1a25a 100644 --- a/Nuake/src/Rendering/Vulkan/VkResources.h +++ b/Nuake/src/Rendering/Vulkan/VkResources.h @@ -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 + namespace Nuake { class GPUResources @@ -18,6 +23,19 @@ namespace Nuake std::map> Meshes; std::map> 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 CreateBuffer(size_t size, BufferUsage flags, MemoryUsage usage, const std::string& name = "") - { - Ref buffer = CreateRef(name, size, flags, usage); - Buffers[buffer->GetID()] = buffer; - return buffer; - } + public: + void Init(); - bool AddBuffer(const Ref& buffer) - { - const UUID id = buffer->GetID(); - if (Buffers.find(id) == Buffers.end()) - { - Buffers[id] = buffer; - return true; - } + Ref CreateBuffer(size_t size, BufferUsage flags, MemoryUsage usage, const std::string& name = ""); + bool AddBuffer(const Ref& buffer); + Ref GetBuffer(const UUID& id); + std::vector> GetAllBuffers(); - Logger::Log("Buffer with ID already exists", "vulkan", CRITICAL); - return false; - } + Ref CreateMesh(const std::vector& vertices, const std::vector& indices); + bool AddMesh(const Ref& mesh); + Ref GetMesh(const UUID& id); - Ref GetBuffer(const UUID& id) - { - if (Buffers.find(id) != Buffers.end()) - { - return Buffers[id]; - } + bool AddTexture(Ref image); + Ref GetTexture(const UUID& id); - Logger::Log("Buffer with ID does not exist", "vulkan", CRITICAL); - return nullptr; - } + std::vector GetBindlessLayout(); - std::vector> GetAllBuffers() - { - std::vector> allBuffers; - allBuffers.reserve(Buffers.size()); - for (const auto& [id, buffer] : Buffers) - { - allBuffers.push_back(buffer); - } - return allBuffers; - } - - Ref CreateMesh(const std::vector& vertices, const std::vector& indices) - { - Ref mesh = CreateRef(vertices, indices); - Meshes[mesh->GetID()] = mesh; - return mesh; - } - - bool AddMesh(const Ref& 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 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 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 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(); }; } \ No newline at end of file diff --git a/Nuake/src/Rendering/Vulkan/VulkanRenderer.cpp b/Nuake/src/Rendering/Vulkan/VulkanRenderer.cpp index 87fafbb2..dbcc504f 100644 --- a/Nuake/src/Rendering/Vulkan/VulkanRenderer.cpp +++ b/Nuake/src/Rendering/Vulkan/VulkanRenderer.cpp @@ -6,11 +6,7 @@ #include "VulkanShader.h" #include "src/Window.h" -#include -#include "imgui/imgui.h" -#include "imgui/imgui_impl_vulkan.h" -#include #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 #include "VkResources.h" -using namespace Nuake; -#include "vk_mem_alloc.h" -#include +#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 + 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 poolRatios) { diff --git a/Nuake/src/Rendering/Vulkan/VulkanRenderer.h b/Nuake/src/Rendering/Vulkan/VulkanRenderer.h index 0e202a73..31b63ad2 100644 --- a/Nuake/src/Rendering/Vulkan/VulkanRenderer.h +++ b/Nuake/src/Rendering/Vulkan/VulkanRenderer.h @@ -83,9 +83,9 @@ namespace Nuake VkCommandPool CommandPool; // This is like the allocator for a buffer. VkCommandBuffer CommandBuffer; // You send commands in there. - Ref CameraStagingBuffer; - Ref ModelStagingBuffer; - Ref MaterialStagingBuffer; + Ref CameraStagingBuffer; // Current camera + Ref ModelStagingBuffer; // Matrices + Ref 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 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; diff --git a/Nuake/src/Rendering/Vulkan/VulkanResources.cpp b/Nuake/src/Rendering/Vulkan/VulkanResources.cpp new file mode 100644 index 00000000..a993fd12 --- /dev/null +++ b/Nuake/src/Rendering/Vulkan/VulkanResources.cpp @@ -0,0 +1,169 @@ +#include "VkResources.h" + +using namespace Nuake; + +GPUResources::GPUResources() +{ + Init(); +} + +void GPUResources::Init() +{ + CreateBindlessLayout(); + +} + +Ref GPUResources::CreateBuffer(size_t size, BufferUsage flags, MemoryUsage usage, const std::string& name) +{ + Ref buffer = CreateRef(name, size, flags, usage); + Buffers[buffer->GetID()] = buffer; + return buffer; +} + +bool GPUResources::AddBuffer(const Ref& 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 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> GPUResources::GetAllBuffers() +{ + std::vector> allBuffers; + allBuffers.reserve(Buffers.size()); + for (const auto& [id, buffer] : Buffers) + { + allBuffers.push_back(buffer); + } + return allBuffers; +} + +Ref GPUResources::CreateMesh(const std::vector& vertices, const std::vector& indices) +{ + Ref mesh = CreateRef(vertices, indices); + Meshes[mesh->GetID()] = mesh; + return mesh; +} + +bool GPUResources::AddMesh(const Ref& 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 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 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 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 GPUResources::GetBindlessLayout() +{ + std::vector layouts = { + CameraDescriptorLayout, + ModelBufferDescriptorLayout, + TriangleBufferDescriptorLayout, + ImageDescriptorLayout, + SamplerDescriptorLayout, + MaterialDescriptorLayout + }; + return layouts; +} \ No newline at end of file diff --git a/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp b/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp index e41834f4..0f8d2aa4 100644 --- a/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp +++ b/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp @@ -17,6 +17,7 @@ #include #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 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); + //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) @@ -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); + GBufferPipeline.Build(); }