Add FrameGraph (WIP)
This commit is contained in:
parent
377129586b
commit
55c2dd8485
|
|
@ -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
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -55,7 +55,7 @@ namespace Nz
|
||||||
inline std::size_t GetPoolIndex() const;
|
inline std::size_t GetPoolIndex() const;
|
||||||
inline const OpenGLCommandPool& GetOwner() const;
|
inline const OpenGLCommandPool& GetOwner() const;
|
||||||
|
|
||||||
inline void SetFramebuffer(const OpenGLFramebuffer& framebuffer, const RenderPass& renderPass, std::initializer_list<CommandBufferBuilder::ClearValues> clearValues);
|
inline void SetFramebuffer(const OpenGLFramebuffer& framebuffer, const RenderPass& renderPass, const CommandBufferBuilder::ClearValues* clearValues, std::size_t clearValueCount);
|
||||||
inline void SetScissor(Nz::Recti scissorRegion);
|
inline void SetScissor(Nz::Recti scissorRegion);
|
||||||
inline void SetViewport(Nz::Recti viewportRegion);
|
inline void SetViewport(Nz::Recti viewportRegion);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -133,13 +133,13 @@ namespace Nz
|
||||||
return *m_owner;
|
return *m_owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void OpenGLCommandBuffer::SetFramebuffer(const OpenGLFramebuffer& framebuffer, const RenderPass& /*renderPass*/, std::initializer_list<CommandBufferBuilder::ClearValues> clearValues)
|
inline void OpenGLCommandBuffer::SetFramebuffer(const OpenGLFramebuffer& framebuffer, const RenderPass& /*renderPass*/, const CommandBufferBuilder::ClearValues* clearValues, std::size_t clearValueCount)
|
||||||
{
|
{
|
||||||
SetFrameBufferData setFramebuffer;
|
SetFrameBufferData setFramebuffer;
|
||||||
setFramebuffer.framebuffer = &framebuffer;
|
setFramebuffer.framebuffer = &framebuffer;
|
||||||
|
|
||||||
assert(clearValues.size() < setFramebuffer.clearValues.size());
|
assert(clearValueCount < setFramebuffer.clearValues.size());
|
||||||
std::copy(clearValues.begin(), clearValues.end(), setFramebuffer.clearValues.begin());
|
std::copy(clearValues, clearValues + clearValueCount, setFramebuffer.clearValues.begin());
|
||||||
|
|
||||||
m_commands.emplace_back(std::move(setFramebuffer));
|
m_commands.emplace_back(std::move(setFramebuffer));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ namespace Nz
|
||||||
~OpenGLCommandBufferBuilder() = default;
|
~OpenGLCommandBufferBuilder() = default;
|
||||||
|
|
||||||
void BeginDebugRegion(const std::string_view& regionName, const Nz::Color& color) override;
|
void BeginDebugRegion(const std::string_view& regionName, const Nz::Color& color) override;
|
||||||
void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, std::initializer_list<ClearValues> clearValues) override;
|
void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, const ClearValues* clearValues, std::size_t clearValueCount) override;
|
||||||
|
|
||||||
void BindIndexBuffer(AbstractBuffer* indexBuffer, UInt64 offset = 0) override;
|
void BindIndexBuffer(AbstractBuffer* indexBuffer, UInt64 offset = 0) override;
|
||||||
void BindPipeline(const RenderPipeline& pipeline) override;
|
void BindPipeline(const RenderPipeline& pipeline) override;
|
||||||
|
|
@ -40,12 +40,16 @@ namespace Nz
|
||||||
void EndDebugRegion() override;
|
void EndDebugRegion() override;
|
||||||
void EndRenderPass() override;
|
void EndRenderPass() override;
|
||||||
|
|
||||||
|
void NextSubpass() override;
|
||||||
|
|
||||||
void PreTransferBarrier() override;
|
void PreTransferBarrier() override;
|
||||||
void PostTransferBarrier() override;
|
void PostTransferBarrier() override;
|
||||||
|
|
||||||
void SetScissor(Nz::Recti scissorRegion) override;
|
void SetScissor(Nz::Recti scissorRegion) override;
|
||||||
void SetViewport(Nz::Recti viewportRegion) override;
|
void SetViewport(Nz::Recti viewportRegion) override;
|
||||||
|
|
||||||
|
void TextureBarrier(PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, MemoryAccessFlags srcAccessMask, MemoryAccessFlags dstAccessMask, TextureLayout oldLayout, TextureLayout newLayout, const Texture& texture) override;
|
||||||
|
|
||||||
OpenGLCommandBufferBuilder& operator=(const OpenGLCommandBufferBuilder&) = delete;
|
OpenGLCommandBufferBuilder& operator=(const OpenGLCommandBufferBuilder&) = delete;
|
||||||
OpenGLCommandBufferBuilder& operator=(OpenGLCommandBufferBuilder&&) = delete;
|
OpenGLCommandBufferBuilder& operator=(OpenGLCommandBufferBuilder&&) = delete;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,12 @@ namespace Nz
|
||||||
// TODO: Fill this switch
|
// TODO: Fill this switch
|
||||||
switch (pixelFormat)
|
switch (pixelFormat)
|
||||||
{
|
{
|
||||||
case PixelFormat_A8: return GLTextureFormat{ GL_R8, GL_RED, GL_UNSIGNED_BYTE, GL_ZERO, GL_ZERO, GL_ZERO, GL_RED };
|
case PixelFormat_A8: return GLTextureFormat{ GL_R8, GL_RED, GL_UNSIGNED_BYTE, GL_ZERO, GL_ZERO, GL_ZERO, GL_RED };
|
||||||
case PixelFormat_BGR8: return GLTextureFormat{ GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, GL_BLUE, GL_GREEN, GL_RED, GL_ONE };
|
case PixelFormat_BGR8: return GLTextureFormat{ GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, GL_BLUE, GL_GREEN, GL_RED, GL_ONE };
|
||||||
case PixelFormat_BGR8_SRGB: return GLTextureFormat{ GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE, GL_BLUE, GL_GREEN, GL_RED, GL_ONE };
|
case PixelFormat_BGR8_SRGB: return GLTextureFormat{ GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE, GL_BLUE, GL_GREEN, GL_RED, GL_ONE };
|
||||||
case PixelFormat_BGRA8: return GLTextureFormat{ GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA };
|
case PixelFormat_BGRA8: return GLTextureFormat{ GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA };
|
||||||
case PixelFormat_BGRA8_SRGB: return GLTextureFormat{ GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA };
|
case PixelFormat_BGRA8_SRGB: return GLTextureFormat{ GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA };
|
||||||
case PixelFormat_Depth24Stencil8: return GLTextureFormat{ GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_RED, GL_GREEN, GL_ZERO, GL_ZERO };
|
case PixelFormat_Depth24Stencil8: return GLTextureFormat{ GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_RED, GL_GREEN, GL_ZERO, GL_ZERO };
|
||||||
case PixelFormat_RGB8: return GLTextureFormat{ GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, GL_RED, GL_GREEN, GL_BLUE, GL_ONE };
|
case PixelFormat_RGB8: return GLTextureFormat{ GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, GL_RED, GL_GREEN, GL_BLUE, GL_ONE };
|
||||||
case PixelFormat_RGB8_SRGB: return GLTextureFormat{ GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE, GL_RED, GL_GREEN, GL_BLUE, GL_ONE };
|
case PixelFormat_RGB8_SRGB: return GLTextureFormat{ GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE, GL_RED, GL_GREEN, GL_BLUE, GL_ONE };
|
||||||
case PixelFormat_RGBA8: return GLTextureFormat{ GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA };
|
case PixelFormat_RGBA8: return GLTextureFormat{ GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA };
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include <Nazara/Core/Color.hpp>
|
#include <Nazara/Core/Color.hpp>
|
||||||
#include <Nazara/Math/Rect.hpp>
|
#include <Nazara/Math/Rect.hpp>
|
||||||
#include <Nazara/Renderer/Config.hpp>
|
#include <Nazara/Renderer/Config.hpp>
|
||||||
|
#include <Nazara/Renderer/Enums.hpp>
|
||||||
#include <Nazara/Renderer/RenderBufferView.hpp>
|
#include <Nazara/Renderer/RenderBufferView.hpp>
|
||||||
#include <Nazara/Renderer/UploadPool.hpp>
|
#include <Nazara/Renderer/UploadPool.hpp>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
@ -21,6 +22,7 @@ namespace Nz
|
||||||
class RenderPass;
|
class RenderPass;
|
||||||
class RenderPipeline;
|
class RenderPipeline;
|
||||||
class ShaderBinding;
|
class ShaderBinding;
|
||||||
|
class Texture;
|
||||||
|
|
||||||
class NAZARA_RENDERER_API CommandBufferBuilder
|
class NAZARA_RENDERER_API CommandBufferBuilder
|
||||||
{
|
{
|
||||||
|
|
@ -33,7 +35,9 @@ namespace Nz
|
||||||
virtual ~CommandBufferBuilder();
|
virtual ~CommandBufferBuilder();
|
||||||
|
|
||||||
virtual void BeginDebugRegion(const std::string_view& regionName, const Nz::Color& color) = 0;
|
virtual void BeginDebugRegion(const std::string_view& regionName, const Nz::Color& color) = 0;
|
||||||
virtual void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, std::initializer_list<ClearValues> clearValues) = 0;
|
virtual void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, const ClearValues* clearValues, std::size_t clearValueCount) = 0;
|
||||||
|
inline void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect);
|
||||||
|
inline void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, std::initializer_list<ClearValues> clearValues);
|
||||||
|
|
||||||
virtual void BindIndexBuffer(Nz::AbstractBuffer* indexBuffer, UInt64 offset = 0) = 0;
|
virtual void BindIndexBuffer(Nz::AbstractBuffer* indexBuffer, UInt64 offset = 0) = 0;
|
||||||
virtual void BindPipeline(const RenderPipeline& pipeline) = 0;
|
virtual void BindPipeline(const RenderPipeline& pipeline) = 0;
|
||||||
|
|
@ -51,20 +55,24 @@ namespace Nz
|
||||||
virtual void EndDebugRegion() = 0;
|
virtual void EndDebugRegion() = 0;
|
||||||
virtual void EndRenderPass() = 0;
|
virtual void EndRenderPass() = 0;
|
||||||
|
|
||||||
|
virtual void NextSubpass() = 0;
|
||||||
|
|
||||||
virtual void PreTransferBarrier() = 0;
|
virtual void PreTransferBarrier() = 0;
|
||||||
virtual void PostTransferBarrier() = 0;
|
virtual void PostTransferBarrier() = 0;
|
||||||
|
|
||||||
virtual void SetScissor(Nz::Recti scissorRegion) = 0;
|
virtual void SetScissor(Nz::Recti scissorRegion) = 0;
|
||||||
virtual void SetViewport(Nz::Recti viewportRegion) = 0;
|
virtual void SetViewport(Nz::Recti viewportRegion) = 0;
|
||||||
|
|
||||||
|
virtual void TextureBarrier(PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, MemoryAccessFlags srcAccessMask, MemoryAccessFlags dstAccessMask, TextureLayout oldLayout, TextureLayout newLayout, const Texture& texture) = 0;
|
||||||
|
|
||||||
CommandBufferBuilder& operator=(const CommandBufferBuilder&) = delete;
|
CommandBufferBuilder& operator=(const CommandBufferBuilder&) = delete;
|
||||||
CommandBufferBuilder& operator=(CommandBufferBuilder&&) = default;
|
CommandBufferBuilder& operator=(CommandBufferBuilder&&) = default;
|
||||||
|
|
||||||
struct ClearValues
|
struct ClearValues
|
||||||
{
|
{
|
||||||
Nz::Color color;
|
Nz::Color color = Nz::Color::Black;
|
||||||
float depth;
|
float depth = 1.f;
|
||||||
UInt32 stencil;
|
UInt32 stencil = 0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,16 @@
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
|
inline void CommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect)
|
||||||
|
{
|
||||||
|
return BeginRenderPass(framebuffer, renderPass, renderRect, nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, std::initializer_list<ClearValues> clearValues)
|
||||||
|
{
|
||||||
|
return BeginRenderPass(framebuffer, renderPass, renderRect, clearValues.begin(), clearValues.size());
|
||||||
|
}
|
||||||
|
|
||||||
inline void CommandBufferBuilder::CopyBuffer(const RenderBufferView& from, const RenderBufferView& to)
|
inline void CommandBufferBuilder::CopyBuffer(const RenderBufferView& from, const RenderBufferView& to)
|
||||||
{
|
{
|
||||||
return CopyBuffer(from, to, from.GetSize());
|
return CopyBuffer(from, to, from.GetSize());
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ namespace Nz
|
||||||
inline std::size_t GetAttachmentCount() const;
|
inline std::size_t GetAttachmentCount() const;
|
||||||
inline const std::vector<Attachment>& GetAttachments() const;
|
inline const std::vector<Attachment>& GetAttachments() const;
|
||||||
inline const std::vector<SubpassDescription>& GetSubpassDescriptions() const;
|
inline const std::vector<SubpassDescription>& GetSubpassDescriptions() const;
|
||||||
inline const std::vector<SubpassDependency>& GetsubpassDependencies() const;
|
inline const std::vector<SubpassDependency>& GetSubpassDependencies() const;
|
||||||
|
|
||||||
RenderPass& operator=(const RenderPass&) = delete;
|
RenderPass& operator=(const RenderPass&) = delete;
|
||||||
RenderPass& operator=(RenderPass&&) noexcept = default;
|
RenderPass& operator=(RenderPass&&) noexcept = default;
|
||||||
|
|
@ -60,6 +60,7 @@ namespace Nz
|
||||||
std::size_t fromSubpassIndex;
|
std::size_t fromSubpassIndex;
|
||||||
PipelineStageFlags fromStages;
|
PipelineStageFlags fromStages;
|
||||||
MemoryAccessFlags fromAccessFlags;
|
MemoryAccessFlags fromAccessFlags;
|
||||||
|
|
||||||
std::size_t toSubpassIndex;
|
std::size_t toSubpassIndex;
|
||||||
PipelineStageFlags toStages;
|
PipelineStageFlags toStages;
|
||||||
MemoryAccessFlags toAccessFlags;
|
MemoryAccessFlags toAccessFlags;
|
||||||
|
|
@ -70,6 +71,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
std::vector<AttachmentReference> colorAttachment;
|
std::vector<AttachmentReference> colorAttachment;
|
||||||
std::vector<AttachmentReference> inputAttachments;
|
std::vector<AttachmentReference> inputAttachments;
|
||||||
|
std::vector<std::size_t> preserveAttachments;
|
||||||
std::optional<AttachmentReference> depthStencilAttachment;
|
std::optional<AttachmentReference> depthStencilAttachment;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ namespace Nz
|
||||||
return m_subpassDescriptions;
|
return m_subpassDescriptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto RenderPass::GetsubpassDependencies() const -> const std::vector<SubpassDependency>&
|
inline auto RenderPass::GetSubpassDependencies() const -> const std::vector<SubpassDependency>&
|
||||||
{
|
{
|
||||||
return m_subpassDependencies;
|
return m_subpassDependencies;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -338,14 +338,14 @@ namespace Nz
|
||||||
{
|
{
|
||||||
switch (textureLayout)
|
switch (textureLayout)
|
||||||
{
|
{
|
||||||
case TextureLayout::ColorInput: return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
case TextureLayout::ColorInput: return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
case TextureLayout::ColorOutput: return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
case TextureLayout::ColorOutput: return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
case TextureLayout::DepthStencilInput: return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
|
case TextureLayout::DepthStencilReadOnly: return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
|
||||||
case TextureLayout::DepthStencilOutput: return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
case TextureLayout::DepthStencilReadWrite: return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
case TextureLayout::Present: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
case TextureLayout::Present: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||||
case TextureLayout::TransferSource: return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
case TextureLayout::TransferSource: return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||||
case TextureLayout::TransferDestination: return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
case TextureLayout::TransferDestination: return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
case TextureLayout::Undefined: return VK_IMAGE_LAYOUT_UNDEFINED;
|
case TextureLayout::Undefined: return VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
NazaraError("Unhandled TextureLayout 0x" + NumberToString(UnderlyingCast(textureLayout), 16));
|
NazaraError("Unhandled TextureLayout 0x" + NumberToString(UnderlyingCast(textureLayout), 16));
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,10 @@ namespace Nz
|
||||||
|
|
||||||
inline Vk::CommandBuffer& VulkanCommandBuffer::GetCommandBuffer(std::size_t imageIndex)
|
inline Vk::CommandBuffer& VulkanCommandBuffer::GetCommandBuffer(std::size_t imageIndex)
|
||||||
{
|
{
|
||||||
|
if (m_commandBuffers.size() == 1)
|
||||||
|
return m_commandBuffers.front();
|
||||||
|
|
||||||
|
assert(imageIndex < m_commandBuffers.size());
|
||||||
return m_commandBuffers[imageIndex].Get();
|
return m_commandBuffers[imageIndex].Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ namespace Nz
|
||||||
~VulkanCommandBufferBuilder() = default;
|
~VulkanCommandBufferBuilder() = default;
|
||||||
|
|
||||||
void BeginDebugRegion(const std::string_view& regionName, const Nz::Color& color) override;
|
void BeginDebugRegion(const std::string_view& regionName, const Nz::Color& color) override;
|
||||||
void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, std::initializer_list<ClearValues> clearValues) override;
|
void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, const ClearValues* clearValues, std::size_t clearValueCount) override;
|
||||||
|
|
||||||
void BindIndexBuffer(AbstractBuffer* indexBuffer, UInt64 offset = 0) override;
|
void BindIndexBuffer(AbstractBuffer* indexBuffer, UInt64 offset = 0) override;
|
||||||
void BindPipeline(const RenderPipeline& pipeline) override;
|
void BindPipeline(const RenderPipeline& pipeline) override;
|
||||||
|
|
@ -44,12 +44,16 @@ namespace Nz
|
||||||
inline Vk::CommandBuffer& GetCommandBuffer();
|
inline Vk::CommandBuffer& GetCommandBuffer();
|
||||||
inline std::size_t GetMaxFramebufferCount() const;
|
inline std::size_t GetMaxFramebufferCount() const;
|
||||||
|
|
||||||
|
void NextSubpass() override;
|
||||||
|
|
||||||
void PreTransferBarrier() override;
|
void PreTransferBarrier() override;
|
||||||
void PostTransferBarrier() override;
|
void PostTransferBarrier() override;
|
||||||
|
|
||||||
void SetScissor(Nz::Recti scissorRegion) override;
|
void SetScissor(Nz::Recti scissorRegion) override;
|
||||||
void SetViewport(Nz::Recti viewportRegion) override;
|
void SetViewport(Nz::Recti viewportRegion) override;
|
||||||
|
|
||||||
|
void TextureBarrier(PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, MemoryAccessFlags srcAccessMask, MemoryAccessFlags dstAccessMask, TextureLayout oldLayout, TextureLayout newLayout, const Texture& texture) override;
|
||||||
|
|
||||||
VulkanCommandBufferBuilder& operator=(const VulkanCommandBufferBuilder&) = delete;
|
VulkanCommandBufferBuilder& operator=(const VulkanCommandBufferBuilder&) = delete;
|
||||||
VulkanCommandBufferBuilder& operator=(VulkanCommandBufferBuilder&&) = delete;
|
VulkanCommandBufferBuilder& operator=(VulkanCommandBufferBuilder&&) = delete;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,11 +70,15 @@ namespace Nz
|
||||||
|
|
||||||
inline CommandPool& GetPool();
|
inline CommandPool& GetPool();
|
||||||
|
|
||||||
|
inline void ImageBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldLayout, VkImageLayout newLayout, VkImage image, VkImageAspectFlags aspectFlags);
|
||||||
|
|
||||||
inline void InsertDebugLabel(const char* label);
|
inline void InsertDebugLabel(const char* label);
|
||||||
inline void InsertDebugLabel(const char* label, Nz::Color color);
|
inline void InsertDebugLabel(const char* label, Nz::Color color);
|
||||||
|
|
||||||
inline void MemoryBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask);
|
inline void MemoryBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask);
|
||||||
|
|
||||||
|
inline void NextSubpass(VkSubpassContents contents = VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
|
||||||
inline void PipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, const VkImageMemoryBarrier& imageMemoryBarrier);
|
inline void PipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, const VkImageMemoryBarrier& imageMemoryBarrier);
|
||||||
inline void PipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, const VkMemoryBarrier& memoryBarrier);
|
inline void PipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, const VkMemoryBarrier& memoryBarrier);
|
||||||
inline void PipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, UInt32 memoryBarrierCount, const VkMemoryBarrier* memoryBarriers, UInt32 bufferMemoryBarrierCount, const VkBufferMemoryBarrier* bufferMemoryBarriers, UInt32 imageMemoryBarrierCount, const VkImageMemoryBarrier* imageMemoryBarriers);
|
inline void PipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, UInt32 memoryBarrierCount, const VkMemoryBarrier* memoryBarriers, UInt32 bufferMemoryBarrierCount, const VkBufferMemoryBarrier* bufferMemoryBarriers, UInt32 imageMemoryBarrierCount, const VkImageMemoryBarrier* imageMemoryBarriers);
|
||||||
|
|
|
||||||
|
|
@ -295,6 +295,28 @@ namespace Nz
|
||||||
return *m_pool;
|
return *m_pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void CommandBuffer::ImageBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldLayout, VkImageLayout newLayout, VkImage image, VkImageAspectFlags aspectFlags)
|
||||||
|
{
|
||||||
|
VkImageMemoryBarrier imageBarrier = {
|
||||||
|
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
|
nullptr,
|
||||||
|
srcAccessMask,
|
||||||
|
dstAccessMask,
|
||||||
|
oldLayout,
|
||||||
|
newLayout,
|
||||||
|
VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
image,
|
||||||
|
{
|
||||||
|
aspectFlags,
|
||||||
|
0, 1,
|
||||||
|
0, 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return PipelineBarrier(srcStageMask, dstStageMask, dependencyFlags, imageBarrier);
|
||||||
|
}
|
||||||
|
|
||||||
inline void CommandBuffer::InsertDebugLabel(const char* label)
|
inline void CommandBuffer::InsertDebugLabel(const char* label)
|
||||||
{
|
{
|
||||||
return InsertDebugLabel(label, Nz::Color(0, 0, 0, 0));
|
return InsertDebugLabel(label, Nz::Color(0, 0, 0, 0));
|
||||||
|
|
@ -333,6 +355,11 @@ namespace Nz
|
||||||
return PipelineBarrier(srcStageMask, dstStageMask, 0U, memoryBarrier);
|
return PipelineBarrier(srcStageMask, dstStageMask, 0U, memoryBarrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void CommandBuffer::NextSubpass(VkSubpassContents contents)
|
||||||
|
{
|
||||||
|
return m_pool->GetDevice()->vkCmdNextSubpass(m_handle, contents);
|
||||||
|
}
|
||||||
|
|
||||||
inline void CommandBuffer::PipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, const VkImageMemoryBarrier& imageMemoryBarrier)
|
inline void CommandBuffer::PipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, const VkImageMemoryBarrier& imageMemoryBarrier)
|
||||||
{
|
{
|
||||||
return PipelineBarrier(srcStageMask, dstStageMask, dependencyFlags, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
|
return PipelineBarrier(srcStageMask, dstStageMask, dependencyFlags, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,160 @@
|
||||||
|
// 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/Graphics.hpp>
|
||||||
|
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
|
||||||
|
#include <Nazara/Renderer/RenderFrame.hpp>
|
||||||
|
#include <Nazara/Graphics/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
BakedFrameGraph::BakedFrameGraph(std::vector<PassData> passes, std::vector<TextureData> textures, AttachmentIdToTextureId attachmentIdToTextureMapping, PassIdToPhysicalPassIndex passIdToPhysicalPassMapping) :
|
||||||
|
m_passes(std::move(passes)),
|
||||||
|
m_textures(std::move(textures)),
|
||||||
|
m_attachmentToTextureMapping(std::move(attachmentIdToTextureMapping)),
|
||||||
|
m_passIdToPhysicalPassMapping(std::move(passIdToPhysicalPassMapping))
|
||||||
|
{
|
||||||
|
RenderDevice& renderDevice = Graphics::Instance()->GetRenderDevice();
|
||||||
|
m_commandPool = renderDevice.InstantiateCommandPool(QueueType::Graphics);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BakedFrameGraph::Execute(RenderFrame& renderFrame)
|
||||||
|
{
|
||||||
|
for (auto& passData : m_passes)
|
||||||
|
{
|
||||||
|
bool regenerateCommandBuffer = (passData.commandBuffer == nullptr);
|
||||||
|
if (passData.executionCallback)
|
||||||
|
{
|
||||||
|
switch (passData.executionCallback())
|
||||||
|
{
|
||||||
|
case FramePassExecution::Execute:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FramePassExecution::Skip:
|
||||||
|
passData.commandBuffer.reset();
|
||||||
|
continue; //< Skip the pass
|
||||||
|
|
||||||
|
case FramePassExecution::UpdateAndExecute:
|
||||||
|
regenerateCommandBuffer = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!regenerateCommandBuffer)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
passData.commandBuffer.reset(); //< Release command buffer resources before reallocating it
|
||||||
|
passData.commandBuffer = m_commandPool->BuildCommandBuffer([&](CommandBufferBuilder& builder)
|
||||||
|
{
|
||||||
|
for (auto& textureTransition : passData.transitions)
|
||||||
|
{
|
||||||
|
const std::shared_ptr<Texture>& texture = m_textures[textureTransition.textureId].texture;
|
||||||
|
builder.TextureBarrier(textureTransition.srcStageMask, textureTransition.dstStageMask, textureTransition.srcAccessMask, textureTransition.dstAccessMask, textureTransition.oldLayout, textureTransition.newLayout, *texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.BeginRenderPass(*passData.framebuffer, *passData.renderPass, passData.renderRect);
|
||||||
|
|
||||||
|
bool first = true;
|
||||||
|
for (auto& subpass : passData.subpasses)
|
||||||
|
{
|
||||||
|
if (!first)
|
||||||
|
builder.NextSubpass();
|
||||||
|
|
||||||
|
first = false;
|
||||||
|
|
||||||
|
subpass.commandCallback(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.EndRenderPass();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Submit all commands buffer at once
|
||||||
|
for (auto& passData : m_passes)
|
||||||
|
{
|
||||||
|
if (passData.commandBuffer)
|
||||||
|
renderFrame.SubmitCommandBuffer(passData.commandBuffer.get(), QueueType::Graphics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::shared_ptr<Texture>& BakedFrameGraph::GetAttachmentTexture(std::size_t attachmentIndex) const
|
||||||
|
{
|
||||||
|
auto it = m_attachmentToTextureMapping.find(attachmentIndex);
|
||||||
|
if (it == m_attachmentToTextureMapping.end())
|
||||||
|
{
|
||||||
|
static std::shared_ptr<Texture> dummy;
|
||||||
|
return dummy;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t textureIndex = it->second;
|
||||||
|
assert(textureIndex < m_textures.size());
|
||||||
|
return m_textures[textureIndex].texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::shared_ptr<RenderPass>& BakedFrameGraph::GetRenderPass(std::size_t passIndex) const
|
||||||
|
{
|
||||||
|
auto it = m_attachmentToTextureMapping.find(passIndex);
|
||||||
|
if (it == m_attachmentToTextureMapping.end())
|
||||||
|
{
|
||||||
|
static std::shared_ptr<RenderPass> dummy;
|
||||||
|
return dummy;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t physicalPassIndex = it->second;
|
||||||
|
assert(physicalPassIndex < m_passes.size());
|
||||||
|
return m_passes[physicalPassIndex].renderPass;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BakedFrameGraph::Resize(unsigned int width, unsigned int height)
|
||||||
|
{
|
||||||
|
RenderDevice& renderDevice = Graphics::Instance()->GetRenderDevice();
|
||||||
|
|
||||||
|
// Delete previous textures to make some room in VRAM
|
||||||
|
for (auto& passData : m_passes)
|
||||||
|
{
|
||||||
|
passData.commandBuffer.reset();
|
||||||
|
passData.framebuffer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& textureData : m_textures)
|
||||||
|
textureData.texture.reset();
|
||||||
|
|
||||||
|
for (auto& textureData : m_textures)
|
||||||
|
{
|
||||||
|
TextureInfo textureCreationParams;
|
||||||
|
textureCreationParams.type = ImageType_2D;
|
||||||
|
textureCreationParams.width = textureData.width * width / 100'000;
|
||||||
|
textureCreationParams.height = textureData.height * height / 100'000;
|
||||||
|
textureCreationParams.usageFlags = textureData.usage;
|
||||||
|
textureCreationParams.pixelFormat = textureData.format;
|
||||||
|
|
||||||
|
textureData.texture = renderDevice.InstantiateTexture(textureCreationParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<Texture>> textures;
|
||||||
|
for (auto& passData : m_passes)
|
||||||
|
{
|
||||||
|
textures.clear();
|
||||||
|
|
||||||
|
unsigned int framebufferWidth = std::numeric_limits<unsigned int>::max();
|
||||||
|
unsigned int framebufferHeight = std::numeric_limits<unsigned int>::max();
|
||||||
|
for (std::size_t textureId : passData.outputTextureIndices)
|
||||||
|
{
|
||||||
|
auto& textureData = m_textures[textureId];
|
||||||
|
textures.push_back(textureData.texture);
|
||||||
|
|
||||||
|
framebufferWidth = std::min(framebufferWidth, textureData.width);
|
||||||
|
framebufferHeight = std::min(framebufferHeight, textureData.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
framebufferWidth = framebufferWidth * width / 100'000;
|
||||||
|
framebufferHeight = framebufferHeight * height / 100'000;
|
||||||
|
|
||||||
|
passData.renderRect.Set(0, 0, int(framebufferWidth), int(framebufferHeight));
|
||||||
|
|
||||||
|
passData.framebuffer = renderDevice.InstantiateFramebuffer(framebufferWidth, framebufferHeight, passData.renderPass, textures);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,913 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// This class was written with a lot of help from themaister articles and Granite source code, check them out!
|
||||||
|
// https://themaister.net/blog/2017/08/15/render-graphs-and-vulkan-a-deep-dive/
|
||||||
|
|
||||||
|
#include <Nazara/Graphics/FrameGraph.hpp>
|
||||||
|
#include <Nazara/Graphics/Graphics.hpp>
|
||||||
|
#include <Nazara/Core/StackArray.hpp>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <Nazara/Graphics/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
template<typename T> const T& Retrieve(const std::unordered_map<std::size_t, T>& map, std::size_t id)
|
||||||
|
{
|
||||||
|
auto it = map.find(id);
|
||||||
|
assert(it != map.end());
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> void UniquePushBack(std::vector<T>& vec, const T& value)
|
||||||
|
{
|
||||||
|
auto it = std::find(vec.begin(), vec.end(), value);
|
||||||
|
if (it == vec.end())
|
||||||
|
vec.push_back(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BakedFrameGraph FrameGraph::Bake()
|
||||||
|
{
|
||||||
|
if (!m_backbufferOutput.has_value())
|
||||||
|
throw std::runtime_error("no backbuffer output has been set");
|
||||||
|
|
||||||
|
m_pending.attachmentReadList.clear();
|
||||||
|
m_pending.attachmentToTextures.clear();
|
||||||
|
m_pending.attachmentWriteList.clear();
|
||||||
|
m_pending.barrierList.clear();
|
||||||
|
m_pending.passIdToPhysicalPassIndex.clear();
|
||||||
|
m_pending.passList.clear();
|
||||||
|
m_pending.physicalPasses.clear();
|
||||||
|
m_pending.renderPasses.clear();
|
||||||
|
m_pending.textures.clear();
|
||||||
|
|
||||||
|
m_pending.backbufferResourceIndex = m_backbufferOutput.value();
|
||||||
|
|
||||||
|
BuildReadWriteList();
|
||||||
|
|
||||||
|
auto it = m_pending.attachmentWriteList.find(m_pending.backbufferResourceIndex);
|
||||||
|
if (it == m_pending.attachmentWriteList.end())
|
||||||
|
throw std::runtime_error("no pass writes to backbuffer");
|
||||||
|
|
||||||
|
const std::vector<std::size_t>& backbufferPasses = it->second;
|
||||||
|
for (std::size_t passIndex : backbufferPasses)
|
||||||
|
TraverseGraph(passIndex);
|
||||||
|
|
||||||
|
std::reverse(m_pending.passList.begin(), m_pending.passList.end());
|
||||||
|
|
||||||
|
RemoveDuplicatePasses();
|
||||||
|
ReorderPasses();
|
||||||
|
AssignPhysicalTextures();
|
||||||
|
AssignPhysicalPasses();
|
||||||
|
BuildPhysicalPasses();
|
||||||
|
//BuildBarriers();
|
||||||
|
//BuildPhysicalBarriers();
|
||||||
|
|
||||||
|
std::vector<BakedFrameGraph::PassData> bakedPasses;
|
||||||
|
bakedPasses.reserve(m_pending.physicalPasses.size());
|
||||||
|
|
||||||
|
std::size_t renderPassIndex = 0;
|
||||||
|
for (auto& physicalPass : m_pending.physicalPasses)
|
||||||
|
{
|
||||||
|
auto& bakedPass = bakedPasses.emplace_back();
|
||||||
|
bakedPass.renderPass = std::move(m_pending.renderPasses[renderPassIndex++]);
|
||||||
|
bakedPass.transitions = std::move(physicalPass.textureTransitions);
|
||||||
|
|
||||||
|
for (auto& subpass : physicalPass.passes)
|
||||||
|
{
|
||||||
|
const FramePass& framePass = m_framePasses[subpass.passIndex];
|
||||||
|
bakedPass.executionCallback = framePass.GetExecutionCallback(); //< FIXME
|
||||||
|
|
||||||
|
auto& bakedSubpass = bakedPass.subpasses.emplace_back();
|
||||||
|
bakedSubpass.commandCallback = framePass.GetCommandCallback();
|
||||||
|
|
||||||
|
for (const auto& output : framePass.GetOutputs())
|
||||||
|
bakedPass.outputTextureIndices.push_back(Retrieve(m_pending.attachmentToTextures, output.attachmentId));
|
||||||
|
|
||||||
|
if (std::size_t attachmentId = framePass.GetDepthStencilOutput(); attachmentId != FramePass::InvalidAttachmentId)
|
||||||
|
bakedPass.outputTextureIndices.push_back(Retrieve(m_pending.attachmentToTextures, attachmentId));
|
||||||
|
else if (std::size_t attachmentId = framePass.GetDepthStencilInput(); attachmentId != FramePass::InvalidAttachmentId)
|
||||||
|
bakedPass.outputTextureIndices.push_back(Retrieve(m_pending.attachmentToTextures, attachmentId)); //< FIXME?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<BakedFrameGraph::TextureData> bakedTextures;
|
||||||
|
bakedTextures.reserve(m_pending.textures.size());
|
||||||
|
for (auto& texture : m_pending.textures)
|
||||||
|
{
|
||||||
|
auto& bakedTexture = bakedTextures.emplace_back();
|
||||||
|
bakedTexture.format = texture.format;
|
||||||
|
bakedTexture.height = texture.height;
|
||||||
|
bakedTexture.usage = texture.usage;
|
||||||
|
bakedTexture.width = texture.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BakedFrameGraph(std::move(bakedPasses), std::move(bakedTextures), std::move(m_pending.attachmentToTextures), std::move(m_pending.passIdToPhysicalPassIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameGraph::AssignPhysicalPasses()
|
||||||
|
{
|
||||||
|
auto ShouldMerge = [&](const FramePass& prevPass, const FramePass& nextPass)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (std::size_t passIndex = 0; passIndex < m_pending.passList.size();)
|
||||||
|
{
|
||||||
|
std::size_t mergeEnd = passIndex + 1;
|
||||||
|
for (; mergeEnd < m_pending.passList.size(); ++mergeEnd)
|
||||||
|
{
|
||||||
|
bool merge = true;
|
||||||
|
for (std::size_t mergeStart = passIndex; mergeStart < mergeEnd; ++mergeStart)
|
||||||
|
{
|
||||||
|
if (!ShouldMerge(m_framePasses[m_pending.passList[mergeStart]], m_framePasses[m_pending.passList[mergeEnd]]))
|
||||||
|
{
|
||||||
|
merge = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!merge)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t physPassIndex = m_pending.physicalPasses.size();
|
||||||
|
PhysicalPassData& currentPass = m_pending.physicalPasses.emplace_back();
|
||||||
|
|
||||||
|
auto begin = m_pending.passList.begin() + passIndex;
|
||||||
|
auto end = m_pending.passList.begin() + mergeEnd;
|
||||||
|
|
||||||
|
for (; begin < end; ++begin)
|
||||||
|
{
|
||||||
|
auto& subpass = currentPass.passes.emplace_back();
|
||||||
|
subpass.passIndex = *begin;
|
||||||
|
m_pending.passIdToPhysicalPassIndex.emplace(subpass.passIndex, physPassIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
passIndex = mergeEnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameGraph::AssignPhysicalTextures()
|
||||||
|
{
|
||||||
|
auto RegisterTexture = [&](std::size_t attachmentIndex)
|
||||||
|
{
|
||||||
|
if (auto it = m_pending.attachmentToTextures.find(attachmentIndex); it == m_pending.attachmentToTextures.end())
|
||||||
|
{
|
||||||
|
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 = 100'000;
|
||||||
|
data.height = 100'000;
|
||||||
|
|
||||||
|
return textureId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return it->second;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (std::size_t passIndex : m_pending.passList)
|
||||||
|
{
|
||||||
|
const FramePass& framePass = m_framePasses[passIndex];
|
||||||
|
|
||||||
|
for (const auto& input : framePass.GetInputs())
|
||||||
|
{
|
||||||
|
std::size_t textureId = RegisterTexture(input.attachmentId);
|
||||||
|
|
||||||
|
TextureData& attachmentData = m_pending.textures[textureId];
|
||||||
|
attachmentData.usage |= TextureUsage::ShaderSampling;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& output : framePass.GetOutputs())
|
||||||
|
{
|
||||||
|
std::size_t textureId = RegisterTexture(output.attachmentId);
|
||||||
|
|
||||||
|
TextureData& attachmentData = m_pending.textures[textureId];
|
||||||
|
attachmentData.usage |= TextureUsage::ColorAttachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::size_t depthStencilInput = framePass.GetDepthStencilInput(); depthStencilInput != FramePass::InvalidAttachmentId)
|
||||||
|
{
|
||||||
|
std::size_t textureId = RegisterTexture(depthStencilInput);
|
||||||
|
|
||||||
|
TextureData& attachmentData = m_pending.textures[textureId];
|
||||||
|
attachmentData.usage |= TextureUsage::DepthStencilAttachment;
|
||||||
|
|
||||||
|
if (std::size_t depthStencilOutput = framePass.GetDepthStencilOutput(); depthStencilOutput != FramePass::InvalidAttachmentId)
|
||||||
|
{
|
||||||
|
if (auto it = m_pending.attachmentToTextures.find(depthStencilOutput); it == m_pending.attachmentToTextures.end())
|
||||||
|
m_pending.attachmentToTextures.emplace(depthStencilOutput, textureId);
|
||||||
|
else
|
||||||
|
throw std::runtime_error("depth-stencil output already assigned");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::size_t depthStencilOutput = framePass.GetDepthStencilOutput(); depthStencilOutput != FramePass::InvalidAttachmentId)
|
||||||
|
{
|
||||||
|
std::size_t textureId = RegisterTexture(depthStencilOutput);
|
||||||
|
|
||||||
|
TextureData& attachmentData = m_pending.textures[textureId];
|
||||||
|
attachmentData.usage |= TextureUsage::DepthStencilAttachment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add TextureUsage::Sampled to backbuffer output
|
||||||
|
|
||||||
|
auto it = m_pending.attachmentToTextures.find(m_pending.backbufferResourceIndex);
|
||||||
|
assert(it != m_pending.attachmentToTextures.end());
|
||||||
|
|
||||||
|
auto& backbufferTexture = m_pending.textures[it->second];
|
||||||
|
backbufferTexture.usage |= TextureUsage::ShaderSampling;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameGraph::BuildBarriers()
|
||||||
|
{
|
||||||
|
assert(m_pending.barrierList.empty());
|
||||||
|
m_pending.barrierList.reserve(m_pending.passList.size());
|
||||||
|
|
||||||
|
auto GetBarrier = [&](std::vector<Barrier>& barriers, std::size_t attachmentId) -> Barrier&
|
||||||
|
{
|
||||||
|
std::size_t textureId = Retrieve(m_pending.attachmentToTextures, attachmentId);
|
||||||
|
|
||||||
|
auto it = std::find_if(barriers.begin(), barriers.end(), [&](const Barrier& barrier) { return barrier.textureId == textureId; });
|
||||||
|
if (it != barriers.end())
|
||||||
|
return *it;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Insert a new barrier
|
||||||
|
auto& barrier = barriers.emplace_back();
|
||||||
|
barrier.textureId = textureId;
|
||||||
|
barrier.layout = TextureLayout::Undefined;
|
||||||
|
|
||||||
|
return barrier;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
for (std::size_t passId : m_pending.passList)
|
||||||
|
{
|
||||||
|
const FramePass& framePass = m_framePasses[passId];
|
||||||
|
|
||||||
|
auto& barriers = m_pending.barrierList.emplace_back();
|
||||||
|
|
||||||
|
auto GetInvalidationBarrier = [&](std::size_t attachmentId) -> Barrier& { return GetBarrier(barriers.invalidationBarriers, attachmentId); };
|
||||||
|
auto GetFlushBarrier = [&](std::size_t attachmentId) -> Barrier& { return GetBarrier(barriers.flushBarriers, attachmentId); };
|
||||||
|
|
||||||
|
for (const auto& input : framePass.GetInputs())
|
||||||
|
{
|
||||||
|
auto& barrier = GetInvalidationBarrier(input.attachmentId);
|
||||||
|
if (barrier.layout != TextureLayout::Undefined)
|
||||||
|
throw std::runtime_error("layout mismatch");
|
||||||
|
|
||||||
|
barrier.access |= MemoryAccess::ColorRead | MemoryAccess::ColorWrite;
|
||||||
|
barrier.stages |= PipelineStage::ColorOutput;
|
||||||
|
barrier.layout = TextureLayout::ColorInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& output : framePass.GetOutputs())
|
||||||
|
{
|
||||||
|
auto& barrier = GetFlushBarrier(output.attachmentId);
|
||||||
|
if (barrier.layout != TextureLayout::Undefined)
|
||||||
|
throw std::runtime_error("layout mismatch");
|
||||||
|
|
||||||
|
barrier.access |= MemoryAccess::ColorRead | MemoryAccess::ColorWrite;
|
||||||
|
barrier.stages |= PipelineStage::ColorOutput;
|
||||||
|
barrier.layout = TextureLayout::ColorOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t dsInputAttachment = framePass.GetDepthStencilInput();
|
||||||
|
std::size_t dsOutputAttachement = framePass.GetDepthStencilOutput();
|
||||||
|
bool depthRead = false;
|
||||||
|
|
||||||
|
if (dsInputAttachment != FramePass::InvalidAttachmentId && dsOutputAttachement != FramePass::InvalidAttachmentId)
|
||||||
|
{
|
||||||
|
// DS input/output
|
||||||
|
auto& invalidationBarrier = GetInvalidationBarrier(dsInputAttachment);
|
||||||
|
if (invalidationBarrier.layout != TextureLayout::Undefined)
|
||||||
|
throw std::runtime_error("layout mismatch");
|
||||||
|
|
||||||
|
invalidationBarrier.layout = TextureLayout::DepthStencilReadWrite;
|
||||||
|
invalidationBarrier.access = MemoryAccess::DepthStencilRead | MemoryAccess::DepthStencilWrite;
|
||||||
|
invalidationBarrier.stages = PipelineStage::FragmentTestsEarly | PipelineStage::FragmentTestsLate;
|
||||||
|
|
||||||
|
auto& flushBarrier = GetInvalidationBarrier(dsOutputAttachement);
|
||||||
|
flushBarrier.layout = TextureLayout::DepthStencilReadWrite;
|
||||||
|
flushBarrier.access = MemoryAccess::DepthStencilWrite;
|
||||||
|
flushBarrier.stages = PipelineStage::FragmentTestsLate;
|
||||||
|
}
|
||||||
|
else if (dsInputAttachment != FramePass::InvalidAttachmentId)
|
||||||
|
{
|
||||||
|
// DS input-only
|
||||||
|
auto& invalidationBarrier = GetInvalidationBarrier(dsInputAttachment);
|
||||||
|
if (invalidationBarrier.layout != TextureLayout::Undefined)
|
||||||
|
throw std::runtime_error("layout mismatch");
|
||||||
|
|
||||||
|
invalidationBarrier.layout = TextureLayout::DepthStencilReadWrite;
|
||||||
|
invalidationBarrier.access = MemoryAccess::DepthStencilRead;
|
||||||
|
invalidationBarrier.stages = PipelineStage::FragmentTestsEarly | PipelineStage::FragmentTestsLate;
|
||||||
|
}
|
||||||
|
else if (dsOutputAttachement != FramePass::InvalidAttachmentId)
|
||||||
|
{
|
||||||
|
// DS output-only
|
||||||
|
auto& flushBarrier = GetInvalidationBarrier(dsOutputAttachement);
|
||||||
|
if (flushBarrier.layout != TextureLayout::Undefined)
|
||||||
|
throw std::runtime_error("layout mismatch");
|
||||||
|
|
||||||
|
flushBarrier.layout = TextureLayout::DepthStencilReadWrite;
|
||||||
|
flushBarrier.access = MemoryAccess::DepthStencilWrite;
|
||||||
|
flushBarrier.stages = PipelineStage::FragmentTestsLate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameGraph::BuildPhysicalBarriers()
|
||||||
|
{
|
||||||
|
struct TextureStates
|
||||||
|
{
|
||||||
|
MemoryAccessFlags invalidatedAccesses;
|
||||||
|
MemoryAccessFlags flushedAccesses;
|
||||||
|
PipelineStageFlags invalidatedStages;
|
||||||
|
PipelineStageFlags flushedStages;
|
||||||
|
TextureLayout initialLayout = TextureLayout::Undefined;
|
||||||
|
TextureLayout finalLayout = TextureLayout::Undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<TextureStates> textureStates;
|
||||||
|
|
||||||
|
auto barriersIt = m_pending.barrierList.begin();
|
||||||
|
for (auto& physicalPass : m_pending.physicalPasses)
|
||||||
|
{
|
||||||
|
textureStates.clear();
|
||||||
|
textureStates.resize(m_pending.textures.size());
|
||||||
|
|
||||||
|
for (auto& subpass : physicalPass.passes)
|
||||||
|
{
|
||||||
|
auto& barriers = *barriersIt++;
|
||||||
|
|
||||||
|
for (auto& invalidation : barriers.invalidationBarriers)
|
||||||
|
{
|
||||||
|
auto& states = textureStates[invalidation.textureId];
|
||||||
|
if (states.initialLayout == TextureLayout::Undefined)
|
||||||
|
{
|
||||||
|
states.invalidatedAccesses |= invalidation.access;
|
||||||
|
states.invalidatedStages |= invalidation.stages;
|
||||||
|
states.initialLayout = invalidation.layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
states.finalLayout = invalidation.layout;
|
||||||
|
states.flushedAccesses = 0;
|
||||||
|
states.flushedStages = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& flush : barriers.flushBarriers)
|
||||||
|
{
|
||||||
|
auto& states = textureStates[flush.textureId];
|
||||||
|
states.flushedAccesses |= flush.access;
|
||||||
|
states.flushedStages |= flush.stages;
|
||||||
|
states.finalLayout = flush.layout;
|
||||||
|
|
||||||
|
if (states.initialLayout == TextureLayout::Undefined)
|
||||||
|
{
|
||||||
|
// First flush in a render pass needs a matching invalidation
|
||||||
|
states.initialLayout = flush.layout;
|
||||||
|
states.invalidatedAccesses = flush.access;
|
||||||
|
states.invalidatedStages = flush.stages;
|
||||||
|
|
||||||
|
if (states.invalidatedAccesses & MemoryAccess::ColorWrite)
|
||||||
|
states.invalidatedAccesses |= MemoryAccess::ColorRead;
|
||||||
|
|
||||||
|
if (states.invalidatedAccesses & MemoryAccess::DepthStencilWrite)
|
||||||
|
states.invalidatedAccesses |= MemoryAccess::DepthStencilRead;
|
||||||
|
|
||||||
|
if (states.invalidatedAccesses & MemoryAccess::ShaderWrite)
|
||||||
|
states.invalidatedAccesses |= MemoryAccess::ShaderRead;
|
||||||
|
|
||||||
|
// TODO: Discard resource
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (std::size_t textureId = 0; textureId < textureStates.size(); ++textureId)
|
||||||
|
{
|
||||||
|
const auto& state = textureStates[textureId];
|
||||||
|
|
||||||
|
if (state.initialLayout == TextureLayout::Undefined && state.finalLayout == TextureLayout::Undefined)
|
||||||
|
continue; //< Texture wasn't touched in this pass
|
||||||
|
|
||||||
|
assert(state.finalLayout != TextureLayout::Undefined);
|
||||||
|
|
||||||
|
// TODO: Register invalidation
|
||||||
|
|
||||||
|
if (state.flushedAccesses)
|
||||||
|
; // TODO: Register flush
|
||||||
|
|
||||||
|
if (state.invalidatedAccesses)
|
||||||
|
; // TODO: Register flush
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameGraph::BuildPhysicalPassDependencies(std::size_t colorAttachmentCount, bool hasDepthStencilAttachment, std::vector<RenderPass::Attachment>& renderPassAttachments, std::vector<RenderPass::SubpassDescription>& subpasses, std::vector<RenderPass::SubpassDependency>& dependencies)
|
||||||
|
{
|
||||||
|
if (hasDepthStencilAttachment)
|
||||||
|
{
|
||||||
|
auto& depthStencilAttachment = renderPassAttachments[colorAttachmentCount];
|
||||||
|
|
||||||
|
if (PixelFormatInfo::GetContent(depthStencilAttachment.format) == PixelFormatContent_DepthStencil)
|
||||||
|
{
|
||||||
|
depthStencilAttachment.stencilLoadOp = depthStencilAttachment.loadOp;
|
||||||
|
depthStencilAttachment.stencilStoreOp = depthStencilAttachment.storeOp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
depthStencilAttachment.stencilLoadOp = AttachmentLoadOp::Discard;
|
||||||
|
depthStencilAttachment.stencilStoreOp = AttachmentStoreOp::Discard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SubpassInfo
|
||||||
|
{
|
||||||
|
bool hasColorWrite = false;
|
||||||
|
bool hasDepthStencilRead = false;
|
||||||
|
bool hasDepthStencilWrite = false;
|
||||||
|
bool externalColorSynchronization = false;
|
||||||
|
bool externalDepthSynchronization = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
StackArray<SubpassInfo> subpassInfo = NazaraStackArray(SubpassInfo, subpasses.size());
|
||||||
|
|
||||||
|
for (std::size_t attachmentIndex = 0; attachmentIndex < renderPassAttachments.size(); ++attachmentIndex)
|
||||||
|
{
|
||||||
|
bool used = false; //< has the attachment already been used in a previous subpass
|
||||||
|
TextureLayout currentLayout = renderPassAttachments[attachmentIndex].initialLayout;
|
||||||
|
|
||||||
|
auto FindColor = [&](std::size_t subpassIndex) -> RenderPass::AttachmentReference*
|
||||||
|
{
|
||||||
|
auto& subpassDesc = subpasses[subpassIndex];
|
||||||
|
for (auto& colorReference : subpassDesc.colorAttachment)
|
||||||
|
{
|
||||||
|
if (colorReference.attachmentIndex == attachmentIndex)
|
||||||
|
return &colorReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto FindDepthStencil = [&](std::size_t subpassIndex) -> RenderPass::AttachmentReference*
|
||||||
|
{
|
||||||
|
auto& subpassDesc = subpasses[subpassIndex];
|
||||||
|
if (subpassDesc.depthStencilAttachment && subpassDesc.depthStencilAttachment->attachmentIndex == attachmentIndex)
|
||||||
|
return &subpassDesc.depthStencilAttachment.value();
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (std::size_t subpassIndex = 0; subpassIndex < subpasses.size(); ++subpassIndex)
|
||||||
|
{
|
||||||
|
RenderPass::SubpassDescription& subpassDesc = subpasses[subpassIndex];
|
||||||
|
|
||||||
|
RenderPass::AttachmentReference* colorAttachment = FindColor(subpassIndex);
|
||||||
|
RenderPass::AttachmentReference* depthStencilAttachment = FindDepthStencil(subpassIndex);
|
||||||
|
|
||||||
|
if (!colorAttachment && !depthStencilAttachment)
|
||||||
|
{
|
||||||
|
if (used)
|
||||||
|
subpassDesc.preserveAttachments.push_back(attachmentIndex);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colorAttachment)
|
||||||
|
{
|
||||||
|
subpassInfo[subpassIndex].hasColorWrite = true;
|
||||||
|
|
||||||
|
currentLayout = colorAttachment->attachmentLayout;
|
||||||
|
|
||||||
|
// If this subpass performs a layout change, color must be synchronized with external
|
||||||
|
if (!used && renderPassAttachments[attachmentIndex].initialLayout != currentLayout)
|
||||||
|
subpassInfo[subpassIndex].externalColorSynchronization = true;
|
||||||
|
}
|
||||||
|
else if (depthStencilAttachment)
|
||||||
|
{
|
||||||
|
if (depthStencilAttachment->attachmentLayout == TextureLayout::DepthStencilReadWrite)
|
||||||
|
subpassInfo[subpassIndex].hasDepthStencilWrite = true;
|
||||||
|
|
||||||
|
subpassInfo[subpassIndex].hasDepthStencilRead = true;
|
||||||
|
|
||||||
|
currentLayout = depthStencilAttachment->attachmentLayout;
|
||||||
|
|
||||||
|
// If this subpass performs a layout change, depth must be synchronized with external
|
||||||
|
if (!used && renderPassAttachments[attachmentIndex].initialLayout != currentLayout)
|
||||||
|
subpassInfo[subpassIndex].externalDepthSynchronization = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
used = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle external subpass dependencies
|
||||||
|
for (std::size_t subpassIndex = 0; subpassIndex < subpasses.size(); ++subpassIndex)
|
||||||
|
{
|
||||||
|
const auto& sync = subpassInfo[subpassIndex];
|
||||||
|
if (!sync.externalColorSynchronization && !sync.externalDepthSynchronization)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto& subpassDependency = dependencies.emplace_back();
|
||||||
|
subpassDependency.fromSubpassIndex = RenderPass::ExternalSubpassIndex;
|
||||||
|
subpassDependency.toSubpassIndex = subpassIndex;
|
||||||
|
|
||||||
|
// TODO: Handle bottom of pipe?
|
||||||
|
|
||||||
|
if (sync.externalColorSynchronization)
|
||||||
|
{
|
||||||
|
subpassDependency.fromStages |= PipelineStage::ColorOutput;
|
||||||
|
subpassDependency.fromAccessFlags |= MemoryAccess::ColorWrite;
|
||||||
|
|
||||||
|
subpassDependency.toStages |= PipelineStage::ColorOutput;
|
||||||
|
subpassDependency.toAccessFlags |= MemoryAccess::ColorRead | MemoryAccess::ColorWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sync.externalDepthSynchronization)
|
||||||
|
{
|
||||||
|
subpassDependency.fromStages |= PipelineStage::FragmentTestsLate;
|
||||||
|
subpassDependency.fromAccessFlags |= MemoryAccess::DepthStencilWrite;
|
||||||
|
|
||||||
|
subpassDependency.toStages |= PipelineStage::FragmentTestsEarly | PipelineStage::FragmentTestsLate;
|
||||||
|
subpassDependency.toAccessFlags |= MemoryAccess::DepthStencilRead | MemoryAccess::DepthStencilWrite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Handle self-dependencies
|
||||||
|
|
||||||
|
// Handle pass to pass dependencies
|
||||||
|
for (std::size_t subpassIndex = 1; subpassIndex < subpasses.size(); ++subpassIndex)
|
||||||
|
{
|
||||||
|
auto& subpassDependency = dependencies.emplace_back();
|
||||||
|
subpassDependency.fromSubpassIndex = subpassIndex - 1;
|
||||||
|
subpassDependency.toSubpassIndex = subpassIndex;
|
||||||
|
subpassDependency.tilable = true;
|
||||||
|
|
||||||
|
const auto& prevSync = subpassInfo[subpassDependency.fromSubpassIndex];
|
||||||
|
const auto& sync = subpassInfo[subpassDependency.toSubpassIndex];
|
||||||
|
|
||||||
|
// Previous pass flags
|
||||||
|
|
||||||
|
if (prevSync.hasColorWrite)
|
||||||
|
{
|
||||||
|
subpassDependency.fromAccessFlags = MemoryAccess::ColorWrite;
|
||||||
|
subpassDependency.fromStages = PipelineStage::ColorOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevSync.hasDepthStencilRead)
|
||||||
|
{
|
||||||
|
subpassDependency.fromStages |= PipelineStage::FragmentTestsEarly | PipelineStage::FragmentTestsLate;
|
||||||
|
subpassDependency.fromAccessFlags |= MemoryAccess::DepthStencilRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevSync.hasDepthStencilWrite)
|
||||||
|
{
|
||||||
|
subpassDependency.fromStages |= PipelineStage::FragmentTestsEarly | PipelineStage::FragmentTestsLate;
|
||||||
|
subpassDependency.fromAccessFlags |= MemoryAccess::DepthStencilWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current pass flags
|
||||||
|
|
||||||
|
if (sync.hasColorWrite)
|
||||||
|
{
|
||||||
|
subpassDependency.toStages = PipelineStage::ColorOutput;
|
||||||
|
subpassDependency.toAccessFlags = MemoryAccess::ColorRead | MemoryAccess::ColorWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sync.hasDepthStencilRead)
|
||||||
|
{
|
||||||
|
subpassDependency.toStages |= PipelineStage::FragmentTestsEarly | PipelineStage::FragmentTestsLate;
|
||||||
|
subpassDependency.toAccessFlags |= MemoryAccess::DepthStencilRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sync.hasDepthStencilWrite)
|
||||||
|
{
|
||||||
|
subpassDependency.toStages |= PipelineStage::FragmentTestsEarly | PipelineStage::FragmentTestsLate;
|
||||||
|
subpassDependency.toAccessFlags |= MemoryAccess::DepthStencilRead | MemoryAccess::DepthStencilWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Handle InputAttachment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameGraph::BuildPhysicalPasses()
|
||||||
|
{
|
||||||
|
RenderDevice& renderDevice = Graphics::Instance()->GetRenderDevice();
|
||||||
|
|
||||||
|
std::unordered_map<std::size_t /*textureId*/, TextureLayout> textureLayouts;
|
||||||
|
|
||||||
|
std::size_t physicalPassIndex = 0;
|
||||||
|
for (auto& physicalPass : m_pending.physicalPasses)
|
||||||
|
{
|
||||||
|
std::unordered_map<std::size_t /*textureId*/, std::size_t /*attachmentIndex*/> usedTextureAttachments;
|
||||||
|
std::size_t depthStencilAttachmentId;
|
||||||
|
std::optional<std::size_t> depthStencilAttachmentIndex;
|
||||||
|
|
||||||
|
std::vector<RenderPass::Attachment> renderPassAttachments;
|
||||||
|
std::vector<RenderPass::SubpassDescription> subpassesDesc;
|
||||||
|
std::vector<RenderPass::SubpassDependency> subpassesDeps;
|
||||||
|
|
||||||
|
auto RegisterColorInput = [&](const FramePass::Input& input, PhysicalPassData::Subpass& subpass)
|
||||||
|
{
|
||||||
|
std::size_t textureId = Retrieve(m_pending.attachmentToTextures, input.attachmentId);
|
||||||
|
|
||||||
|
auto it = textureLayouts.find(textureId);
|
||||||
|
assert(it != textureLayouts.end());
|
||||||
|
|
||||||
|
TextureLayout& textureLayout = it->second;
|
||||||
|
if (textureLayout != TextureLayout::ColorInput)
|
||||||
|
{
|
||||||
|
auto& transition = physicalPass.textureTransitions.emplace_back();
|
||||||
|
transition.textureId = textureId;
|
||||||
|
|
||||||
|
transition.srcAccessMask = MemoryAccess::ColorWrite;
|
||||||
|
transition.srcStageMask = PipelineStage::ColorOutput;
|
||||||
|
|
||||||
|
transition.dstStageMask = PipelineStage::ColorOutput;
|
||||||
|
transition.dstAccessMask = MemoryAccess::ColorRead | MemoryAccess::ColorWrite;
|
||||||
|
|
||||||
|
transition.oldLayout = textureLayout;
|
||||||
|
transition.newLayout = TextureLayout::ColorInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
textureLayout = TextureLayout::ColorInput;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto RegisterColorOutput = [&](const FramePass::Output& output)
|
||||||
|
{
|
||||||
|
std::size_t textureId = Retrieve(m_pending.attachmentToTextures, output.attachmentId);
|
||||||
|
|
||||||
|
TextureLayout initialLayout = TextureLayout::Undefined;
|
||||||
|
auto layoutIt = textureLayouts.find(textureId);
|
||||||
|
if (layoutIt != textureLayouts.end())
|
||||||
|
{
|
||||||
|
initialLayout = layoutIt->second;
|
||||||
|
layoutIt->second = TextureLayout::ColorOutput;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
textureLayouts.emplace(textureId, TextureLayout::ColorOutput);
|
||||||
|
|
||||||
|
auto it = usedTextureAttachments.find(textureId);
|
||||||
|
if (it != usedTextureAttachments.end())
|
||||||
|
return it->second;
|
||||||
|
|
||||||
|
std::size_t attachmentIndex = renderPassAttachments.size();
|
||||||
|
auto& attachment = renderPassAttachments.emplace_back();
|
||||||
|
attachment.format = m_pending.textures[textureId].format;
|
||||||
|
attachment.initialLayout = initialLayout;
|
||||||
|
attachment.loadOp = (output.clearColor) ? AttachmentLoadOp::Clear : AttachmentLoadOp::Discard;
|
||||||
|
attachment.storeOp = AttachmentStoreOp::Store;
|
||||||
|
attachment.stencilLoadOp = AttachmentLoadOp::Discard;
|
||||||
|
attachment.stencilStoreOp = AttachmentStoreOp::Discard;
|
||||||
|
|
||||||
|
usedTextureAttachments.emplace(textureId, attachmentIndex);
|
||||||
|
return attachmentIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto RegisterDepthStencil = [&](std::size_t attachmentId, TextureLayout textureLayout, bool* first) -> RenderPass::Attachment&
|
||||||
|
{
|
||||||
|
if (depthStencilAttachmentIndex)
|
||||||
|
{
|
||||||
|
assert(depthStencilAttachmentId == attachmentId);
|
||||||
|
*first = false;
|
||||||
|
|
||||||
|
return renderPassAttachments[depthStencilAttachmentIndex.value()];
|
||||||
|
}
|
||||||
|
|
||||||
|
*first = true;
|
||||||
|
|
||||||
|
std::size_t textureId = Retrieve(m_pending.attachmentToTextures, attachmentId);
|
||||||
|
|
||||||
|
TextureLayout initialLayout = TextureLayout::Undefined;
|
||||||
|
auto layoutIt = textureLayouts.find(textureId);
|
||||||
|
if (layoutIt != textureLayouts.end())
|
||||||
|
{
|
||||||
|
initialLayout = layoutIt->second;
|
||||||
|
layoutIt->second = textureLayout;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
textureLayouts.emplace(textureId, textureLayout);
|
||||||
|
|
||||||
|
depthStencilAttachmentId = attachmentId;
|
||||||
|
depthStencilAttachmentIndex = renderPassAttachments.size();
|
||||||
|
|
||||||
|
usedTextureAttachments.emplace(textureId, *depthStencilAttachmentIndex);
|
||||||
|
|
||||||
|
auto& depthStencilAttachment = renderPassAttachments.emplace_back();
|
||||||
|
depthStencilAttachment.format = m_pending.textures[textureId].format;
|
||||||
|
depthStencilAttachment.initialLayout = initialLayout;
|
||||||
|
|
||||||
|
return depthStencilAttachment;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::size_t subpassIndex = 0;
|
||||||
|
|
||||||
|
std::vector<RenderPass::AttachmentReference> colorAttachments;
|
||||||
|
for (auto& subpass : physicalPass.passes)
|
||||||
|
{
|
||||||
|
const FramePass& framePass = m_framePasses[subpass.passIndex];
|
||||||
|
const auto& subpassInputs = framePass.GetInputs();
|
||||||
|
const auto& subpassOutputs = framePass.GetOutputs();
|
||||||
|
|
||||||
|
colorAttachments.reserve(subpassOutputs.size());
|
||||||
|
|
||||||
|
for (const auto& input : subpassInputs)
|
||||||
|
RegisterColorInput(input, subpass);
|
||||||
|
|
||||||
|
bool hasColorWrite = false;
|
||||||
|
for (const auto& output : subpassOutputs)
|
||||||
|
{
|
||||||
|
hasColorWrite = true;
|
||||||
|
|
||||||
|
std::size_t attachmentIndex = RegisterColorOutput(output);
|
||||||
|
|
||||||
|
colorAttachments.push_back({
|
||||||
|
attachmentIndex,
|
||||||
|
TextureLayout::ColorOutput
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t colorAttachmentCount = renderPassAttachments.size();
|
||||||
|
|
||||||
|
std::optional<RenderPass::AttachmentReference> depthStencilAttachment;
|
||||||
|
for (auto& subpass : physicalPass.passes)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
// DS input/output
|
||||||
|
bool first;
|
||||||
|
auto& dsAttachment = RegisterDepthStencil(dsInputAttachment, TextureLayout::DepthStencilReadWrite, &first);
|
||||||
|
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
dsAttachment.loadOp = AttachmentLoadOp::Load;
|
||||||
|
dsAttachment.storeOp = AttachmentStoreOp::Store;
|
||||||
|
}
|
||||||
|
|
||||||
|
depthStencilAttachment = RenderPass::AttachmentReference{
|
||||||
|
depthStencilAttachmentIndex.value(),
|
||||||
|
TextureLayout::DepthStencilReadWrite
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (dsInputAttachment != FramePass::InvalidAttachmentId)
|
||||||
|
{
|
||||||
|
// DS input-only
|
||||||
|
bool first;
|
||||||
|
auto& dsAttachment = RegisterDepthStencil(dsInputAttachment, TextureLayout::DepthStencilReadOnly, &first);
|
||||||
|
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
// Check if a future pass reads from the DS buffer or if we can discard it after this pass
|
||||||
|
if (auto readIt = m_pending.attachmentReadList.find(dsInputAttachment); readIt != m_pending.attachmentReadList.end())
|
||||||
|
{
|
||||||
|
for (std::size_t passIndex : readIt->second)
|
||||||
|
{
|
||||||
|
std::size_t readPhysicalPassIndex = Retrieve(m_pending.passIdToPhysicalPassIndex, passIndex);
|
||||||
|
if (readPhysicalPassIndex > physicalPassIndex) //< Read in a future pass?
|
||||||
|
{
|
||||||
|
// Yes, store it
|
||||||
|
dsAttachment.storeOp = AttachmentStoreOp::Store;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
depthStencilAttachment = RenderPass::AttachmentReference{
|
||||||
|
depthStencilAttachmentIndex.value(),
|
||||||
|
TextureLayout::DepthStencilReadOnly
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (dsOutputAttachement != FramePass::InvalidAttachmentId)
|
||||||
|
{
|
||||||
|
// DS output-only
|
||||||
|
bool first;
|
||||||
|
auto& dsAttachment = RegisterDepthStencil(dsOutputAttachement, TextureLayout::DepthStencilReadWrite, &first);
|
||||||
|
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
dsAttachment.initialLayout = TextureLayout::Undefined; //< Don't care about initial layout
|
||||||
|
dsAttachment.loadOp = (framePass.GetDepthStencilClear()) ? AttachmentLoadOp::Clear : AttachmentLoadOp::Discard;
|
||||||
|
dsAttachment.storeOp = AttachmentStoreOp::Store;
|
||||||
|
}
|
||||||
|
|
||||||
|
depthStencilAttachment = RenderPass::AttachmentReference{
|
||||||
|
depthStencilAttachmentIndex.value(),
|
||||||
|
TextureLayout::DepthStencilReadWrite
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
subpassesDesc.push_back({
|
||||||
|
std::move(colorAttachments),
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
std::move(depthStencilAttachment)
|
||||||
|
});
|
||||||
|
|
||||||
|
subpassIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign final layout (TODO: Use this to perform layouts useful for future passes?)
|
||||||
|
for (const auto& [textureId, attachmentIndex] : usedTextureAttachments)
|
||||||
|
{
|
||||||
|
auto layoutIt = textureLayouts.find(textureId);
|
||||||
|
assert(layoutIt != textureLayouts.end());
|
||||||
|
|
||||||
|
auto& attachment = renderPassAttachments[attachmentIndex];
|
||||||
|
attachment.finalLayout = layoutIt->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
BuildPhysicalPassDependencies(colorAttachmentCount, depthStencilAttachmentIndex.has_value(), renderPassAttachments, subpassesDesc, subpassesDeps);
|
||||||
|
|
||||||
|
m_pending.renderPasses.push_back(renderDevice.InstantiateRenderPass(std::move(renderPassAttachments), std::move(subpassesDesc), std::move(subpassesDeps)));
|
||||||
|
|
||||||
|
physicalPassIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameGraph::BuildReadWriteList()
|
||||||
|
{
|
||||||
|
for (std::size_t passIndex = 0; passIndex < m_framePasses.size(); ++passIndex)
|
||||||
|
{
|
||||||
|
const FramePass& framePass = m_framePasses[passIndex];
|
||||||
|
|
||||||
|
for (const auto& input : framePass.GetInputs())
|
||||||
|
UniquePushBack(m_pending.attachmentReadList[input.attachmentId], passIndex);
|
||||||
|
|
||||||
|
if (std::size_t depthStencilId = framePass.GetDepthStencilInput(); depthStencilId != FramePass::InvalidAttachmentId)
|
||||||
|
UniquePushBack(m_pending.attachmentReadList[depthStencilId], passIndex);
|
||||||
|
|
||||||
|
for (const auto& output : framePass.GetOutputs())
|
||||||
|
UniquePushBack(m_pending.attachmentWriteList[output.attachmentId], passIndex);
|
||||||
|
|
||||||
|
if (std::size_t depthStencilId = framePass.GetDepthStencilOutput(); depthStencilId != FramePass::InvalidAttachmentId)
|
||||||
|
UniquePushBack(m_pending.attachmentWriteList[depthStencilId], passIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameGraph::ReorderPasses()
|
||||||
|
{
|
||||||
|
/* TODO */
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameGraph::TraverseGraph(std::size_t passIndex)
|
||||||
|
{
|
||||||
|
m_pending.passList.push_back(passIndex);
|
||||||
|
|
||||||
|
const FramePass& framePass = m_framePasses[passIndex];
|
||||||
|
for (const auto& input : framePass.GetInputs())
|
||||||
|
{
|
||||||
|
auto it = m_pending.attachmentWriteList.find(input.attachmentId);
|
||||||
|
if (it != m_pending.attachmentWriteList.end())
|
||||||
|
{
|
||||||
|
const PassList& dependencyPassList = it->second;
|
||||||
|
for (std::size_t dependencyPass : dependencyPassList)
|
||||||
|
TraverseGraph(dependencyPass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameGraph::RemoveDuplicatePasses()
|
||||||
|
{
|
||||||
|
// A way to remove duplicates from a std::vector without sorting it
|
||||||
|
std::unordered_set<std::size_t> seen;
|
||||||
|
|
||||||
|
auto itRead = m_pending.passList.begin();
|
||||||
|
auto itWrite = m_pending.passList.begin();
|
||||||
|
|
||||||
|
while (itRead != m_pending.passList.end())
|
||||||
|
{
|
||||||
|
std::size_t passIndex = *itRead;
|
||||||
|
if (seen.find(passIndex) == seen.end())
|
||||||
|
{
|
||||||
|
if (itRead != itWrite)
|
||||||
|
*itWrite++ = passIndex;
|
||||||
|
else
|
||||||
|
++itWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
++itRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pending.passList.erase(itWrite, m_pending.passList.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
// 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 <Nazara/Graphics/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
// 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 <Nazara/Graphics/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -19,9 +19,9 @@ namespace Nz
|
||||||
m_commandBuffer.BeginDebugRegion(regionName, color);
|
m_commandBuffer.BeginDebugRegion(regionName, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLCommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti /*renderRect*/, std::initializer_list<ClearValues> clearValues)
|
void OpenGLCommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti /*renderRect*/, const ClearValues* clearValues, std::size_t clearValueCount)
|
||||||
{
|
{
|
||||||
m_commandBuffer.SetFramebuffer(static_cast<const OpenGLFramebuffer&>(framebuffer), renderPass, clearValues);
|
m_commandBuffer.SetFramebuffer(static_cast<const OpenGLFramebuffer&>(framebuffer), renderPass, clearValues, clearValueCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLCommandBufferBuilder::BindIndexBuffer(Nz::AbstractBuffer* indexBuffer, UInt64 offset)
|
void OpenGLCommandBufferBuilder::BindIndexBuffer(Nz::AbstractBuffer* indexBuffer, UInt64 offset)
|
||||||
|
|
@ -84,14 +84,22 @@ namespace Nz
|
||||||
|
|
||||||
void OpenGLCommandBufferBuilder::EndRenderPass()
|
void OpenGLCommandBufferBuilder::EndRenderPass()
|
||||||
{
|
{
|
||||||
|
/* nothing to do */
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLCommandBufferBuilder::NextSubpass()
|
||||||
|
{
|
||||||
|
/* nothing to do */
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLCommandBufferBuilder::PreTransferBarrier()
|
void OpenGLCommandBufferBuilder::PreTransferBarrier()
|
||||||
{
|
{
|
||||||
|
/* nothing to do */
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLCommandBufferBuilder::PostTransferBarrier()
|
void OpenGLCommandBufferBuilder::PostTransferBarrier()
|
||||||
{
|
{
|
||||||
|
/* nothing to do */
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLCommandBufferBuilder::SetScissor(Nz::Recti scissorRegion)
|
void OpenGLCommandBufferBuilder::SetScissor(Nz::Recti scissorRegion)
|
||||||
|
|
@ -103,4 +111,9 @@ namespace Nz
|
||||||
{
|
{
|
||||||
m_commandBuffer.SetViewport(viewportRegion);
|
m_commandBuffer.SetViewport(viewportRegion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLCommandBufferBuilder::TextureBarrier(PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, MemoryAccessFlags srcAccessMask, MemoryAccessFlags dstAccessMask, TextureLayout oldLayout, TextureLayout newLayout, const Texture& texture)
|
||||||
|
{
|
||||||
|
/* nothing to do */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include <Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp>
|
#include <Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp>
|
||||||
#include <Nazara/VulkanRenderer/VulkanSingleFramebuffer.hpp>
|
#include <Nazara/VulkanRenderer/VulkanSingleFramebuffer.hpp>
|
||||||
#include <Nazara/VulkanRenderer/VulkanShaderBinding.hpp>
|
#include <Nazara/VulkanRenderer/VulkanShaderBinding.hpp>
|
||||||
|
#include <Nazara/VulkanRenderer/VulkanTexture.hpp>
|
||||||
#include <Nazara/VulkanRenderer/VulkanUploadPool.hpp>
|
#include <Nazara/VulkanRenderer/VulkanUploadPool.hpp>
|
||||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||||
|
|
||||||
|
|
@ -26,7 +27,7 @@ namespace Nz
|
||||||
m_commandBuffer.BeginDebugRegion(regionNameEOS.data(), color);
|
m_commandBuffer.BeginDebugRegion(regionNameEOS.data(), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanCommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, std::initializer_list<ClearValues> clearValues)
|
void VulkanCommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, const ClearValues* clearValues, std::size_t clearValueCount)
|
||||||
{
|
{
|
||||||
const VulkanRenderPass& vkRenderPass = static_cast<const VulkanRenderPass&>(renderPass);
|
const VulkanRenderPass& vkRenderPass = static_cast<const VulkanRenderPass&>(renderPass);
|
||||||
|
|
||||||
|
|
@ -49,14 +50,15 @@ namespace Nz
|
||||||
throw std::runtime_error("Unhandled framebuffer type " + std::to_string(UnderlyingCast(vkFramebuffer.GetType())));
|
throw std::runtime_error("Unhandled framebuffer type " + std::to_string(UnderlyingCast(vkFramebuffer.GetType())));
|
||||||
}();
|
}();
|
||||||
|
|
||||||
StackArray<VkClearValue> vkClearValues = NazaraStackArray(VkClearValue, clearValues.size());
|
std::size_t attachmentCount = vkRenderPass.GetAttachmentCount();
|
||||||
|
|
||||||
std::size_t index = 0;
|
StackArray<VkClearValue> vkClearValues = NazaraStackArray(VkClearValue, attachmentCount);
|
||||||
for (const ClearValues& values : clearValues)
|
for (std::size_t i = 0; i < attachmentCount; ++i)
|
||||||
{
|
{
|
||||||
auto& vkValues = vkClearValues[index];
|
const auto& values = (i < clearValueCount) ? clearValues[i] : CommandBufferBuilder::ClearValues{};
|
||||||
|
auto& vkValues = vkClearValues[i];
|
||||||
|
|
||||||
if (PixelFormatInfo::GetContent(vkRenderPass.GetAttachment(index).format) == PixelFormatContent_ColorRGBA)
|
if (PixelFormatInfo::GetContent(vkRenderPass.GetAttachment(i).format) == PixelFormatContent_ColorRGBA)
|
||||||
{
|
{
|
||||||
vkValues.color.float32[0] = values.color.r / 255.f;
|
vkValues.color.float32[0] = values.color.r / 255.f;
|
||||||
vkValues.color.float32[1] = values.color.g / 255.f;
|
vkValues.color.float32[1] = values.color.g / 255.f;
|
||||||
|
|
@ -68,8 +70,6 @@ namespace Nz
|
||||||
vkValues.depthStencil.depth = values.depth;
|
vkValues.depthStencil.depth = values.depth;
|
||||||
vkValues.depthStencil.stencil = values.stencil;
|
vkValues.depthStencil.stencil = values.stencil;
|
||||||
}
|
}
|
||||||
|
|
||||||
index++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkRenderPassBeginInfo beginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
|
VkRenderPassBeginInfo beginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
|
||||||
|
|
@ -157,6 +157,11 @@ namespace Nz
|
||||||
m_currentRenderPass = nullptr;
|
m_currentRenderPass = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VulkanCommandBufferBuilder::NextSubpass()
|
||||||
|
{
|
||||||
|
m_commandBuffer.NextSubpass();
|
||||||
|
}
|
||||||
|
|
||||||
void VulkanCommandBufferBuilder::PreTransferBarrier()
|
void VulkanCommandBufferBuilder::PreTransferBarrier()
|
||||||
{
|
{
|
||||||
m_commandBuffer.MemoryBarrier(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0U, VK_ACCESS_TRANSFER_READ_BIT);
|
m_commandBuffer.MemoryBarrier(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0U, VK_ACCESS_TRANSFER_READ_BIT);
|
||||||
|
|
@ -176,4 +181,11 @@ namespace Nz
|
||||||
{
|
{
|
||||||
m_commandBuffer.SetViewport(Nz::Rectf(viewportRegion), 0.f, 1.f);
|
m_commandBuffer.SetViewport(Nz::Rectf(viewportRegion), 0.f, 1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VulkanCommandBufferBuilder::TextureBarrier(PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, MemoryAccessFlags srcAccessMask, MemoryAccessFlags dstAccessMask, TextureLayout oldLayout, TextureLayout newLayout, const Texture& texture)
|
||||||
|
{
|
||||||
|
const VulkanTexture& vkTexture = static_cast<const VulkanTexture&>(texture);
|
||||||
|
|
||||||
|
m_commandBuffer.ImageBarrier(ToVulkan(srcStageMask), ToVulkan(dstStageMask), VkDependencyFlags(0), ToVulkan(srcAccessMask), ToVulkan(dstAccessMask), ToVulkan(oldLayout), ToVulkan(newLayout), vkTexture.GetImage(), VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ namespace Nz
|
||||||
}
|
}
|
||||||
|
|
||||||
StackVector<VkAttachmentReference> vkAttachmentReferences = NazaraStackVector(VkAttachmentReference, totalAttachmentReference);
|
StackVector<VkAttachmentReference> vkAttachmentReferences = NazaraStackVector(VkAttachmentReference, totalAttachmentReference);
|
||||||
|
StackVector<UInt32> vkPreserveAttachments = NazaraStackVector(UInt32, attachments.size());
|
||||||
|
|
||||||
StackVector<VkSubpassDescription> vkSubpassDescs = NazaraStackVector(VkSubpassDescription, m_subpassDescriptions.size());
|
StackVector<VkSubpassDescription> vkSubpassDescs = NazaraStackVector(VkSubpassDescription, m_subpassDescriptions.size());
|
||||||
for (const SubpassDescription& subpassInfo : m_subpassDescriptions)
|
for (const SubpassDescription& subpassInfo : m_subpassDescriptions)
|
||||||
|
|
@ -72,6 +73,10 @@ namespace Nz
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(subpassInfo.preserveAttachments.size() <= vkPreserveAttachments.size());
|
||||||
|
for (std::size_t attachmentIndex : subpassInfo.preserveAttachments)
|
||||||
|
vkPreserveAttachments.push_back(UInt32(attachmentIndex));
|
||||||
|
|
||||||
vkSubpassDescs.push_back({
|
vkSubpassDescs.push_back({
|
||||||
VkSubpassDescriptionFlags(0),
|
VkSubpassDescriptionFlags(0),
|
||||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
|
|
@ -81,17 +86,25 @@ namespace Nz
|
||||||
(!subpassInfo.colorAttachment.empty()) ? &vkAttachmentReferences[colorAttachmentIndex] : nullptr,
|
(!subpassInfo.colorAttachment.empty()) ? &vkAttachmentReferences[colorAttachmentIndex] : nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
(subpassInfo.depthStencilAttachment) ? &vkAttachmentReferences[depthStencilAttachmentIndex] : nullptr,
|
(subpassInfo.depthStencilAttachment) ? &vkAttachmentReferences[depthStencilAttachmentIndex] : nullptr,
|
||||||
0,
|
UInt32(vkPreserveAttachments.size()),
|
||||||
nullptr
|
(!vkPreserveAttachments.empty()) ? &vkPreserveAttachments[0] : nullptr
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
StackVector<VkSubpassDependency> vkSubpassDeps = NazaraStackVector(VkSubpassDependency, m_subpassDependencies.size());
|
StackVector<VkSubpassDependency> vkSubpassDeps = NazaraStackVector(VkSubpassDependency, m_subpassDependencies.size());
|
||||||
for (const SubpassDependency& subpassDependency : m_subpassDependencies)
|
for (const SubpassDependency& subpassDependency : m_subpassDependencies)
|
||||||
{
|
{
|
||||||
|
auto ToSubPassIndex = [](std::size_t subpassIndex) -> UInt32
|
||||||
|
{
|
||||||
|
if (subpassIndex == ExternalSubpassIndex)
|
||||||
|
return VK_SUBPASS_EXTERNAL;
|
||||||
|
|
||||||
|
return UInt32(subpassIndex);
|
||||||
|
};
|
||||||
|
|
||||||
vkSubpassDeps.push_back({
|
vkSubpassDeps.push_back({
|
||||||
UInt32(subpassDependency.fromSubpassIndex),
|
ToSubPassIndex(subpassDependency.fromSubpassIndex),
|
||||||
UInt32(subpassDependency.toSubpassIndex),
|
ToSubPassIndex(subpassDependency.toSubpassIndex),
|
||||||
ToVulkan(subpassDependency.fromStages),
|
ToVulkan(subpassDependency.fromStages),
|
||||||
ToVulkan(subpassDependency.toStages),
|
ToVulkan(subpassDependency.toStages),
|
||||||
ToVulkan(subpassDependency.fromAccessFlags),
|
ToVulkan(subpassDependency.fromAccessFlags),
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <Nazara/VulkanRenderer/VulkanSurface.hpp>
|
#include <Nazara/VulkanRenderer/VulkanSurface.hpp>
|
||||||
#include <Nazara/VulkanRenderer/Vulkan.hpp>
|
#include <Nazara/VulkanRenderer/Vulkan.hpp>
|
||||||
|
#include <vulkan/vk_sdk_platform.h>
|
||||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue