Add FrameGraph (WIP)

This commit is contained in:
Jérôme Leclercq
2021-05-02 13:58:35 +02:00
parent 377129586b
commit 55c2dd8485
29 changed files with 1749 additions and 36 deletions

View File

@@ -0,0 +1,98 @@
// Copyright (C) 2017 Jérôme Leclercq
// 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_BAKEDFRAMEGRAPH_HPP
#define NAZARA_BAKEDFRAMEGRAPH_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/FramePass.hpp>
#include <Nazara/Math/Rect.hpp>
#include <Nazara/Renderer/CommandPool.hpp>
#include <Nazara/Renderer/Framebuffer.hpp>
#include <Nazara/Renderer/RenderPass.hpp>
#include <Nazara/Renderer/Texture.hpp>
#include <vector>
namespace Nz
{
class RenderFrame;
class NAZARA_GRAPHICS_API BakedFrameGraph
{
friend class FrameGraph;
public:
BakedFrameGraph(const BakedFrameGraph&) = delete;
BakedFrameGraph(BakedFrameGraph&&) noexcept = default;
~BakedFrameGraph() = default;
void Execute(RenderFrame& renderFrame);
const std::shared_ptr<Texture>& GetAttachmentTexture(std::size_t attachmentIndex) const;
const std::shared_ptr<RenderPass>& GetRenderPass(std::size_t passIndex) const;
void Resize(unsigned int width, unsigned int height);
BakedFrameGraph& operator=(const BakedFrameGraph&) = delete;
BakedFrameGraph& operator=(BakedFrameGraph&&) noexcept = default;
private:
struct PassData;
struct TextureData;
using AttachmentIdToTextureId = std::unordered_map<std::size_t /*attachmentId*/, std::size_t /*textureId*/>;
using PassIdToPhysicalPassIndex = std::unordered_map<std::size_t /*passId*/, std::size_t /*physicalPassId*/>;
BakedFrameGraph(std::vector<PassData> passes, std::vector<TextureData> textures, AttachmentIdToTextureId attachmentIdToTextureMapping, PassIdToPhysicalPassIndex passIdToPhysicalPassMapping);
struct TextureTransition
{
std::size_t textureId;
MemoryAccessFlags dstAccessMask;
MemoryAccessFlags srcAccessMask;
PipelineStageFlags dstStageMask;
PipelineStageFlags srcStageMask;
TextureLayout newLayout;
TextureLayout oldLayout;
};
struct SubpassData
{
FramePass::CommandCallback commandCallback;
};
struct PassData
{
CommandBufferPtr commandBuffer;
std::shared_ptr<Framebuffer> framebuffer;
std::shared_ptr<RenderPass> renderPass;
std::vector<std::size_t> outputTextureIndices;
std::vector<SubpassData> subpasses;
std::vector<TextureTransition> transitions;
FramePass::ExecutionCallback executionCallback;
Recti renderRect;
};
struct TextureData
{
std::shared_ptr<Texture> texture;
PixelFormat format;
TextureUsageFlags usage;
unsigned int width;
unsigned int height;
};
std::shared_ptr<CommandPool> m_commandPool;
std::vector<PassData> m_passes;
std::vector<TextureData> m_textures;
AttachmentIdToTextureId m_attachmentToTextureMapping;
PassIdToPhysicalPassIndex m_passIdToPhysicalPassMapping;
};
}
#include <Nazara/Graphics/BakedFrameGraph.inl>
#endif

View File

@@ -0,0 +1,12 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/BakedFrameGraph.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
}
#include <Nazara/Graphics/DebugOff.hpp>

View File

@@ -0,0 +1,120 @@
// Copyright (C) 2017 Jérôme Leclercq
// 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_FRAMEGRAPH_HPP
#define NAZARA_FRAMEGRAPH_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Graphics/BakedFrameGraph.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/FramePass.hpp>
#include <Nazara/Graphics/FramePassAttachment.hpp>
#include <Nazara/Renderer/Enums.hpp>
#include <Nazara/Renderer/RenderPass.hpp>
#include <optional>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
namespace Nz
{
class NAZARA_GRAPHICS_API FrameGraph
{
public:
FrameGraph() = default;
FrameGraph(const FrameGraph&) = delete;
FrameGraph(FrameGraph&&) noexcept = default;
~FrameGraph() = default;
inline std::size_t AddAttachment(FramePassAttachment attachment);
inline FramePass& AddPass(std::string name);
BakedFrameGraph Bake();
inline void SetBackbufferOutput(std::size_t backbufferOutput);
FrameGraph& operator=(const FrameGraph&) = delete;
FrameGraph& operator=(FrameGraph&&) noexcept = default;
private:
struct PassBarriers;
using BarrierList = std::vector<PassBarriers>;
using PassList = std::vector<std::size_t /*PassIndex*/>;
using AttachmentIdToPassMap = std::unordered_map<std::size_t /*resourceIndex*/, PassList /*passIndexes*/>;
using AttachmentIdToTextureId = std::unordered_map<std::size_t /*attachmentId*/, std::size_t /*textureId*/>;
using PassIdToPhysicalPassIndex = std::unordered_map<std::size_t /*passId*/, std::size_t /*physicalPassId*/>;
using TextureTransition = BakedFrameGraph::TextureTransition;
struct Barrier
{
std::size_t textureId;
MemoryAccessFlags access;
PipelineStageFlags stages;
TextureLayout layout;
};
struct PassBarriers
{
std::vector<Barrier> invalidationBarriers;
std::vector<Barrier> flushBarriers;
};
struct PhysicalPassData
{
struct Subpass
{
std::size_t passIndex;
};
std::vector<TextureTransition> textureTransitions;
std::vector<Subpass> passes;
};
struct TextureData
{
PixelFormat format;
TextureUsageFlags usage;
unsigned int width;
unsigned int height;
};
struct WorkData
{
std::size_t backbufferResourceIndex;
std::vector<std::shared_ptr<RenderPass>> renderPasses;
std::vector<PhysicalPassData> physicalPasses;
std::vector<TextureData> textures;
AttachmentIdToPassMap attachmentReadList;
AttachmentIdToPassMap attachmentWriteList;
AttachmentIdToTextureId attachmentToTextures;
BarrierList barrierList;
PassList passList;
PassIdToPhysicalPassIndex passIdToPhysicalPassIndex;
};
void AssignPhysicalPasses();
void AssignPhysicalTextures();
void BuildBarriers();
void BuildPhysicalBarriers();
void BuildPhysicalPassDependencies(std::size_t colorAttachmentCount, bool hasDepthStencilAttachment, std::vector<RenderPass::Attachment>& renderPassAttachments, std::vector<RenderPass::SubpassDescription>& subpasses, std::vector<RenderPass::SubpassDependency>& dependencies);
void BuildPhysicalPasses();
void BuildReadWriteList();
void RemoveDuplicatePasses();
void ReorderPasses();
void TraverseGraph(std::size_t passIndex);
std::optional<std::size_t> m_backbufferOutput;
std::vector<FramePass> m_framePasses;
std::vector<FramePassAttachment> m_attachments;
WorkData m_pending;
};
}
#include <Nazara/Graphics/FrameGraph.inl>
#endif

View File

@@ -0,0 +1,31 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/FrameGraph.hpp>
#include <cassert>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
inline std::size_t FrameGraph::AddAttachment(FramePassAttachment attachment)
{
std::size_t id = m_attachments.size();
m_attachments.emplace_back(std::move(attachment));
return id;
}
inline FramePass& FrameGraph::AddPass(std::string name)
{
std::size_t id = m_framePasses.size();
return m_framePasses.emplace_back(*this, id, std::move(name));
}
inline void FrameGraph::SetBackbufferOutput(std::size_t backbufferOutput)
{
m_backbufferOutput = backbufferOutput;
}
}
#include <Nazara/Graphics/DebugOff.hpp>

View File

@@ -0,0 +1,102 @@
// Copyright (C) 2017 Jérôme Leclercq
// 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_FRAMEPASS_HPP
#define NAZARA_FRAMEPASS_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Color.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/FramePassAttachment.hpp>
#include <limits>
#include <optional>
#include <string>
namespace Nz
{
class CommandBufferBuilder;
class FrameGraph;
enum class FramePassExecution
{
Execute,
Skip,
UpdateAndExecute
};
class NAZARA_GRAPHICS_API FramePass
{
public:
using CommandCallback = std::function<void(CommandBufferBuilder& builder)>;
using ExecutionCallback = std::function<FramePassExecution()>;
struct DepthStencilClear;
struct Input;
struct Output;
inline FramePass(FrameGraph& owner, std::size_t passId, std::string name);
FramePass(const FramePass&) = delete;
FramePass(FramePass&&) noexcept = default;
~FramePass() = default;
inline std::size_t AddInput(std::size_t attachmentId);
inline std::size_t AddOutput(std::size_t attachmentId);
inline const CommandCallback& GetCommandCallback() const;
inline const std::optional<DepthStencilClear>& GetDepthStencilClear() const;
inline std::size_t GetDepthStencilInput() const;
inline std::size_t GetDepthStencilOutput() const;
inline const ExecutionCallback& GetExecutionCallback() const;
inline const std::vector<Input>& GetInputs() const;
inline const std::vector<Output>& GetOutputs() const;
inline std::size_t GetPassId() const;
inline void SetCommandCallback(CommandCallback callback);
inline void SetClearColor(std::size_t outputIndex, const std::optional<Color>& color);
inline void SetDepthStencilClear(float depth, UInt32 stencil);
inline void SetExecutionCallback(CommandCallback callback);
inline void SetDepthStencilInput(std::size_t attachmentId);
inline void SetDepthStencilOutput(std::size_t attachmentId);
FramePass& operator=(const FramePass&) = delete;
FramePass& operator=(FramePass&&) noexcept = default;
static constexpr std::size_t InvalidAttachmentId = std::numeric_limits<std::size_t>::max();
struct DepthStencilClear
{
float depth;
UInt32 stencil;
};
struct Input
{
std::size_t attachmentId;
};
struct Output
{
std::size_t attachmentId;
std::optional<Color> clearColor;
};
private:
std::optional<DepthStencilClear> m_depthStencilClear;
std::size_t m_depthStencilInput;
std::size_t m_depthStencilOutput;
std::size_t m_passId;
std::string m_name;
std::vector<Input> m_inputs;
std::vector<Output> m_outputs;
FrameGraph& m_owner;
CommandCallback m_commandCallback;
ExecutionCallback m_executionCallback;
};
}
#include <Nazara/Graphics/FramePass.inl>
#endif

View File

@@ -0,0 +1,116 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/FramePass.hpp>
#include <cassert>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
inline FramePass::FramePass(FrameGraph& owner, std::size_t passId, std::string name) :
m_depthStencilInput(InvalidAttachmentId),
m_depthStencilOutput(InvalidAttachmentId),
m_passId(passId),
m_name(std::move(name)),
m_owner(owner)
{
}
inline std::size_t FramePass::AddInput(std::size_t attachmentId)
{
assert(attachmentId != InvalidAttachmentId);
std::size_t inputIndex = m_inputs.size();
auto& input = m_inputs.emplace_back();
input.attachmentId = attachmentId;
return inputIndex;
}
inline std::size_t FramePass::AddOutput(std::size_t attachmentId)
{
assert(attachmentId != InvalidAttachmentId);
std::size_t outputIndex = m_outputs.size();
auto& output = m_outputs.emplace_back();
output.attachmentId = attachmentId;
return outputIndex;
}
inline auto FramePass::GetCommandCallback() const -> const CommandCallback&
{
return m_commandCallback;
}
inline auto FramePass::GetDepthStencilClear() const -> const std::optional<DepthStencilClear>&
{
return m_depthStencilClear;
}
inline std::size_t FramePass::GetDepthStencilInput() const
{
return m_depthStencilInput;
}
inline std::size_t FramePass::GetDepthStencilOutput() const
{
return m_depthStencilOutput;
}
inline auto FramePass::GetExecutionCallback() const -> const ExecutionCallback&
{
return m_executionCallback;
}
inline auto FramePass::GetInputs() const -> const std::vector<Input>&
{
return m_inputs;
}
inline auto FramePass::GetOutputs() const -> const std::vector<Output>&
{
return m_outputs;
}
inline std::size_t FramePass::GetPassId() const
{
return m_passId;
}
inline void FramePass::SetCommandCallback(CommandCallback callback)
{
m_commandCallback = std::move(callback);
}
inline void FramePass::SetClearColor(std::size_t outputIndex, const std::optional<Color>& color)
{
assert(outputIndex < m_outputs.size());
m_outputs[outputIndex].clearColor = color;
}
inline void FramePass::SetDepthStencilClear(float depth, UInt32 stencil)
{
auto& dsClear = m_depthStencilClear.emplace();
dsClear.depth = depth;
dsClear.stencil = stencil;
}
inline void FramePass::SetExecutionCallback(CommandCallback callback)
{
m_commandCallback = std::move(callback);
}
inline void FramePass::SetDepthStencilInput(std::size_t attachmentId)
{
m_depthStencilInput = attachmentId;
}
inline void FramePass::SetDepthStencilOutput(std::size_t attachmentId)
{
m_depthStencilOutput = attachmentId;
}
}
#include <Nazara/Graphics/DebugOff.hpp>

View File

@@ -0,0 +1,26 @@
// Copyright (C) 2017 Jérôme Leclercq
// 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_FRAMEPASSATTACHMENT_HPP
#define NAZARA_FRAMEPASSATTACHMENT_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Utility/PixelFormat.hpp>
#include <string>
namespace Nz
{
struct FramePassAttachment
{
std::string name;
PixelFormat format;
};
}
#include <Nazara/Graphics/FramePassAttachment.inl>
#endif

View File

@@ -0,0 +1,13 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/FramePassAttachment.hpp>
#include <cassert>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
}
#include <Nazara/Graphics/DebugOff.hpp>