diff --git a/include/Nazara/Graphics/BakedFrameGraph.hpp b/include/Nazara/Graphics/BakedFrameGraph.hpp index 2fd9a7059..abac7b8f5 100644 --- a/include/Nazara/Graphics/BakedFrameGraph.hpp +++ b/include/Nazara/Graphics/BakedFrameGraph.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -81,15 +82,10 @@ namespace Nz bool forceCommandBufferRegeneration = true; }; - struct TextureData + struct TextureData : FrameGraphTextureData { std::string name; std::shared_ptr texture; - FramePassAttachmentSize size; - PixelFormat format; - TextureUsageFlags usage; - unsigned int width; - unsigned int height; }; std::shared_ptr m_commandPool; diff --git a/include/Nazara/Graphics/FrameGraph.hpp b/include/Nazara/Graphics/FrameGraph.hpp index b65efac0c..74946b4e6 100644 --- a/include/Nazara/Graphics/FrameGraph.hpp +++ b/include/Nazara/Graphics/FrameGraph.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,8 @@ namespace Nz ~FrameGraph() = default; inline std::size_t AddAttachment(FramePassAttachment attachment); + inline std::size_t AddAttachmentCube(FramePassAttachment attachment); + inline std::size_t AddAttachmentCubeFace(std::size_t attachmentId, CubemapFace face); inline std::size_t AddAttachmentProxy(std::string name, std::size_t attachmentId); inline void AddBackbufferOutput(std::size_t backbufferOutput); inline FramePass& AddPass(std::string name); @@ -52,6 +55,16 @@ namespace Nz using PassIdToPhysicalPassIndex = std::unordered_map; using TextureBarrier = BakedFrameGraph::TextureBarrier; + struct AttachmentCube : FramePassAttachment + { + }; + + struct AttachmentLayer + { + std::size_t attachmentId; + std::size_t layerIndex; + }; + struct AttachmentProxy { std::size_t attachmentId; @@ -84,22 +97,13 @@ namespace Nz std::vector passes; }; - struct TextureData - { - std::string name; - PixelFormat format; - FramePassAttachmentSize size; - TextureUsageFlags usage; - unsigned int width; - unsigned int height; - }; - struct WorkData { std::vector> renderPasses; std::vector physicalPasses; - std::vector textures; - std::vector texturePool; + std::vector textures; + std::vector texture2DPool; + std::vector textureCubePool; AttachmentIdToPassId attachmentLastUse; AttachmentIdToPassMap attachmentReadList; AttachmentIdToPassMap attachmentWriteList; @@ -123,9 +127,11 @@ namespace Nz void ReorderPasses(); void TraverseGraph(std::size_t passIndex); + using AttachmentType = std::variant; + std::vector m_backbufferOutputs; std::vector m_framePasses; - std::vector> m_attachments; + std::vector m_attachments; WorkData m_pending; }; } diff --git a/include/Nazara/Graphics/FrameGraph.inl b/include/Nazara/Graphics/FrameGraph.inl index 37698c873..b0e533738 100644 --- a/include/Nazara/Graphics/FrameGraph.inl +++ b/include/Nazara/Graphics/FrameGraph.inl @@ -16,10 +16,32 @@ namespace Nz return id; } + inline std::size_t FrameGraph::AddAttachmentCube(FramePassAttachment attachment) + { + std::size_t id = m_attachments.size(); + m_attachments.emplace_back(AttachmentCube{ std::move(attachment) }); + + return id; + } + + inline std::size_t FrameGraph::AddAttachmentCubeFace(std::size_t attachmentId, CubemapFace face) + { + attachmentId = ResolveAttachmentIndex(attachmentId); + + assert(std::holds_alternative(m_attachments[attachmentId])); + + std::size_t id = m_attachments.size(); + m_attachments.emplace_back(AttachmentLayer{ + attachmentId, + SafeCast(face) + }); + + return id; + } + inline std::size_t FrameGraph::AddAttachmentProxy(std::string name, std::size_t attachmentId) { assert(attachmentId < m_attachments.size()); - assert(std::holds_alternative(m_attachments[attachmentId])); std::size_t id = m_attachments.size(); m_attachments.emplace_back(AttachmentProxy { diff --git a/include/Nazara/Graphics/FrameGraphStructs.hpp b/include/Nazara/Graphics/FrameGraphStructs.hpp new file mode 100644 index 000000000..428d54bc2 --- /dev/null +++ b/include/Nazara/Graphics/FrameGraphStructs.hpp @@ -0,0 +1,38 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_GRAPHICS_FRAMEGRAPHSTRUCTS_HPP +#define NAZARA_GRAPHICS_FRAMEGRAPHSTRUCTS_HPP + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + struct FrameGraphTextureData + { + struct ViewData + { + std::size_t parentTextureId; + std::size_t arrayLayer; + }; + + std::optional viewData; + std::string name; + ImageType type; + PixelFormat format; + FramePassAttachmentSize size; + TextureUsageFlags usage; + unsigned int width; + unsigned int height; + }; +} + +#endif // NAZARA_GRAPHICS_FRAMEGRAPHSTRUCTS_HPP diff --git a/src/Nazara/Graphics/BakedFrameGraph.cpp b/src/Nazara/Graphics/BakedFrameGraph.cpp index 32a238e37..7912a7216 100644 --- a/src/Nazara/Graphics/BakedFrameGraph.cpp +++ b/src/Nazara/Graphics/BakedFrameGraph.cpp @@ -149,29 +149,48 @@ namespace Nz for (auto& textureData : m_textures) { - TextureInfo textureCreationParams; - textureCreationParams.type = ImageType::E2D; - textureCreationParams.usageFlags = textureData.usage; - textureCreationParams.pixelFormat = textureData.format; - - textureCreationParams.width = 1; - textureCreationParams.height = 1; - switch (textureData.size) + if (textureData.viewData) { - case FramePassAttachmentSize::Fixed: - textureCreationParams.width = textureData.width; - textureCreationParams.height = textureData.height; - break; + TextureData& parentTexture = m_textures[textureData.viewData->parentTextureId]; - case FramePassAttachmentSize::SwapchainFactor: - textureCreationParams.width = frameWidth * textureData.width / 100'000; - textureCreationParams.height = frameHeight * textureData.height / 100'000; - break; + // This is a view on another texture + TextureViewInfo textureViewParams; + textureViewParams.viewType = textureData.type; + textureViewParams.reinterpretFormat = textureData.format; + textureViewParams.baseArrayLayer = textureData.viewData->arrayLayer; + + textureData.texture = parentTexture.texture->CreateView(textureViewParams); } + else + { - textureData.texture = renderDevice->InstantiateTexture(textureCreationParams); - if (!textureData.name.empty()) - textureData.texture->UpdateDebugName(textureData.name); + TextureInfo textureCreationParams; + textureCreationParams.type = textureData.type; + textureCreationParams.usageFlags = textureData.usage; + textureCreationParams.pixelFormat = textureData.format; + + if (textureCreationParams.type == ImageType::Cubemap) + textureCreationParams.layerCount = 6; + + textureCreationParams.width = 1; + textureCreationParams.height = 1; + switch (textureData.size) + { + case FramePassAttachmentSize::Fixed: + textureCreationParams.width = textureData.width; + textureCreationParams.height = textureData.height; + break; + + case FramePassAttachmentSize::SwapchainFactor: + textureCreationParams.width = frameWidth * textureData.width / 100'000; + textureCreationParams.height = frameHeight * textureData.height / 100'000; + break; + } + + textureData.texture = renderDevice->InstantiateTexture(textureCreationParams); + if (!textureData.name.empty()) + textureData.texture->UpdateDebugName(textureData.name); + } } std::vector> textures; diff --git a/src/Nazara/Graphics/FrameGraph.cpp b/src/Nazara/Graphics/FrameGraph.cpp index da0f3c5c5..cdbfacf7f 100644 --- a/src/Nazara/Graphics/FrameGraph.cpp +++ b/src/Nazara/Graphics/FrameGraph.cpp @@ -39,7 +39,8 @@ namespace Nz m_pending.physicalPasses.clear(); m_pending.renderPasses.clear(); m_pending.textures.clear(); - m_pending.texturePool.clear(); + m_pending.texture2DPool.clear(); + m_pending.textureCubePool.clear(); BuildReadWriteList(); @@ -113,12 +114,7 @@ namespace Nz for (auto& texture : m_pending.textures) { auto& bakedTexture = bakedTextures.emplace_back(); - bakedTexture.name = std::move(texture.name); - bakedTexture.format = texture.format; - bakedTexture.height = texture.height; - bakedTexture.size = texture.size; - bakedTexture.usage = texture.usage; - bakedTexture.width = texture.width; + static_cast(bakedTexture) = std::move(texture); } return BakedFrameGraph(std::move(bakedPasses), std::move(bakedTextures), std::move(m_pending.attachmentToTextures), std::move(m_pending.passIdToPhysicalPassIndex)); @@ -195,7 +191,7 @@ namespace Nz { std::size_t textureId = RegisterTexture(input.attachmentId); - TextureData& attachmentData = m_pending.textures[textureId]; + FrameGraphTextureData& attachmentData = m_pending.textures[textureId]; attachmentData.usage |= TextureUsage::ShaderSampling; } @@ -203,7 +199,7 @@ namespace Nz { std::size_t textureId = RegisterTexture(output.attachmentId); - TextureData& attachmentData = m_pending.textures[textureId]; + FrameGraphTextureData& attachmentData = m_pending.textures[textureId]; attachmentData.usage |= TextureUsage::ColorAttachment; } @@ -211,7 +207,7 @@ namespace Nz { std::size_t textureId = RegisterTexture(depthStencilInput); - TextureData& attachmentData = m_pending.textures[textureId]; + FrameGraphTextureData& attachmentData = m_pending.textures[textureId]; attachmentData.usage |= TextureUsage::DepthStencilAttachment; if (std::size_t depthStencilOutput = framePass.GetDepthStencilOutput(); depthStencilOutput != FramePass::InvalidAttachmentId) @@ -240,7 +236,7 @@ namespace Nz { std::size_t textureId = RegisterTexture(depthStencilOutput); - TextureData& attachmentData = m_pending.textures[textureId]; + FrameGraphTextureData& attachmentData = m_pending.textures[textureId]; attachmentData.usage |= TextureUsage::DepthStencilAttachment; } @@ -253,10 +249,21 @@ namespace Nz // If this pass is the last one where this attachment is used, push the texture to the reuse pool if (it != m_pending.attachmentLastUse.end() && passIndex == it->second) { - std::size_t textureId = Retrieve(m_pending.attachmentToTextures, attachmentId); + const auto& attachmentData = m_attachments[attachmentId]; + if (std::holds_alternative(attachmentData)) + { + std::size_t textureId = Retrieve(m_pending.attachmentToTextures, attachmentId); - assert(std::find(m_pending.texturePool.begin(), m_pending.texturePool.end(), textureId) == m_pending.texturePool.end()); - m_pending.texturePool.push_back(textureId); + assert(std::find(m_pending.texture2DPool.begin(), m_pending.texture2DPool.end(), textureId) == m_pending.texture2DPool.end()); + m_pending.texture2DPool.push_back(textureId); + } + else if (std::holds_alternative(attachmentData)) + { + std::size_t textureId = Retrieve(m_pending.attachmentToTextures, attachmentId); + + assert(std::find(m_pending.textureCubePool.begin(), m_pending.textureCubePool.end(), textureId) == m_pending.textureCubePool.end()); + m_pending.textureCubePool.push_back(textureId); + } } }); } @@ -270,6 +277,16 @@ namespace Nz auto& backbufferTexture = m_pending.textures[it->second]; backbufferTexture.usage |= TextureUsage::ShaderSampling; } + + // Apply texture view usage to their parents + for (auto& textureData : m_pending.textures) + { + if (textureData.viewData) + { + auto& parentTextureData = m_pending.textures[textureData.viewData->parentTextureId]; + parentTextureData.usage |= textureData.usage; + } + } } void FrameGraph::BuildBarriers() @@ -946,18 +963,20 @@ namespace Nz const FramePassAttachment& attachmentData = arg; // Fetch from reuse pool if possible - for (auto it = m_pending.texturePool.begin(); it != m_pending.texturePool.end(); ++it) + for (auto it = m_pending.texture2DPool.begin(); it != m_pending.texture2DPool.end(); ++it) { std::size_t textureId = *it; - TextureData& data = m_pending.textures[textureId]; + FrameGraphTextureData& data = m_pending.textures[textureId]; + assert(data.type == ImageType::E2D); + if (data.format != attachmentData.format || - data.width != attachmentData.width || + data.width != attachmentData.width || data.height != attachmentData.height || - data.size != attachmentData.size) + data.size != attachmentData.size) continue; - m_pending.texturePool.erase(it); + m_pending.texture2DPool.erase(it); m_pending.attachmentToTextures.emplace(attachmentIndex, textureId); if (!attachmentData.name.empty() && data.name != attachmentData.name) @@ -969,7 +988,8 @@ namespace Nz std::size_t textureId = m_pending.textures.size(); m_pending.attachmentToTextures.emplace(attachmentIndex, textureId); - TextureData& data = m_pending.textures.emplace_back(); + FrameGraphTextureData& data = m_pending.textures.emplace_back(); + data.type = ImageType::E2D; data.name = attachmentData.name; data.format = attachmentData.format; data.width = attachmentData.width; @@ -978,6 +998,72 @@ namespace Nz return textureId; } + else if constexpr (std::is_same_v) + { + const AttachmentCube& attachmentData = arg; + + // Fetch from reuse pool if possible + for (auto it = m_pending.textureCubePool.begin(); it != m_pending.textureCubePool.end(); ++it) + { + std::size_t textureId = *it; + + FrameGraphTextureData& data = m_pending.textures[textureId]; + assert(data.type == ImageType::Cubemap); + + if (data.format != attachmentData.format || + data.width != attachmentData.width || + data.height != attachmentData.height || + data.size != attachmentData.size) + continue; + + m_pending.textureCubePool.erase(it); + m_pending.attachmentToTextures.emplace(attachmentIndex, textureId); + + if (!attachmentData.name.empty() && data.name != attachmentData.name) + data.name += " / " + attachmentData.name; + + return textureId; + } + + std::size_t textureId = m_pending.textures.size(); + m_pending.attachmentToTextures.emplace(attachmentIndex, textureId); + + FrameGraphTextureData& data = m_pending.textures.emplace_back(); + data.type = ImageType::Cubemap; + data.name = attachmentData.name; + data.format = attachmentData.format; + data.width = attachmentData.width; + data.height = attachmentData.height; + data.size = attachmentData.size; + + return textureId; + } + else if constexpr (std::is_same_v) + { + const AttachmentLayer& texLayer = arg; + + // TODO: Reuse texture views from pool? + + std::size_t parentTextureId = RegisterTexture(texLayer.attachmentId); + + std::size_t textureId = m_pending.textures.size(); + m_pending.attachmentToTextures.emplace(attachmentIndex, textureId); + + FrameGraphTextureData& data = m_pending.textures.emplace_back(); + const FrameGraphTextureData& parentTexture = m_pending.textures[parentTextureId]; + + data.type = ImageType::E2D; + data.format = parentTexture.format; + data.width = parentTexture.width; + data.height = parentTexture.height; + data.size = parentTexture.size; + data.viewData = { + parentTextureId, + texLayer.layerIndex + }; + + return textureId; + } else if constexpr (std::is_same_v) { const AttachmentProxy& proxy = arg; @@ -1022,8 +1108,9 @@ namespace Nz std::size_t FrameGraph::ResolveAttachmentIndex(std::size_t attachmentIndex) const { assert(attachmentIndex < m_attachments.size()); - if (const AttachmentProxy* proxy = std::get_if(&m_attachments[attachmentIndex])) - return proxy->attachmentId; + + while (const AttachmentProxy* proxy = std::get_if(&m_attachments[attachmentIndex])) + attachmentIndex = proxy->attachmentId; return attachmentIndex; }