From 4eb96849dbaa279fcbf5cfeb7ec101b2421cf4f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 5 Dec 2021 16:53:02 +0100 Subject: [PATCH] Graphics/FrameGraph: Reuse textures if possible --- include/Nazara/Graphics/FrameGraph.hpp | 2 + include/Nazara/Graphics/FramePass.hpp | 2 + include/Nazara/Graphics/FramePass.inl | 19 +++++++++ src/Nazara/Graphics/FrameGraph.cpp | 57 +++++++++++++++++++++++--- 4 files changed, 75 insertions(+), 5 deletions(-) diff --git a/include/Nazara/Graphics/FrameGraph.hpp b/include/Nazara/Graphics/FrameGraph.hpp index eaa6e0b9f..6a38031d8 100644 --- a/include/Nazara/Graphics/FrameGraph.hpp +++ b/include/Nazara/Graphics/FrameGraph.hpp @@ -45,6 +45,7 @@ namespace Nz using BarrierList = std::vector; using PassList = std::vector; using AttachmentIdToPassMap = std::unordered_map; + using AttachmentIdToPassId = std::unordered_map; using AttachmentIdToTextureId = std::unordered_map; using PassIdToPhysicalPassIndex = std::unordered_map; using TextureTransition = BakedFrameGraph::TextureTransition; @@ -88,6 +89,7 @@ namespace Nz std::vector> renderPasses; std::vector physicalPasses; std::vector textures; + AttachmentIdToPassId attachmentLastUse; AttachmentIdToPassMap attachmentReadList; AttachmentIdToPassMap attachmentWriteList; AttachmentIdToTextureId attachmentToTextures; diff --git a/include/Nazara/Graphics/FramePass.hpp b/include/Nazara/Graphics/FramePass.hpp index 638a73bf7..bf9b81fb7 100644 --- a/include/Nazara/Graphics/FramePass.hpp +++ b/include/Nazara/Graphics/FramePass.hpp @@ -46,6 +46,8 @@ namespace Nz inline std::size_t AddInput(std::size_t attachmentId); inline std::size_t AddOutput(std::size_t attachmentId); + template void ForEachAttachment(F&& func) const; + inline const CommandCallback& GetCommandCallback() const; inline const std::optional& GetDepthStencilClear() const; inline std::size_t GetDepthStencilInput() const; diff --git a/include/Nazara/Graphics/FramePass.inl b/include/Nazara/Graphics/FramePass.inl index a87154c92..8a27e0f11 100644 --- a/include/Nazara/Graphics/FramePass.inl +++ b/include/Nazara/Graphics/FramePass.inl @@ -38,6 +38,25 @@ namespace Nz return outputIndex; } + template + void FramePass::ForEachAttachment(F&& func) const + { + for (const auto& input : m_inputs) + func(input.attachmentId); + + for (const auto& output : m_outputs) + func(output.attachmentId); + + if (m_depthStencilInput != FramePass::InvalidAttachmentId) + { + func(m_depthStencilInput); + + if (m_depthStencilOutput != FramePass::InvalidAttachmentId && m_depthStencilOutput != m_depthStencilInput) + func(m_depthStencilOutput); + } + else if (m_depthStencilOutput != FramePass::InvalidAttachmentId) + func(m_depthStencilOutput); + } inline auto FramePass::GetCommandCallback() const -> const CommandCallback& { diff --git a/src/Nazara/Graphics/FrameGraph.cpp b/src/Nazara/Graphics/FrameGraph.cpp index 8bb73328d..715576aac 100644 --- a/src/Nazara/Graphics/FrameGraph.cpp +++ b/src/Nazara/Graphics/FrameGraph.cpp @@ -179,17 +179,38 @@ namespace Nz void FrameGraph::AssignPhysicalTextures() { + std::vector texturePool; + auto RegisterTexture = [&](std::size_t attachmentIndex) { if (auto it = m_pending.attachmentToTextures.find(attachmentIndex); it == m_pending.attachmentToTextures.end()) { + const auto& attachmentData = m_attachments[attachmentIndex]; + + // Fetch from reuse pool if possible + for (auto it = texturePool.begin(); it != texturePool.end(); ++it) + { + std::size_t textureId = *it; + + TextureData& data = m_pending.textures[textureId]; + if (data.format != attachmentData.format || + data.width != attachmentData.width || + data.height != attachmentData.height) + continue; + + texturePool.erase(it); + m_pending.attachmentToTextures.emplace(attachmentIndex, textureId); + + return textureId; + } + std::size_t textureId = m_pending.textures.size(); m_pending.attachmentToTextures.emplace(attachmentIndex, textureId); TextureData& data = m_pending.textures.emplace_back(); - data.format = m_attachments[attachmentIndex].format; - data.width = m_attachments[attachmentIndex].width; - data.height = m_attachments[attachmentIndex].height; + data.format = attachmentData.format; + data.width = attachmentData.width; + data.height = attachmentData.height; return textureId; } @@ -197,6 +218,16 @@ namespace Nz return it->second; }; + // Assign last use pass index for every attachment + for (std::size_t passIndex : m_pending.passList) + { + const FramePass& framePass = m_framePasses[passIndex]; + framePass.ForEachAttachment([&](std::size_t attachmentId) + { + m_pending.attachmentLastUse[attachmentId] = passIndex; + }); + } + for (std::size_t passIndex : m_pending.passList) { const FramePass& framePass = m_framePasses[passIndex]; @@ -240,6 +271,24 @@ namespace Nz TextureData& attachmentData = m_pending.textures[textureId]; attachmentData.usage |= TextureUsage::DepthStencilAttachment; } + + framePass.ForEachAttachment([&](std::size_t attachmentId) + { + std::size_t lastUsingPassId = Retrieve(m_pending.attachmentLastUse, attachmentId); + + // If this pass is the last one where this attachment is used, push the texture to the reuse pool + if (passIndex == lastUsingPassId) + { + std::size_t textureId = Retrieve(m_pending.attachmentToTextures, attachmentId); + + // For input/output depth-stencil buffer, the same texture can be used + if (texturePool.empty() || texturePool.back() != textureId) + { + assert(std::find(texturePool.begin(), texturePool.end(), textureId) == texturePool.end()); + texturePool.push_back(textureId); + } + } + }); } // Add TextureUsage::Sampled to backbuffer output @@ -274,7 +323,6 @@ namespace Nz return barrier; } - }; for (std::size_t passId : m_pending.passList) @@ -779,7 +827,6 @@ namespace Nz const FramePass& framePass = m_framePasses[subpass.passIndex]; std::size_t dsInputAttachment = framePass.GetDepthStencilInput(); std::size_t dsOutputAttachement = framePass.GetDepthStencilOutput(); - bool depthRead = false; if (dsInputAttachment != FramePass::InvalidAttachmentId && dsOutputAttachement != FramePass::InvalidAttachmentId) {