From 7e5a45de52cad75a3d7e17d8cacf226fe73c267f Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Fri, 10 Jan 2025 13:20:22 -0500 Subject: [PATCH] Manually tracking image layout transitions --- Editor/src/Windows/EditorInterface.cpp | 4 +- .../Vulkan/Pipeline/RenderPipeline.cpp | 132 +++++++++-------- .../Vulkan/VulkanImage/VulkanImage.cpp | 58 ++++++-- .../Vulkan/VulkanImage/VulkanImage.h | 56 +++++++- Nuake/src/Rendering/Vulkan/VulkanInit.cpp | 1 + Nuake/src/Rendering/Vulkan/VulkanRenderer.cpp | 23 ++- .../Rendering/Vulkan/VulkanSceneRenderer.cpp | 120 ++++++++-------- Resources/Shaders/Vulkan/shadow.frag | 136 ++++++++++++++++++ Resources/Shaders/Vulkan/shadow.vert | 89 ++++++++++++ 9 files changed, 470 insertions(+), 149 deletions(-) create mode 100644 Resources/Shaders/Vulkan/shadow.frag create mode 100644 Resources/Shaders/Vulkan/shadow.vert diff --git a/Editor/src/Windows/EditorInterface.cpp b/Editor/src/Windows/EditorInterface.cpp index bf7bcffe..40aebf9a 100644 --- a/Editor/src/Windows/EditorInterface.cpp +++ b/Editor/src/Windows/EditorInterface.cpp @@ -626,9 +626,9 @@ namespace Nuake { framebuffer->QueueResize(viewportPanelSize * Engine::GetProject()->Settings.ResolutionScale); Ref texture = framebuffer->GetTexture(); - VkDescriptorSet textureDesc = VkRenderer::Get().GetDrawImage()->GetImGuiDescriptorSet(); - auto& pipeline = VkRenderer::Get().GetRenderPipeline(); + VkDescriptorSet textureDesc = pipeline.GetRenderPass("Shading").GetAttachment("Output").Image->GetImGuiDescriptorSet(); + if (SelectedViewport == 1) { textureDesc = pipeline.GetRenderPass("GBuffer").GetAttachment("Albedo").Image->GetImGuiDescriptorSet(); diff --git a/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.cpp b/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.cpp index 5231ad7f..13f89fc9 100644 --- a/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.cpp +++ b/Nuake/src/Rendering/Vulkan/Pipeline/RenderPipeline.cpp @@ -43,7 +43,8 @@ void RenderPass::ClearAttachments(PassRenderContext& ctx) auto& gpuResources = GPUResources::Get(); gpuResources.AddTexture(newAttachment); - VulkanUtil::TransitionImage(ctx.commandBuffer, newAttachment->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); + newAttachment->TransitionLayout(ctx.commandBuffer, VK_IMAGE_LAYOUT_GENERAL); + //VulkanUtil::TransitionImage(ctx.commandBuffer, newAttachment->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); // TODO: Queue deletion of old textures } @@ -56,7 +57,8 @@ void RenderPass::ClearAttachments(PassRenderContext& ctx) auto& gpuResources = GPUResources::Get(); gpuResources.AddTexture(newDepthAttachment); - VulkanUtil::TransitionImage(ctx.commandBuffer, newDepthAttachment->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, true); + newDepthAttachment->TransitionLayout(ctx.commandBuffer, VK_IMAGE_LAYOUT_GENERAL); + //VulkanUtil::TransitionImage(ctx.commandBuffer, newDepthAttachment->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, true); } // Clear all color attachments @@ -75,13 +77,15 @@ 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); + //VulkanUtil::TransitionImage(ctx.commandBuffer, attachment.Image->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + attachment.Image->TransitionLayout(ctx.commandBuffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); } // Transition depth attachment if (DepthAttachment.Image) { - VulkanUtil::TransitionImage(ctx.commandBuffer, DepthAttachment.Image->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL); + //VulkanUtil::TransitionImage(ctx.commandBuffer, DepthAttachment.Image->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL); + //DepthAttachment.Image->TransitionLayout(ctx.commandBuffer, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL); } } @@ -90,8 +94,10 @@ void RenderPass::UntransitionAttachments(PassRenderContext& ctx) for (auto& attachment : Attachments) { // Transform from color attachment to transfer src for next pass - VulkanUtil::TransitionImage(ctx.commandBuffer, attachment.Image->GetImage(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - VulkanUtil::TransitionImage(ctx.commandBuffer, attachment.Image->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL); + //VulkanUtil::TransitionImage(ctx.commandBuffer, attachment.Image->GetImage(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + attachment.Image->TransitionLayout(ctx.commandBuffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + //VulkanUtil::TransitionImage(ctx.commandBuffer, attachment.Image->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL); + attachment.Image->TransitionLayout(ctx.commandBuffer, VK_IMAGE_LAYOUT_GENERAL); } if (DepthAttachment.Image) @@ -385,63 +391,64 @@ void RenderPipeline::Execute(PassRenderContext& ctx) std::vector transitionedInputs; for (auto& pass : RenderPasses) { + for (auto& input : pass.GetInputAttachments()) + { + VkImageMemoryBarrier barrier{}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - //for (auto& input : pass.GetInputAttachments()) - //{ - // VkImageMemoryBarrier barrier{}; - // barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - // - // // Handle old and new layouts based on attachment type - // barrier.oldLayout = input.Format != ImageFormat::D32F ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - // barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - // - // // Access masks for color or depth-stencil attachments - // if (input.Format != ImageFormat::D32F) { - // barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - // barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - // } - // else { - // barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - // barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - // - // // Include stencil aspect if applicable - // //if (input.HasStencilComponent()) { - // // barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - // //} - // } - // - // // Destination access mask is always for shaders reading - // barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - // - // // No queue family ownership transfer in this case - // barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - // barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - // - // // Set the image and subresource range - // barrier.image = input.Image->GetImage(); - // barrier.subresourceRange.baseMipLevel = 0; - // barrier.subresourceRange.levelCount = 1; - // barrier.subresourceRange.baseArrayLayer = 0; - // barrier.subresourceRange.layerCount = 1; - // - // // Choose appropriate source pipeline stage for color or depth-stencil - // VkPipelineStageFlags srcStage = (input.Format != ImageFormat::D32F) - // ? VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT - // : (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT); - // - // // Insert the pipeline barrier - // vkCmdPipelineBarrier( - // ctx.commandBuffer, - // srcStage, // Source stage - // VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // Destination stage - // 0, - // 0, nullptr, - // 0, nullptr, - // 1, &barrier - // ); + // Handle old and new layouts based on attachment type + barrier.oldLayout = input.Format != ImageFormat::D32F ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + input.Image->SetLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - // transitionedInputs.push_back(input); - //} + // Access masks for color or depth-stencil attachments + if (input.Format != ImageFormat::D32F) { + barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + else { + barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + + // Include stencil aspect if applicable + //if (input.HasStencilComponent()) { + // barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + //} + } + + // Destination access mask is always for shaders reading + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + // No queue family ownership transfer in this case + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + + // Set the image and subresource range + barrier.image = input.Image->GetImage(); + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + + // Choose appropriate source pipeline stage for color or depth-stencil + VkPipelineStageFlags srcStage = (input.Format != ImageFormat::D32F) + ? VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT + : (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT); + + // Insert the pipeline barrier + vkCmdPipelineBarrier( + ctx.commandBuffer, + srcStage, // Source stage + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // Destination stage + 0, + 0, nullptr, + 0, nullptr, + 1, &barrier + ); + + transitionedInputs.push_back(input); + } pass.ClearAttachments(ctx); pass.TransitionAttachments(ctx); @@ -461,7 +468,8 @@ void RenderPipeline::Execute(PassRenderContext& ctx) } else { - VulkanUtil::TransitionImage(ctx.commandBuffer, transitionedOutputs.Image->GetImage(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL); + //VulkanUtil::TransitionImage(ctx.commandBuffer, transitionedOutputs.Image->GetImage(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL); + transitionedOutputs.Image->TransitionLayout(ctx.commandBuffer, VK_IMAGE_LAYOUT_GENERAL); } } diff --git a/Nuake/src/Rendering/Vulkan/VulkanImage/VulkanImage.cpp b/Nuake/src/Rendering/Vulkan/VulkanImage/VulkanImage.cpp index 09f961f2..b6d80bab 100644 --- a/Nuake/src/Rendering/Vulkan/VulkanImage/VulkanImage.cpp +++ b/Nuake/src/Rendering/Vulkan/VulkanImage/VulkanImage.cpp @@ -65,7 +65,8 @@ VulkanImage::VulkanImage(const std::string & path) : // Transition image and copy data to GPU VkRenderer::Get().ImmediateSubmit([&](VkCommandBuffer cmd) { - VulkanUtil::TransitionImage(cmd, Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + TransitionLayout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + //VulkanUtil::TransitionImage(cmd, Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); VkBufferImageCopy copyRegion = {}; copyRegion.bufferOffset = 0; @@ -80,7 +81,8 @@ VulkanImage::VulkanImage(const std::string & path) : vkCmdCopyBufferToImage(cmd, uploadBuffer->GetBuffer(), Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); - VulkanUtil::TransitionImage(cmd, Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + TransitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + //VulkanUtil::TransitionImage(cmd, Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); }); } @@ -88,7 +90,8 @@ VulkanImage::VulkanImage(ImageFormat inFormat, Vector2 inSize, ImageUsage usage) Format(inFormat), Extent(inSize, 1), ImGuiDescriptorSetGenerated(false), - ID(UUID()) + ID(UUID()), + Usage(usage) { VkExtent3D vkExtent = { @@ -177,8 +180,8 @@ VulkanImage::VulkanImage(void* inData, ImageFormat inFormat, Vector2 inSize) : V VkRenderer::Get().ImmediateSubmit([&](VkCommandBuffer cmd) { - VulkanUtil::TransitionImage(cmd, Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - + //VulkanUtil::TransitionImage(cmd, Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + TransitionLayout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); VkBufferImageCopy copyRegion = {}; copyRegion.bufferOffset = 0; copyRegion.bufferRowLength = 0; @@ -192,8 +195,8 @@ VulkanImage::VulkanImage(void* inData, ImageFormat inFormat, Vector2 inSize) : V vkCmdCopyBufferToImage(cmd, uploadBuffer->GetBuffer(), Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); - - VulkanUtil::TransitionImage(cmd, Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + TransitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + //VulkanUtil::TransitionImage(cmd, Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); } ); @@ -252,8 +255,8 @@ VulkanImage::VulkanImage(void* inData, size_t inSize) : // Transition image and copy data to GPU VkRenderer::Get().ImmediateSubmit([&](VkCommandBuffer cmd) { - VulkanUtil::TransitionImage(cmd, Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - + //VulkanUtil::TransitionImage(cmd, Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + TransitionLayout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); VkBufferImageCopy copyRegion = {}; copyRegion.bufferOffset = 0; copyRegion.bufferRowLength = 0; @@ -266,8 +269,8 @@ VulkanImage::VulkanImage(void* inData, size_t inSize) : copyRegion.imageExtent = vkExtent; vkCmdCopyBufferToImage(cmd, uploadBuffer->GetBuffer(), Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); - - VulkanUtil::TransitionImage(cmd, Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + TransitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + //VulkanUtil::TransitionImage(cmd, Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); }); } @@ -276,6 +279,39 @@ VulkanImage::~VulkanImage() // TODO: deletion of image } +void VulkanImage::TransitionLayout(VkCommandBuffer cmd, VkImageLayout layout) +{ + if(!IsLayoutTransitionValid(Layout, layout)) + { + throw std::runtime_error("Invalid layout transition!"); + } + + VkImageMemoryBarrier2 imageBarrier{ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 }; + imageBarrier.pNext = nullptr; + + imageBarrier.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT; + imageBarrier.srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT; + imageBarrier.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT; + imageBarrier.dstAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT | VK_ACCESS_2_MEMORY_READ_BIT; + imageBarrier.oldLayout = Layout; + imageBarrier.newLayout = layout; + + VkImageAspectFlags aspectMask = (layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL || Usage == ImageUsage::Depth) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; + imageBarrier.subresourceRange = VulkanInit::ImageSubResourceRange(aspectMask); + imageBarrier.image = GetImage(); + + VkDependencyInfo depInfo{}; + depInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + depInfo.pNext = nullptr; + + depInfo.imageMemoryBarrierCount = 1; + depInfo.pImageMemoryBarriers = &imageBarrier; + + vkCmdPipelineBarrier2(cmd, &depInfo); + + Layout = layout; +} + VkDescriptorSet& VulkanImage::GetImGuiDescriptorSet() { if (!ImGuiDescriptorSetGenerated) diff --git a/Nuake/src/Rendering/Vulkan/VulkanImage/VulkanImage.h b/Nuake/src/Rendering/Vulkan/VulkanImage/VulkanImage.h index fa7a3a9e..bbb109c5 100644 --- a/Nuake/src/Rendering/Vulkan/VulkanImage/VulkanImage.h +++ b/Nuake/src/Rendering/Vulkan/VulkanImage/VulkanImage.h @@ -43,10 +43,10 @@ namespace Nuake Vector3 Extent; ImageFormat Format; VkSampler Sampler; - + VkImageLayout Layout = VK_IMAGE_LAYOUT_UNDEFINED; bool ImGuiDescriptorSetGenerated; VkDescriptorSet ImGuiDescriptorSet; - + ImageUsage Usage; public: VulkanImage(const std::string& path); VulkanImage(ImageFormat format, Vector2 size, ImageUsage usage = ImageUsage::Default); @@ -55,6 +55,8 @@ namespace Nuake ~VulkanImage(); + void TransitionLayout(VkCommandBuffer cmd, VkImageLayout layout); + Vector2 GetSize() const { return Vector2(Extent.x, Extent.y); } int GetWidth() const { return static_cast(Extent.x); } int GetHeight() const { return static_cast(Extent.y); } @@ -64,5 +66,55 @@ namespace Nuake VkImage GetImage() { return Image; } VkDescriptorSet& GetImGuiDescriptorSet(); ImageFormat GetFormat() const { return Format; } + VkImageLayout GetLayout() const { return Layout; } + void SetLayout(VkImageLayout layout) { Layout = layout; } + + bool IsLayoutTransitionValid(VkImageLayout oldLayout, VkImageLayout newLayout) { + switch (oldLayout) { + case VK_IMAGE_LAYOUT_UNDEFINED: + // Any layout is valid after VK_IMAGE_LAYOUT_UNDEFINED + return true; + + case VK_IMAGE_LAYOUT_PREINITIALIZED: + // Only certain layouts are valid after VK_IMAGE_LAYOUT_PREINITIALIZED + return newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL || + newLayout == VK_IMAGE_LAYOUT_GENERAL; + + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + // Valid transitions for color attachments + return newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR || + newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + // Valid transitions for transfer source + return newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL || + newLayout == VK_IMAGE_LAYOUT_GENERAL; + + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + // Valid transitions for transfer destination + return newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL || + newLayout == VK_IMAGE_LAYOUT_GENERAL; + + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + // Valid transitions for shader read-only + return newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL || + newLayout == VK_IMAGE_LAYOUT_GENERAL; + + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + // Only transition to COLOR_ATTACHMENT_OPTIMAL for reuse + return newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + case VK_IMAGE_LAYOUT_GENERAL: + // General layout can transition to almost anything + return newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL || + newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL || + newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL || + newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL || + newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + default: + // Add other cases as needed + return false; + } + } }; } \ No newline at end of file diff --git a/Nuake/src/Rendering/Vulkan/VulkanInit.cpp b/Nuake/src/Rendering/Vulkan/VulkanInit.cpp index 2d4191b8..6480b8ba 100644 --- a/Nuake/src/Rendering/Vulkan/VulkanInit.cpp +++ b/Nuake/src/Rendering/Vulkan/VulkanInit.cpp @@ -1,4 +1,5 @@ #include "VulkanInit.h" +#include "VulkanImage\VulkanImage.h" using namespace Nuake; diff --git a/Nuake/src/Rendering/Vulkan/VulkanRenderer.cpp b/Nuake/src/Rendering/Vulkan/VulkanRenderer.cpp index 57011072..9d1c85e9 100644 --- a/Nuake/src/Rendering/Vulkan/VulkanRenderer.cpp +++ b/Nuake/src/Rendering/Vulkan/VulkanRenderer.cpp @@ -770,21 +770,17 @@ bool VkRenderer::Draw() // Create commands VK_CALL(vkBeginCommandBuffer(cmd, &cmdBeginInfo)); // Transfer rendering image to general layout - VulkanUtil::TransitionImage(cmd, DrawImage->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - // Execute compute shader that writes to the image - //vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, Pipeline); - //vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, PipelineLayout, 0, 1, &DrawImageDescriptors, 0, nullptr); - - VulkanUtil::TransitionImage(cmd, DrawImage->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - //vkCmdDispatch(cmd, std::ceil(DrawExtent.width / 16.0), std::ceil(DrawExtent.height / 16.0), 1); - //DrawBackground(cmd); + DrawImage->TransitionLayout(cmd, VK_IMAGE_LAYOUT_GENERAL); + //VulkanUtil::TransitionImage(cmd, DrawImage->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); // Transition rendering iamge to transfert onto swapchain images //VulkanUtil::TransitionImage(cmd, DrawImage->GetImage(), VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + //SwapchainImages[swapchainImageIndex]->TransitionLayout(cmd, VK_IMAGE_LAYOUT_GENERAL); + //DepthImage->TransitionLayout(cmd, VK_IMAGE_LAYOUT_GENERAL); VulkanUtil::TransitionImage(cmd, SwapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - VulkanUtil::TransitionImage(cmd, DepthImage->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL); + //VulkanUtil::TransitionImage(cmd, DepthImage->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL); //DrawGeometry(cmd); @@ -799,19 +795,18 @@ void VkRenderer::EndDraw() } VkCommandBuffer cmd = GetCurrentFrame().CommandBuffer; - VulkanUtil::TransitionImage(cmd, DrawImage->GetImage(), VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); //draw imgui into the swapchain image - DrawImgui(cmd, SwapchainImageViews[swapchainImageIndex]); // set swapchain image layout to Attachment Optimal so we can draw it VulkanUtil::TransitionImage(cmd, SwapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - // set swapchain image layout to Present so we can draw it - VulkanUtil::TransitionImage(cmd, SwapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + DrawImage->TransitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + // VulkanUtil::TransitionImage(cmd, DrawImage->GetImage(), VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + DrawImgui(cmd, SwapchainImageViews[swapchainImageIndex]); // Transition the swapchain image to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR for presentation - VulkanUtil::TransitionImage(cmd, SwapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + VulkanUtil::TransitionImage(cmd, SwapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); VK_CALL(vkEndCommandBuffer(cmd)); VkCommandBufferSubmitInfo cmdinfo = VulkanInit::CommandBufferSubmitInfo(cmd); diff --git a/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp b/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp index a1476597..4fab4d9f 100644 --- a/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp +++ b/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp @@ -100,11 +100,15 @@ void VkSceneRenderer::EndScene() auto& normal = GBufferPipeline.GetRenderPass("GBuffer").GetAttachment("Normal"); auto& shading = GBufferPipeline.GetRenderPass("Shading").GetAttachment("Output"); auto& selectedOutput = shading; - VulkanUtil::TransitionImage(cmd, selectedOutput.Image->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - VulkanUtil::TransitionImage(cmd, vk.DrawImage->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + selectedOutput.Image->TransitionLayout(cmd, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + vk.DrawImage->TransitionLayout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + //VulkanUtil::TransitionImage(cmd, selectedOutput.Image->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + //VulkanUtil::TransitionImage(cmd, vk.DrawImage->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); VulkanUtil::CopyImageToImage(cmd, selectedOutput.Image->GetImage(), vk.GetDrawImage()->GetImage(), selectedOutput.Image->GetSize(), vk.DrawImage->GetSize()); - VulkanUtil::TransitionImage(cmd, vk.DrawImage->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL); - VulkanUtil::TransitionImage(cmd, selectedOutput.Image->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL); + vk.DrawImage->TransitionLayout(cmd, VK_IMAGE_LAYOUT_GENERAL); + selectedOutput.Image->TransitionLayout(cmd, VK_IMAGE_LAYOUT_GENERAL); + //VulkanUtil::TransitionImage(cmd, vk.DrawImage->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL); + //VulkanUtil::TransitionImage(cmd, selectedOutput.Image->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL); } void VkSceneRenderer::CreateBuffers() @@ -258,60 +262,60 @@ void VkSceneRenderer::CreateDescriptors() void VkSceneRenderer::CreatePipelines() { - ShadowPipeline = RenderPipeline(); - auto& shadowPass = ShadowPipeline.AddPass("Shadow"); - shadowPass.AddAttachment("Depth", ImageFormat::D32F, ImageUsage::Depth); - shadowPass.SetShaders(Shaders["shading_vert"], Shaders["shading_frag"]); - shadowPass.SetPreRender([&](PassRenderContext& ctx) { - std::vector descriptors2 = { CameraBufferDescriptors, ModelBufferDescriptor }; - vkCmdBindDescriptorSets( - ctx.commandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - ctx.renderPass->PipelineLayout, - 0, // firstSet - 2, // descriptorSetCount - descriptors2.data(), // pointer to the descriptor set(s) - 0, // dynamicOffsetCount - nullptr // dynamicOffsets - ); - - // Bind material - vkCmdBindDescriptorSets( - ctx.commandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - ctx.renderPass->PipelineLayout, - 4, // firstSet - 1, // descriptorSetCount - &MaterialBufferDescriptor, // pointer to the descriptor set(s) - 0, // dynamicOffsetCount - nullptr // dynamicOffsets - ); - - vkCmdBindDescriptorSets( - ctx.commandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - ctx.renderPass->PipelineLayout, - 5, // firstSet - 1, // descriptorSetCount - &GPUResources::Get().TextureDescriptor, // pointer to the descriptor set(s) - 0, // dynamicOffsetCount - nullptr // dynamicOffsets - ); - - vkCmdBindDescriptorSets( - ctx.commandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - ctx.renderPass->PipelineLayout, - 6, // firstSet - 1, // descriptorSetCount - &LightBufferDescriptor, // pointer to the descriptor set(s) - 0, // dynamicOffsetCount - nullptr // dynamicOffsets - ); - - vkCmdBindDescriptorSets(ctx.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx.renderPass->PipelineLayout, 3, 1, &SamplerDescriptor, 0, nullptr); - }); - shadowPass.SetRender([&](PassRenderContext& ctx) {}); + //ShadowPipeline = RenderPipeline(); + //auto& shadowPass = ShadowPipeline.AddPass("Shadow"); + //shadowPass.AddAttachment("Depth", ImageFormat::D32F, ImageUsage::Depth); + //shadowPass.SetShaders(Shaders["shading_vert"], Shaders["shading_frag"]); + //shadowPass.SetPreRender([&](PassRenderContext& ctx) { + // std::vector descriptors2 = { CameraBufferDescriptors, ModelBufferDescriptor }; + // vkCmdBindDescriptorSets( + // ctx.commandBuffer, + // VK_PIPELINE_BIND_POINT_GRAPHICS, + // ctx.renderPass->PipelineLayout, + // 0, // firstSet + // 2, // descriptorSetCount + // descriptors2.data(), // pointer to the descriptor set(s) + // 0, // dynamicOffsetCount + // nullptr // dynamicOffsets + // ); + // + // // Bind material + // vkCmdBindDescriptorSets( + // ctx.commandBuffer, + // VK_PIPELINE_BIND_POINT_GRAPHICS, + // ctx.renderPass->PipelineLayout, + // 4, // firstSet + // 1, // descriptorSetCount + // &MaterialBufferDescriptor, // pointer to the descriptor set(s) + // 0, // dynamicOffsetCount + // nullptr // dynamicOffsets + // ); + // + // vkCmdBindDescriptorSets( + // ctx.commandBuffer, + // VK_PIPELINE_BIND_POINT_GRAPHICS, + // ctx.renderPass->PipelineLayout, + // 5, // firstSet + // 1, // descriptorSetCount + // &GPUResources::Get().TextureDescriptor, // pointer to the descriptor set(s) + // 0, // dynamicOffsetCount + // nullptr // dynamicOffsets + // ); + // + // vkCmdBindDescriptorSets( + // ctx.commandBuffer, + // VK_PIPELINE_BIND_POINT_GRAPHICS, + // ctx.renderPass->PipelineLayout, + // 6, // firstSet + // 1, // descriptorSetCount + // &LightBufferDescriptor, // pointer to the descriptor set(s) + // 0, // dynamicOffsetCount + // nullptr // dynamicOffsets + // ); + // + // vkCmdBindDescriptorSets(ctx.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx.renderPass->PipelineLayout, 3, 1, //&SamplerDescriptor, 0, nullptr); + //}); + //shadowPass.SetRender([&](PassRenderContext& ctx) {}); GBufferPipeline = RenderPipeline(); diff --git a/Resources/Shaders/Vulkan/shadow.frag b/Resources/Shaders/Vulkan/shadow.frag new file mode 100644 index 00000000..69163454 --- /dev/null +++ b/Resources/Shaders/Vulkan/shadow.frag @@ -0,0 +1,136 @@ +struct Camera +{ + float4x4 view; + float4x4 proj; + float4x4 invView; + float4x4 invProj; + float3 position; +}; +[[vk::binding(0, 0)]] +StructuredBuffer camera : register(t0); + +[[vk::binding(0, 3)]] +SamplerState mySampler : register(s0); // Sampler binding at slot s0 + +struct Material +{ + float hasAlbedo; + float3 albedo; + int hasNormal; + int hasMetalness; + int hasRoughness; + int hasAO; + float metalnessValue; + float roughnessValue; + float aoValue; + int albedoTextureId; + int normalTextureId; + int metalnessTextureId; + int roughnessTextureId; + int aoTextureId; +}; + +[[vk::binding(0, 4)]] +StructuredBuffer material; // array de 2000 materials + +[[vk::binding(0, 5)]] +Texture2D textures[]; // Array de 500 textures + +struct Light +{ + float3 position; + int type; + float4 color; + float3 direction; + float outerConeAngle; + float innerConeAngle; + bool castShadow; + int shadowMapTextureId; + int transformId; +}; + +[[vk::binding(0, 6)]] +StructuredBuffer lights; + +struct PSInput { + float4 Position : SV_Position; + float3 Color : TEXCOORD0; + float2 UV : TEXCOORD1; + float3 Normal : TEXCOORD2; + float3x3 TBN : TEXCOORD3; +}; + +struct PSOutput { + float4 oColor0 : SV_TARGET; + float4 oNormal : SV_TARGET1; + float4 oMaterial : SV_TARGET2; +}; + +struct ModelPushConstant +{ + int modelIndex; // Push constant data + int materialIndex; +}; + +[[vk::push_constant]] +ModelPushConstant pushConstants; + +PSOutput main(PSInput input) +{ + PSOutput output; + + Material inMaterial = material[pushConstants.materialIndex]; + // NORMAL + // TODO use TBN matrix + float3 normal = float3(0.5, 0.5, 1.0); + if(inMaterial.hasNormal == 1) + { + // Sample from texture. + } + + normal = mul(input.TBN, normal); + normal = input.Normal / 2.0f + 0.5f; + output.oNormal = float4(normal, 1.0f); + + // MATERIAL + + // ALBEDO COLOR + float4 albedoColor = float4(inMaterial.albedo.xyz, 1.0f); + if(inMaterial.hasAlbedo == 1) + { + float4 albedoSample = textures[inMaterial.albedoTextureId].Sample(mySampler, input.UV); + + // Alpha cutout? + if(albedoSample.a < 0.001f) + { + discard; + } + + albedoColor.xyz = albedoSample.xyz; + } + output.oColor0 = albedoColor; + + // MATERIAL PROPERTIES + float metalnessValue = inMaterial.metalnessValue; + if(inMaterial.hasMetalness == 1) + { + // TODO: Sample from metal texture + } + + float aoValue = inMaterial.aoValue; + if(inMaterial.hasAO == 1) + { + // TODO: Sample from AO texture + } + + float roughnessValue = inMaterial.roughnessValue; + if(inMaterial.hasRoughness == 1) + { + // TODO: Sample from roughness texture + } + + float3 materialOuput = float3(inMaterial.metalnessValue, inMaterial.aoValue, inMaterial.roughnessValue); + + output.oMaterial = float4(materialOuput, 1.0f); + return output; +} \ No newline at end of file diff --git a/Resources/Shaders/Vulkan/shadow.vert b/Resources/Shaders/Vulkan/shadow.vert new file mode 100644 index 00000000..2cafa98c --- /dev/null +++ b/Resources/Shaders/Vulkan/shadow.vert @@ -0,0 +1,89 @@ +struct Camera +{ + float4x4 view; + float4x4 proj; + float4x4 invView; + float4x4 invProj; + float3 position; +}; +[[vk::binding(0, 0)]] +StructuredBuffer camera : register(t0); + +struct ModelData +{ + float4x4 model; +}; +[[vk::binding(0, 1)]] +StructuredBuffer model : register(t1); + +struct Vertex +{ + float3 position; + float uv_x; + float3 normal; + float uv_y; + float3 tangent; + float3 bitangent; +}; + +[[vk::binding(0, 2)]] +StructuredBuffer vertexBuffer : register(t2); + +struct ModelPushConstant +{ + int modelIndex; // Push constant data + int materialIndex; +}; + +struct Light +{ + float3 position; + int type; + float4 color; + float3 direction; + float outerConeAngle; + float innerConeAngle; + bool castShadow; + int shadowMapTextureId; + int transformId; +}; + +[[vk::binding(0, 6)]] +StructuredBuffer lights; + +[[vk::push_constant]] +ModelPushConstant pushConstants; + +// Outputs +struct VSOutput { + float4 Position : SV_Position; + float3 Color : TEXCOORD0; + float2 UV : TEXCOORD1; + float3 Normal : TEXCOORD2; + float3x3 TBN : TEXCOORD3; +}; + +// Main vertex shader +VSOutput main(uint vertexIndex : SV_VertexID) +{ + VSOutput output; + + Camera camData = camera[0]; + + ModelData modelData = model[pushConstants.modelIndex]; + + // Load vertex data from the buffer + Vertex v = vertexBuffer[vertexIndex]; + + // Output the position of each vertex + output.Position = mul(camData.proj, mul(camData.view, mul(modelData.model, float4(v.position, 1.0f)))); + output.Color = normalize(float3(v.position.xyz)); + output.UV = float2(v.uv_x, v.uv_y); + output.Normal = normalize(v.normal); + + float3 T = normalize(mul((float3x3)modelData.model, normalize(v.tangent.xyz))); + float3 B = normalize(mul((float3x3)modelData.model, normalize(v.bitangent.xyz))); + float3 N = normalize(mul((float3x3)modelData.model, normalize(v.normal)).xyz); + output.TBN = transpose(float3x3(T, B, N)); + return output; +} \ No newline at end of file