From d058a127e11dea76b037c3d217cb80062fb32044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Mon, 15 Feb 2021 18:14:47 +0100 Subject: [PATCH] Renderer/RenderPass: Implement RenderPass correctly --- .../OpenGLRenderer/OpenGLRenderPass.hpp | 2 +- include/Nazara/Renderer/Enums.hpp | 113 +++++++++-- include/Nazara/Renderer/RenderPass.hpp | 51 ++++- include/Nazara/Renderer/RenderPass.inl | 33 ++++ include/Nazara/VulkanRenderer/Utils.hpp | 11 ++ include/Nazara/VulkanRenderer/Utils.inl | 166 ++++++++++++++++- .../VulkanRenderer/VulkanRenderPass.hpp | 4 +- .../VulkanRenderer/VulkanRenderPass.inl | 11 -- src/Nazara/VulkanRenderer/VkRenderWindow.cpp | 175 +++++++++--------- .../VulkanCommandBufferBuilder.cpp | 2 +- .../VulkanRenderer/VulkanRenderPass.cpp | 108 +++++++++++ 11 files changed, 543 insertions(+), 133 deletions(-) diff --git a/include/Nazara/OpenGLRenderer/OpenGLRenderPass.hpp b/include/Nazara/OpenGLRenderer/OpenGLRenderPass.hpp index 8c4ff18cd..d60870578 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLRenderPass.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLRenderPass.hpp @@ -17,7 +17,7 @@ namespace Nz class NAZARA_OPENGLRENDERER_API OpenGLRenderPass final : public RenderPass { public: - OpenGLRenderPass() = default; + using RenderPass::RenderPass; OpenGLRenderPass(const OpenGLRenderPass&) = delete; OpenGLRenderPass(OpenGLRenderPass&&) noexcept = default; ~OpenGLRenderPass() = default; diff --git a/include/Nazara/Renderer/Enums.hpp b/include/Nazara/Renderer/Enums.hpp index 0b44ae629..2e3f95286 100644 --- a/include/Nazara/Renderer/Enums.hpp +++ b/include/Nazara/Renderer/Enums.hpp @@ -11,6 +11,96 @@ namespace Nz { + enum class AttachmentLoadOp + { + Clear, + Discard, + Load + }; + + enum class AttachmentStoreOp + { + Discard, + Store + }; + + enum class MemoryAccess + { + ColorRead, + ColorWrite, + DepthStencilRead, + DepthStencilWrite, + IndexBufferRead, + IndirectCommandRead, + HostRead, + HostWrite, + MemoryRead, + MemoryWrite, + ShaderRead, + ShaderWrite, + TransferRead, + TransferWrite, + UniformBufferRead, + VertexBufferRead, + + Max = VertexBufferRead + }; + + template<> + struct EnumAsFlags + { + static constexpr MemoryAccess max = MemoryAccess::Max; + }; + + using MemoryAccessFlags = Flags; + + enum class PipelineStage + { + TopOfPipe, + + ColorOutput, + DrawIndirect, + FragmentShader, + FragmentTestsEarly, + FragmentTestsLate, + GeometryShader, + TessellationControlShader, + TessellationEvaluationShader, + Transfer, + TransformFeedback, + VertexInput, + VertexShader, + + BottomOfPipe, + + Max = BottomOfPipe + }; + + template<> + struct EnumAsFlags + { + static constexpr PipelineStage max = PipelineStage::Max; + }; + + using PipelineStageFlags = Flags; + + enum class QueueType + { + Compute, + Graphics, + Transfer, + + Max = Transfer + }; + + template<> + struct EnumAsFlags + { + static constexpr QueueType max = QueueType::Max; + }; + + using QueueTypeFlags = Flags; + enum class RenderAPI { Direct3D, ///< Microsoft Render API, only works on MS platforms @@ -53,22 +143,17 @@ namespace Nz SpirV }; - enum class QueueType + enum class TextureLayout { - Compute, - Graphics, - Transfer, - - Max = Transfer + ColorInput, + ColorOutput, + DepthStencilInput, + DepthStencilOutput, + Present, + TransferSource, + TransferDestination, + Undefined }; - - template<> - struct EnumAsFlags - { - static constexpr QueueType max = QueueType::Max; - }; - - using QueueTypeFlags = Flags; } #endif // NAZARA_ENUMS_RENDERER_HPP diff --git a/include/Nazara/Renderer/RenderPass.hpp b/include/Nazara/Renderer/RenderPass.hpp index 10f57ddbe..d971069e2 100644 --- a/include/Nazara/Renderer/RenderPass.hpp +++ b/include/Nazara/Renderer/RenderPass.hpp @@ -11,6 +11,9 @@ #include #include #include +#include +#include +#include namespace Nz { @@ -18,20 +21,64 @@ namespace Nz { public: struct Attachment; + struct SubpassDependency; + struct SubpassDescription; - RenderPass() = default; + inline RenderPass(std::vector attachments, std::vector subpassDescriptions, std::vector subpassDependencies); RenderPass(const RenderPass&) = delete; RenderPass(RenderPass&&) noexcept = default; virtual ~RenderPass(); + inline const Attachment& GetAttachment(std::size_t attachmentIndex) const; + inline std::size_t GetAttachmentCount() const; + inline const std::vector& GetAttachments() const; + inline const std::vector& GetSubpassDescriptions() const; + inline const std::vector& GetsubpassDependencies() const; + RenderPass& operator=(const RenderPass&) = delete; RenderPass& operator=(RenderPass&&) noexcept = default; struct Attachment { PixelFormat format; - // TODO + AttachmentLoadOp loadOp = AttachmentLoadOp::Load; + AttachmentLoadOp stencilLoadOp = AttachmentLoadOp::Load; + AttachmentStoreOp storeOp = AttachmentStoreOp::Store; + AttachmentStoreOp stencilStoreOp = AttachmentStoreOp::Store; + TextureLayout initialLayout = TextureLayout::Undefined; + TextureLayout finalLayout = TextureLayout::Present; }; + + struct AttachmentReference + { + std::size_t attachmentIndex; + TextureLayout attachmentLayout = TextureLayout::ColorInput; + }; + + struct SubpassDependency + { + std::size_t fromSubpassIndex; + PipelineStageFlags fromStages; + MemoryAccessFlags fromAccessFlags; + std::size_t toSubpassIndex; + PipelineStageFlags toStages; + MemoryAccessFlags toAccessFlags; + bool tilable = false; + }; + + struct SubpassDescription + { + std::vector colorAttachment; + std::vector inputAttachments; + std::optional depthStencilAttachment; + }; + + static constexpr std::size_t ExternalSubpassIndex = std::numeric_limits::max(); + + protected: + std::vector m_attachments; + std::vector m_subpassDependencies; + std::vector m_subpassDescriptions; }; } diff --git a/include/Nazara/Renderer/RenderPass.inl b/include/Nazara/Renderer/RenderPass.inl index c2c3865a3..a7360cd30 100644 --- a/include/Nazara/Renderer/RenderPass.inl +++ b/include/Nazara/Renderer/RenderPass.inl @@ -3,10 +3,43 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include namespace Nz { + inline RenderPass::RenderPass(std::vector attachments, std::vector subpassDescriptions, std::vector subpassDependencies) : + m_attachments(std::move(attachments)), + m_subpassDescriptions(std::move(subpassDescriptions)), + m_subpassDependencies(std::move(subpassDependencies)) + { + } + + inline auto Nz::RenderPass::GetAttachment(std::size_t attachmentIndex) const -> const Attachment& + { + assert(attachmentIndex < m_attachments.size()); + return m_attachments[attachmentIndex]; + } + + inline std::size_t RenderPass::GetAttachmentCount() const + { + return m_attachments.size(); + } + + inline auto RenderPass::GetAttachments() const -> const std::vector& + { + return m_attachments; + } + + inline auto RenderPass::GetSubpassDescriptions() const -> const std::vector& + { + return m_subpassDescriptions; + } + + inline auto RenderPass::GetsubpassDependencies() const -> const std::vector& + { + return m_subpassDependencies; + } } #include diff --git a/include/Nazara/VulkanRenderer/Utils.hpp b/include/Nazara/VulkanRenderer/Utils.hpp index c1267da83..b337d3d10 100644 --- a/include/Nazara/VulkanRenderer/Utils.hpp +++ b/include/Nazara/VulkanRenderer/Utils.hpp @@ -11,14 +11,24 @@ #include #include #include +#include #include namespace Nz { + inline std::optional FromVulkan(VkFormat format); + + inline VkAttachmentLoadOp ToVulkan(AttachmentLoadOp loadOp); + inline VkAttachmentStoreOp ToVulkan(AttachmentStoreOp storeOp); inline VkBufferUsageFlags ToVulkan(BufferType bufferType); inline VkFormat ToVulkan(ComponentType componentType); inline VkCullModeFlagBits ToVulkan(FaceSide faceSide); inline VkPolygonMode ToVulkan(FaceFilling faceFilling); + inline VkAccessFlagBits ToVulkan(MemoryAccess memoryAccess); + inline VkAccessFlags ToVulkan(MemoryAccessFlags memoryAccessFlags); + inline VkPipelineStageFlagBits ToVulkan(PipelineStage pipelineStage); + inline VkPipelineStageFlags ToVulkan(PipelineStageFlags pipelineStages); + inline VkFormat ToVulkan(PixelFormat pixelFormat); inline VkPrimitiveTopology ToVulkan(PrimitiveMode primitiveMode); inline VkCompareOp ToVulkan(RendererComparison comparison); inline VkFilter ToVulkan(SamplerFilter samplerFilter); @@ -28,6 +38,7 @@ namespace Nz inline VkShaderStageFlagBits ToVulkan(ShaderStageType stageType); inline VkShaderStageFlags ToVulkan(ShaderStageTypeFlags stageType); inline VkStencilOp ToVulkan(StencilOperation stencilOp); + inline VkImageLayout ToVulkan(TextureLayout textureLayout); inline VkVertexInputRate ToVulkan(VertexInputRate inputRate); NAZARA_VULKANRENDERER_API std::string TranslateVulkanError(VkResult code); diff --git a/include/Nazara/VulkanRenderer/Utils.inl b/include/Nazara/VulkanRenderer/Utils.inl index 242e7c6e0..90eba6933 100644 --- a/include/Nazara/VulkanRenderer/Utils.inl +++ b/include/Nazara/VulkanRenderer/Utils.inl @@ -10,6 +10,45 @@ namespace Nz { + std::optional FromVulkan(VkFormat format) + { + switch (format) + { + case VK_FORMAT_B8G8R8A8_UNORM: return PixelFormat::PixelFormat_BGRA8; + case VK_FORMAT_D24_UNORM_S8_UINT: return PixelFormat::PixelFormat_Depth24Stencil8; + case VK_FORMAT_D32_SFLOAT: return PixelFormat::PixelFormat_Depth32; + case VK_FORMAT_R8G8B8A8_UNORM: return PixelFormat::PixelFormat_RGBA8; + default: break; + } + + return std::nullopt; + } + + VkAttachmentLoadOp ToVulkan(AttachmentLoadOp loadOp) + { + switch (loadOp) + { + case AttachmentLoadOp::Clear: return VK_ATTACHMENT_LOAD_OP_CLEAR; + case AttachmentLoadOp::Discard: return VK_ATTACHMENT_LOAD_OP_DONT_CARE; + case AttachmentLoadOp::Load: return VK_ATTACHMENT_LOAD_OP_LOAD; + } + + NazaraError("Unhandled AttachmentLoadOp 0x" + NumberToString(UnderlyingCast(loadOp), 16)); + return {}; + } + + VkAttachmentStoreOp ToVulkan(AttachmentStoreOp storeOp) + { + switch (storeOp) + { + case AttachmentStoreOp::Discard: return VK_ATTACHMENT_STORE_OP_DONT_CARE; + case AttachmentStoreOp::Store: return VK_ATTACHMENT_STORE_OP_STORE; + } + + NazaraError("Unhandled AttachmentStoreOp 0x" + NumberToString(UnderlyingCast(storeOp), 16)); + return {}; + } + inline VkBufferUsageFlags ToVulkan(BufferType bufferType) { switch (bufferType) @@ -73,6 +112,97 @@ namespace Nz NazaraError("Unhandled FaceFilling 0x" + NumberToString(faceFilling, 16)); return VK_POLYGON_MODE_FILL; } + + inline VkAccessFlagBits ToVulkan(MemoryAccess memoryAccess) + { + switch (memoryAccess) + { + case MemoryAccess::ColorRead: return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + case MemoryAccess::ColorWrite: return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + case MemoryAccess::DepthStencilRead: return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + case MemoryAccess::DepthStencilWrite: return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + case MemoryAccess::IndexBufferRead: return VK_ACCESS_INDEX_READ_BIT; + case MemoryAccess::IndirectCommandRead: return VK_ACCESS_INDIRECT_COMMAND_READ_BIT; + case MemoryAccess::HostRead: return VK_ACCESS_HOST_READ_BIT; + case MemoryAccess::HostWrite: return VK_ACCESS_HOST_WRITE_BIT; + case MemoryAccess::MemoryRead: return VK_ACCESS_MEMORY_READ_BIT; + case MemoryAccess::MemoryWrite: return VK_ACCESS_MEMORY_WRITE_BIT; + case MemoryAccess::ShaderRead: return VK_ACCESS_SHADER_READ_BIT; + case MemoryAccess::ShaderWrite: return VK_ACCESS_SHADER_WRITE_BIT; + case MemoryAccess::TransferRead: return VK_ACCESS_TRANSFER_READ_BIT; + case MemoryAccess::TransferWrite: return VK_ACCESS_TRANSFER_WRITE_BIT; + case MemoryAccess::UniformBufferRead: return VK_ACCESS_UNIFORM_READ_BIT; + case MemoryAccess::VertexBufferRead: return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; + } + + NazaraError("Unhandled MemoryAccess 0x" + NumberToString(UnderlyingCast(memoryAccess), 16)); + return {}; + } + + inline VkAccessFlags ToVulkan(MemoryAccessFlags memoryAccessFlags) + { + VkShaderStageFlags accessBits = 0; + for (int i = 0; i <= UnderlyingCast(MemoryAccess::Max); ++i) + { + MemoryAccess memoryAccess = static_cast(i); + if (memoryAccessFlags.Test(memoryAccess)) + accessBits |= ToVulkan(memoryAccess); + } + + return accessBits; + } + + VkPipelineStageFlagBits ToVulkan(PipelineStage pipelineStage) + { + switch (pipelineStage) + { + case PipelineStage::TopOfPipe: return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + case PipelineStage::ColorOutput: return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + case PipelineStage::DrawIndirect: return VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; + case PipelineStage::FragmentShader: return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + case PipelineStage::FragmentTestsEarly: return VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + case PipelineStage::FragmentTestsLate: return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + case PipelineStage::GeometryShader: return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT; + case PipelineStage::TessellationControlShader: return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT; + case PipelineStage::TessellationEvaluationShader: return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT; + case PipelineStage::Transfer: return VK_PIPELINE_STAGE_TRANSFER_BIT; + case PipelineStage::TransformFeedback: return VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT; + case PipelineStage::VertexInput: return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + case PipelineStage::VertexShader: return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; + case PipelineStage::BottomOfPipe: return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + } + + NazaraError("Unhandled PipelineStage 0x" + NumberToString(UnderlyingCast(pipelineStage), 16)); + return {}; + } + + VkPipelineStageFlags ToVulkan(PipelineStageFlags pipelineStages) + { + VkShaderStageFlags pipelineStageBits = 0; + for (int i = 0; i <= UnderlyingCast(PipelineStage::Max); ++i) + { + PipelineStage pipelineStage = static_cast(i); + if (pipelineStages.Test(pipelineStage)) + pipelineStageBits |= ToVulkan(pipelineStage); + } + + return pipelineStageBits; + } + + VkFormat ToVulkan(PixelFormat pixelFormat) + { + switch (pixelFormat) + { + case PixelFormat::PixelFormat_BGRA8: return VK_FORMAT_B8G8R8A8_UNORM; + case PixelFormat::PixelFormat_Depth24Stencil8: return VK_FORMAT_D24_UNORM_S8_UINT; + case PixelFormat::PixelFormat_Depth32: return VK_FORMAT_D32_SFLOAT; + case PixelFormat::PixelFormat_RGBA8: return VK_FORMAT_R8G8B8A8_UNORM; + default: break; + } + + NazaraError("Unhandled PixelFormat 0x" + NumberToString(pixelFormat, 16)); + return {}; + } inline VkPrimitiveTopology ToVulkan(PrimitiveMode primitiveMode) { @@ -172,14 +302,12 @@ namespace Nz inline VkShaderStageFlags ToVulkan(ShaderStageTypeFlags stageType) { VkShaderStageFlags shaderStageBits = 0; - - if (stageType.Test(ShaderStageType::Fragment)) - shaderStageBits |= VK_SHADER_STAGE_FRAGMENT_BIT; - - if (stageType.Test(ShaderStageType::Vertex)) - shaderStageBits |= VK_SHADER_STAGE_VERTEX_BIT; - - static_assert(UnderlyingCast(ShaderStageType::Max) + 1 == 2); + for (int i = 0; i <= UnderlyingCast(ShaderStageType::Max); ++i) + { + ShaderStageType shaderStage = static_cast(i); + if (stageType.Test(shaderStage)) + shaderStageBits |= ToVulkan(shaderStage); + } return shaderStageBits; } @@ -198,8 +326,26 @@ namespace Nz case StencilOperation_Zero: return VK_STENCIL_OP_ZERO; } - NazaraError("Unhandled RendererComparison 0x" + NumberToString(stencilOp, 16)); - return VK_STENCIL_OP_KEEP; + NazaraError("Unhandled StencilOperation 0x" + NumberToString(stencilOp, 16)); + return {}; + } + + VkImageLayout ToVulkan(TextureLayout textureLayout) + { + switch (textureLayout) + { + case TextureLayout::ColorInput: return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + case TextureLayout::ColorOutput: return VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR; + case TextureLayout::DepthStencilInput: return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL; + case TextureLayout::DepthStencilOutput: return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + case TextureLayout::Present: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + case TextureLayout::TransferSource: return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + case TextureLayout::TransferDestination: return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + case TextureLayout::Undefined: return VK_IMAGE_LAYOUT_UNDEFINED; + } + + NazaraError("Unhandled TextureLayout 0x" + NumberToString(UnderlyingCast(textureLayout), 16)); + return {}; } inline VkVertexInputRate ToVulkan(VertexInputRate inputRate) diff --git a/include/Nazara/VulkanRenderer/VulkanRenderPass.hpp b/include/Nazara/VulkanRenderer/VulkanRenderPass.hpp index 87bc54fa9..7b66c1bcb 100644 --- a/include/Nazara/VulkanRenderer/VulkanRenderPass.hpp +++ b/include/Nazara/VulkanRenderer/VulkanRenderPass.hpp @@ -18,12 +18,11 @@ namespace Nz class NAZARA_VULKANRENDERER_API VulkanRenderPass final : public RenderPass { public: - inline VulkanRenderPass(Vk::RenderPass renderPass, std::initializer_list formats); //< FIXME + VulkanRenderPass(Vk::Device& device, std::vector attachments, std::vector subpassDescriptions, std::vector subpassDependencies); VulkanRenderPass(const VulkanRenderPass&) = delete; VulkanRenderPass(VulkanRenderPass&&) noexcept = default; ~VulkanRenderPass() = default; - inline PixelFormat GetAttachmentFormat(std::size_t attachmentIndex) const; inline Vk::RenderPass& GetRenderPass(); inline const Vk::RenderPass& GetRenderPass() const; @@ -31,7 +30,6 @@ namespace Nz VulkanRenderPass& operator=(VulkanRenderPass&&) noexcept = default; private: - std::vector m_formats; Vk::RenderPass m_renderPass; }; } diff --git a/include/Nazara/VulkanRenderer/VulkanRenderPass.inl b/include/Nazara/VulkanRenderer/VulkanRenderPass.inl index d21e1a67c..ce153800d 100644 --- a/include/Nazara/VulkanRenderer/VulkanRenderPass.inl +++ b/include/Nazara/VulkanRenderer/VulkanRenderPass.inl @@ -7,17 +7,6 @@ namespace Nz { - inline VulkanRenderPass::VulkanRenderPass(Vk::RenderPass renderPass, std::initializer_list formats) : - m_formats(std::begin(formats), std::end(formats)), - m_renderPass(std::move(renderPass)) - { - } - - inline PixelFormat VulkanRenderPass::GetAttachmentFormat(std::size_t attachmentIndex) const - { - return m_formats[attachmentIndex]; - } - inline Vk::RenderPass& VulkanRenderPass::GetRenderPass() { return m_renderPass; diff --git a/src/Nazara/VulkanRenderer/VkRenderWindow.cpp b/src/Nazara/VulkanRenderer/VkRenderWindow.cpp index 111ed0840..98c8d8d67 100644 --- a/src/Nazara/VulkanRenderer/VkRenderWindow.cpp +++ b/src/Nazara/VulkanRenderer/VkRenderWindow.cpp @@ -22,7 +22,6 @@ namespace Nz VkRenderWindow::VkRenderWindow(RenderWindow& owner) : m_currentFrame(0), m_owner(owner), - m_depthStencilFormat(VK_FORMAT_MAX_ENUM), m_shouldRecreateSwapchain(false) { } @@ -151,6 +150,7 @@ namespace Nz } }(); + m_depthStencilFormat = VK_FORMAT_MAX_ENUM; if (!parameters.depthFormats.empty()) { for (PixelFormat format : parameters.depthFormats) @@ -177,8 +177,7 @@ namespace Nz break; case PixelFormat_Stencil16: - m_depthStencilFormat = VK_FORMAT_MAX_ENUM; - break; + continue; default: { @@ -400,98 +399,92 @@ namespace Nz bool VkRenderWindow::SetupRenderPass() { - std::array attachments = { - { - { - 0, // VkAttachmentDescriptionFlags flags; - m_surfaceFormat.format, // VkFormat format; - VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; - VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; - VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; - VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; - VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; - VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR // VkImageLayout finalLayout; - }, - { - 0, // VkAttachmentDescriptionFlags flags; - m_depthStencilFormat, // VkFormat format; - VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; - VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; - VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp; - VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; - VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; - VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout; - }, - } - }; - - VkAttachmentReference colorReference = { - 0, // uint32_t attachment; - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout; - }; - - VkAttachmentReference depthReference = { - 1, // uint32_t attachment; - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // VkImageLayout layout; - }; - - VkSubpassDescription subpass = { - 0, // VkSubpassDescriptionFlags flags; - VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; - 0U, // uint32_t inputAttachmentCount; - nullptr, // const VkAttachmentReference* pInputAttachments; - 1U, // uint32_t colorAttachmentCount; - &colorReference, // const VkAttachmentReference* pColorAttachments; - nullptr, // const VkAttachmentReference* pResolveAttachments; - (m_depthStencilFormat != VK_FORMAT_MAX_ENUM) ? &depthReference : nullptr, // const VkAttachmentReference* pDepthStencilAttachment; - 0U, // uint32_t preserveAttachmentCount; - nullptr // const uint32_t* pPreserveAttachments; - }; - - std::array dependencies; - // First dependency at the start of the render pass - // Does the transition from final to initial layout - dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; // Producer of the dependency - dependencies[0].dstSubpass = 0; // Consumer is our single subpass that will wait for the execution dependency - dependencies[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependencies[0].srcAccessMask = 0; - dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - - // Second dependency at the end the render pass - // Does the transition from the initial to the final layout - dependencies[1].srcSubpass = 0; // Producer of the dependency is our single subpass - dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; // Consumer are all commands outside of the render pass - dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; - dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - - VkRenderPassCreateInfo createInfo = { - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType; - nullptr, // const void* pNext; - 0, // VkRenderPassCreateFlags flags; - (m_depthStencilFormat != VK_FORMAT_MAX_ENUM) ? 2U : 1U, // uint32_t attachmentCount; - attachments.data(), // const VkAttachmentDescription* pAttachments; - 1U, // uint32_t subpassCount; - &subpass, // const VkSubpassDescription* pSubpasses; - UInt32(dependencies.size()), // uint32_t dependencyCount; - dependencies.data() // const VkSubpassDependency* pDependencies; - }; - - Vk::RenderPass renderPass; - if (!renderPass.Create(*m_device, createInfo)) + std::optional colorFormat = FromVulkan(m_surfaceFormat.format); + if (!colorFormat) { - NazaraError("Failed to create render pass: " + TranslateVulkanError(renderPass.GetLastErrorCode())); + NazaraError("unhandled vulkan pixel format (0x" + NumberToString(m_surfaceFormat.format, 16) + ")"); return false; } - std::initializer_list fixmeplease = { PixelFormat::PixelFormat_RGB8, PixelFormat::PixelFormat_Depth24Stencil8 }; - m_renderPass.emplace(std::move(renderPass), fixmeplease); + std::vector attachments; + attachments.push_back({ + *colorFormat, + AttachmentLoadOp::Clear, + AttachmentLoadOp::Discard, + AttachmentStoreOp::Store, + AttachmentStoreOp::Discard, + TextureLayout::Undefined, + TextureLayout::Present + }); + + RenderPass::AttachmentReference colorReference = { + 0, + TextureLayout::ColorInput + }; + + std::vector subpasses = { + { + { + { colorReference }, + {}, + std::nullopt + } + } + }; + + std::vector subpassDependencies = { + { + { + RenderPass::ExternalSubpassIndex, + PipelineStage::ColorOutput, + {}, + + 0, + PipelineStage::ColorOutput, + MemoryAccess::ColorWrite, + + true //< tilable + }, + { + 0, + PipelineStage::ColorOutput, + MemoryAccess::ColorWrite, + + RenderPass::ExternalSubpassIndex, + PipelineStage::BottomOfPipe, + MemoryAccess::MemoryRead, + + true //< tilable + } + } + }; + + if (m_depthStencilFormat != VK_FORMAT_MAX_ENUM) + { + std::optional depthStencilFormat = FromVulkan(m_depthStencilFormat); + if (!depthStencilFormat) + { + NazaraError("unhandled vulkan pixel format (0x" + NumberToString(m_depthStencilFormat, 16) + ")"); + return false; + } + + attachments.push_back({ + *depthStencilFormat, + AttachmentLoadOp::Clear, + AttachmentLoadOp::Discard, + AttachmentStoreOp::Discard, + AttachmentStoreOp::Discard, + TextureLayout::Undefined, + TextureLayout::DepthStencilInput + }); + + subpasses.front().depthStencilAttachment = RenderPass::AttachmentReference{ + 1, + TextureLayout::DepthStencilInput + }; + } + + m_renderPass.emplace(*m_device, std::move(attachments), std::move(subpasses), std::move(subpassDependencies)); return true; } diff --git a/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp b/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp index 8e027e923..f6f3c465b 100644 --- a/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp +++ b/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp @@ -56,7 +56,7 @@ namespace Nz { auto& vkValues = vkClearValues[index]; - if (PixelFormatInfo::GetContent(vkRenderPass.GetAttachmentFormat(index)) == PixelFormatContent_ColorRGBA) + if (PixelFormatInfo::GetContent(vkRenderPass.GetAttachment(index).format) == PixelFormatContent_ColorRGBA) { vkValues.color.float32[0] = values.color.r / 255.f; vkValues.color.float32[1] = values.color.g / 255.f; diff --git a/src/Nazara/VulkanRenderer/VulkanRenderPass.cpp b/src/Nazara/VulkanRenderer/VulkanRenderPass.cpp index e9c406cfc..2d497d6ab 100644 --- a/src/Nazara/VulkanRenderer/VulkanRenderPass.cpp +++ b/src/Nazara/VulkanRenderer/VulkanRenderPass.cpp @@ -3,8 +3,116 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include +#include #include namespace Nz { + inline VulkanRenderPass::VulkanRenderPass(Vk::Device& device, std::vector attachments, std::vector subpassDescriptions, std::vector subpassDependencies) : + RenderPass(std::move(attachments), std::move(subpassDescriptions), std::move(subpassDependencies)) + { + std::size_t totalAttachmentReference = 0; + for (const SubpassDescription& subpassInfo : m_subpassDescriptions) + { + totalAttachmentReference += subpassInfo.colorAttachment.size(); + totalAttachmentReference += subpassInfo.inputAttachments.size(); + + if (subpassInfo.depthStencilAttachment) + totalAttachmentReference++; + } + + StackVector vkAttachments = NazaraStackVector(VkAttachmentDescription, m_attachments.size()); + for (const Attachment& attachmentInfo : m_attachments) + { + vkAttachments.push_back({ + 0, + ToVulkan(attachmentInfo.format), + VK_SAMPLE_COUNT_1_BIT, + ToVulkan(attachmentInfo.loadOp), + ToVulkan(attachmentInfo.storeOp), + ToVulkan(attachmentInfo.stencilLoadOp), + ToVulkan(attachmentInfo.stencilStoreOp), + ToVulkan(attachmentInfo.initialLayout), + ToVulkan(attachmentInfo.finalLayout) + }); + } + + StackVector vkAttachmentReferences = NazaraStackVector(VkAttachmentReference, totalAttachmentReference); + + StackVector vkSubpassDescs = NazaraStackVector(VkSubpassDescription, m_subpassDescriptions.size()); + for (const SubpassDescription& subpassInfo : m_subpassDescriptions) + { + std::size_t colorAttachmentIndex = vkAttachmentReferences.size(); + for (const AttachmentReference& attachmentRef : subpassInfo.colorAttachment) + { + vkAttachmentReferences.push_back({ + UInt32(attachmentRef.attachmentIndex), + ToVulkan(attachmentRef.attachmentLayout) + }); + } + + std::size_t inputAttachmentIndex = vkAttachmentReferences.size(); + for (const AttachmentReference& attachmentRef : subpassInfo.inputAttachments) + { + vkAttachmentReferences.push_back({ + UInt32(attachmentRef.attachmentIndex), + ToVulkan(attachmentRef.attachmentLayout) + }); + } + + std::size_t depthStencilAttachmentIndex = vkAttachmentReferences.size(); + if (subpassInfo.depthStencilAttachment) + { + auto& depthStencilRef = *subpassInfo.depthStencilAttachment; + vkAttachmentReferences.push_back({ + UInt32(depthStencilRef.attachmentIndex), + ToVulkan(depthStencilRef.attachmentLayout) + }); + } + + vkSubpassDescs.push_back({ + VkSubpassDescriptionFlags(0), + VK_PIPELINE_BIND_POINT_GRAPHICS, + UInt32(subpassInfo.inputAttachments.size()), + &vkAttachmentReferences[inputAttachmentIndex], + UInt32(subpassInfo.colorAttachment.size()), + &vkAttachmentReferences[colorAttachmentIndex], + nullptr, + (subpassInfo.depthStencilAttachment) ? &vkAttachmentReferences[depthStencilAttachmentIndex] : nullptr, + 0, + nullptr + }); + } + + StackVector vkSubpassDeps = NazaraStackVector(VkSubpassDependency, m_subpassDependencies.size()); + for (const SubpassDependency& subpassDependency : m_subpassDependencies) + { + vkSubpassDeps.push_back({ + UInt32(subpassDependency.fromSubpassIndex), + UInt32(subpassDependency.toSubpassIndex), + ToVulkan(subpassDependency.fromStages), + ToVulkan(subpassDependency.toStages), + ToVulkan(subpassDependency.fromAccessFlags), + ToVulkan(subpassDependency.toAccessFlags), + VkDependencyFlags((subpassDependency.tilable) ? VK_DEPENDENCY_BY_REGION_BIT : 0) + }); + } + + VkRenderPassCreateInfo renderPassInfo = { + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // sType + nullptr, // pNext + 0, // flags + UInt32(vkAttachments.size()), // attachmentCount + vkAttachments.data(), // pAttachments + UInt32(vkSubpassDescs.size()), // subpassCount + vkSubpassDescs.data(), // pSubpasses + UInt32(vkSubpassDeps.size()), // dependencyCount + vkSubpassDeps.data() // pDependencies + }; + + if (!m_renderPass.Create(device, renderPassInfo)) + throw std::runtime_error("failed to instantiate Vulkan render pass: " + TranslateVulkanError(m_renderPass.GetLastErrorCode())); + } }