From 10aa7231b62b2a5f428e4cd14f2b57b763d007aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 5 May 2021 12:01:20 +0200 Subject: [PATCH] Renderer: Fix MRT support --- .../OpenGLRenderer/OpenGLCommandBuffer.hpp | 1 + .../OpenGLRenderer/OpenGLCommandBuffer.inl | 4 ++ .../VulkanCommandBufferBuilder.hpp | 1 + .../VulkanRenderer/VulkanRenderPipeline.hpp | 16 ++++++-- .../VulkanRenderer/VulkanRenderPipeline.inl | 9 +++++ .../OpenGLRenderer/OpenGLCommandBuffer.cpp | 12 ++++++ .../VulkanCommandBufferBuilder.cpp | 4 +- .../VulkanRenderer/VulkanRenderPipeline.cpp | 37 ++++++++++++++++--- 8 files changed, 74 insertions(+), 10 deletions(-) diff --git a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp index a2e4d9bb1..9657ceb31 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp @@ -149,6 +149,7 @@ namespace Nz DrawStates m_currentStates; std::size_t m_bindingIndex; + std::size_t m_maxColorBufferCount; std::size_t m_poolIndex; std::vector m_commands; OpenGLCommandPool* m_owner; diff --git a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl index 57d5e543e..84b7d3128 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl @@ -11,12 +11,14 @@ namespace Nz { inline OpenGLCommandBuffer::OpenGLCommandBuffer() : + m_maxColorBufferCount(0), m_owner(nullptr) { } inline OpenGLCommandBuffer::OpenGLCommandBuffer(OpenGLCommandPool& owner, std::size_t poolIndex, std::size_t bindingIndex) : m_bindingIndex(bindingIndex), + m_maxColorBufferCount(0), m_poolIndex(poolIndex), m_owner(&owner) { @@ -135,6 +137,8 @@ namespace Nz inline void OpenGLCommandBuffer::SetFramebuffer(const OpenGLFramebuffer& framebuffer, const RenderPass& /*renderPass*/, const CommandBufferBuilder::ClearValues* clearValues, std::size_t clearValueCount) { + m_maxColorBufferCount = std::max(m_maxColorBufferCount, framebuffer.GetColorBufferCount()); + SetFrameBufferData setFramebuffer; setFramebuffer.framebuffer = &framebuffer; diff --git a/include/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp b/include/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp index c089dba01..a3c8173a2 100644 --- a/include/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp +++ b/include/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp @@ -60,6 +60,7 @@ namespace Nz private: Vk::CommandBuffer& m_commandBuffer; const VulkanRenderPass* m_currentRenderPass; + std::size_t m_currentSubpassIndex; std::size_t m_framebufferCount; std::size_t m_imageIndex; }; diff --git a/include/Nazara/VulkanRenderer/VulkanRenderPipeline.hpp b/include/Nazara/VulkanRenderer/VulkanRenderPipeline.hpp index df48fe046..aa0d44a98 100644 --- a/include/Nazara/VulkanRenderer/VulkanRenderPipeline.hpp +++ b/include/Nazara/VulkanRenderer/VulkanRenderPipeline.hpp @@ -8,12 +8,13 @@ #define NAZARA_VULKANRENDERER_VULKANRENDERPIPELINE_HPP #include +#include #include #include #include +#include #include #include -#include #include namespace Nz @@ -26,7 +27,7 @@ namespace Nz VulkanRenderPipeline(Vk::Device& device, RenderPipelineInfo pipelineInfo); ~VulkanRenderPipeline() = default; - VkPipeline Get(const Vk::RenderPass& renderPass) const; + VkPipeline Get(const VulkanRenderPass& renderPass, std::size_t subpassIndex) const; inline const RenderPipelineInfo& GetPipelineInfo() const override; @@ -71,9 +72,16 @@ namespace Nz }; private: - mutable std::unordered_map m_pipelines; + void UpdateCreateInfo(std::size_t colorBufferCount) const; + + struct PipelineHasher + { + inline std::size_t operator()(const std::pair& renderPass) const; + }; + + mutable std::unordered_map, Vk::Pipeline, PipelineHasher> m_pipelines; MovablePtr m_device; - CreateInfo m_pipelineCreateInfo; + mutable CreateInfo m_pipelineCreateInfo; RenderPipelineInfo m_pipelineInfo; }; } diff --git a/include/Nazara/VulkanRenderer/VulkanRenderPipeline.inl b/include/Nazara/VulkanRenderer/VulkanRenderPipeline.inl index 954464855..177d4a5d3 100644 --- a/include/Nazara/VulkanRenderer/VulkanRenderPipeline.inl +++ b/include/Nazara/VulkanRenderer/VulkanRenderPipeline.inl @@ -7,6 +7,15 @@ namespace Nz { + inline std::size_t VulkanRenderPipeline::PipelineHasher::operator()(const std::pair& renderPass) const + { + std::size_t seed = 0; + HashCombine(seed, renderPass.first); + HashCombine(seed, renderPass.second); + + return seed; + } + inline const RenderPipelineInfo& VulkanRenderPipeline::GetPipelineInfo() const { return m_pipelineInfo; diff --git a/src/Nazara/OpenGLRenderer/OpenGLCommandBuffer.cpp b/src/Nazara/OpenGLRenderer/OpenGLCommandBuffer.cpp index 6ed855aa4..8e5be48ba 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLCommandBuffer.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLCommandBuffer.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -57,6 +58,10 @@ namespace Nz { const GL::Context* context = GL::Context::GetCurrentContext(); + StackArray fboDrawBuffers = NazaraStackArrayNoInit(GLenum, m_maxColorBufferCount); + for (std::size_t i = 0; i < m_maxColorBufferCount; ++i) + fboDrawBuffers[i] = GLenum(GL_COLOR_ATTACHMENT0 + i); + for (const auto& commandVariant : m_commands) { std::visit([&](auto&& command) @@ -103,6 +108,10 @@ namespace Nz if (command.framebuffer->GetType() == OpenGLFramebuffer::Type::FBO) { std::size_t colorBufferCount = command.framebuffer->GetColorBufferCount(); + assert(colorBufferCount <= fboDrawBuffers.size()); + + context->glDrawBuffers(GLsizei(colorBufferCount), fboDrawBuffers.data()); + for (std::size_t i = 0; i < colorBufferCount; ++i) { Nz::Color color = command.clearValues[i].color; @@ -115,6 +124,9 @@ namespace Nz } else { + GLenum buffer = GL_BACK; + context->glDrawBuffers(1, &buffer); + Nz::Color color = command.clearValues[0].color; context->glClearColor(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f); context->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); diff --git a/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp b/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp index 6982e5575..fc30b00c4 100644 --- a/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp +++ b/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp @@ -85,6 +85,7 @@ namespace Nz m_commandBuffer.BeginRenderPass(beginInfo); m_currentRenderPass = &vkRenderPass; + m_currentSubpassIndex = 0; } void VulkanCommandBufferBuilder::BindIndexBuffer(Nz::AbstractBuffer* indexBuffer, UInt64 offset) @@ -101,7 +102,7 @@ namespace Nz const VulkanRenderPipeline& vkBinding = static_cast(pipeline); - m_commandBuffer.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vkBinding.Get(m_currentRenderPass->GetRenderPass())); + m_commandBuffer.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vkBinding.Get(*m_currentRenderPass, m_currentSubpassIndex)); } void VulkanCommandBufferBuilder::BindShaderBinding(const ShaderBinding& binding) @@ -160,6 +161,7 @@ namespace Nz void VulkanCommandBufferBuilder::NextSubpass() { m_commandBuffer.NextSubpass(); + m_currentSubpassIndex++; } void VulkanCommandBufferBuilder::PreTransferBarrier() diff --git a/src/Nazara/VulkanRenderer/VulkanRenderPipeline.cpp b/src/Nazara/VulkanRenderer/VulkanRenderPipeline.cpp index 0f8b7098e..608287ba1 100644 --- a/src/Nazara/VulkanRenderer/VulkanRenderPipeline.cpp +++ b/src/Nazara/VulkanRenderer/VulkanRenderPipeline.cpp @@ -19,20 +19,31 @@ namespace Nz m_pipelineCreateInfo = BuildCreateInfo(m_pipelineInfo); } - VkPipeline VulkanRenderPipeline::Get(const Vk::RenderPass& renderPass) const + VkPipeline VulkanRenderPipeline::Get(const VulkanRenderPass& renderPass, std::size_t subpassIndex) const { - if (auto it = m_pipelines.find(renderPass); it != m_pipelines.end()) + const Vk::RenderPass& renderPassHandle = renderPass.GetRenderPass(); + + // Use color attachment count as a key + const auto& subpasses = renderPass.GetSubpassDescriptions(); + assert(subpassIndex < subpasses.size()); + + std::size_t colorAttachmentCount = subpasses[subpassIndex].colorAttachment.size(); + + std::pair key = { renderPassHandle, colorAttachmentCount }; + + if (auto it = m_pipelines.find(key); it != m_pipelines.end()) return it->second; - // Copy create info to make Get re-entrant + UpdateCreateInfo(colorAttachmentCount); + VkGraphicsPipelineCreateInfo pipelineCreateInfo = m_pipelineCreateInfo.pipelineInfo; - pipelineCreateInfo.renderPass = renderPass; + pipelineCreateInfo.renderPass = renderPassHandle; Vk::Pipeline newPipeline; if (!newPipeline.CreateGraphics(*m_device, pipelineCreateInfo)) return VK_NULL_HANDLE; - auto it = m_pipelines.emplace(renderPass, std::move(newPipeline)).first; + auto it = m_pipelines.emplace(key, std::move(newPipeline)).first; return it->second; } @@ -269,4 +280,20 @@ namespace Nz return createInfo; } + + void VulkanRenderPipeline::UpdateCreateInfo(std::size_t colorBufferCount) const + { + // TODO: Add support for independent blend + std::size_t previousSize = m_pipelineCreateInfo.colorBlendAttachmentState.size(); + if (previousSize < colorBufferCount) + { + assert(!m_pipelineCreateInfo.colorBlendAttachmentState.empty()); + + m_pipelineCreateInfo.colorBlendAttachmentState.resize(colorBufferCount); + for (std::size_t i = previousSize; i < colorBufferCount; ++i) + m_pipelineCreateInfo.colorBlendAttachmentState[i] = m_pipelineCreateInfo.colorBlendAttachmentState.front(); + } + + m_pipelineCreateInfo.stateData->colorBlendState = BuildColorBlendInfo(m_pipelineInfo, m_pipelineCreateInfo.colorBlendAttachmentState); + } }