Renderer: Add RenderPassCache
This commit is contained in:
parent
8846eb4309
commit
7e4f624ca7
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_RENDERPASSCACHE_HPP
|
||||
#define NAZARA_RENDERPASSCACHE_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/RenderPass.hpp>
|
||||
#include <memory>
|
||||
#include <variant>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class RenderDevice;
|
||||
|
||||
class NAZARA_RENDERER_API RenderPassCache
|
||||
{
|
||||
public:
|
||||
inline RenderPassCache(RenderDevice& device);
|
||||
RenderPassCache(const RenderPassCache&) = delete;
|
||||
RenderPassCache(RenderPassCache&&) noexcept = default;
|
||||
~RenderPassCache() = default;
|
||||
|
||||
const std::shared_ptr<RenderPass>& Get(const std::vector<RenderPass::Attachment>& attachments, const std::vector<RenderPass::SubpassDescription>& subpassDescriptions, const std::vector<RenderPass::SubpassDependency>& subpassDependencies) const;
|
||||
|
||||
RenderPassCache& operator=(const RenderPassCache&) = delete;
|
||||
RenderPassCache& operator=(RenderPassCache&&) noexcept = default;
|
||||
|
||||
private:
|
||||
struct RenderPassData
|
||||
{
|
||||
std::size_t attachmentCount;
|
||||
std::size_t dependencyCount;
|
||||
std::size_t descriptionCount;
|
||||
const RenderPass::Attachment* attachments;
|
||||
const RenderPass::SubpassDependency* subpassDependencies;
|
||||
const RenderPass::SubpassDescription* subpassDescriptions;
|
||||
};
|
||||
|
||||
using Key = std::variant<std::shared_ptr<RenderPass>, RenderPassData>;
|
||||
|
||||
struct Hasher
|
||||
{
|
||||
template<typename T> std::size_t operator()(const T& renderPass) const;
|
||||
std::size_t operator()(const RenderPassData& renderPassData) const;
|
||||
};
|
||||
|
||||
struct EqualityChecker
|
||||
{
|
||||
template<typename T1, typename T2> bool operator()(const T1& lhs, const T2& rhs) const;
|
||||
bool operator()(const RenderPassData& lhs, const RenderPassData& rhs) const;
|
||||
};
|
||||
|
||||
static inline auto ToRenderPassData(const Key& key);
|
||||
static inline RenderPassData ToRenderPassData(const std::shared_ptr<RenderPass>& renderPass);
|
||||
static inline const RenderPassData& ToRenderPassData(const RenderPassData& renderPassData);
|
||||
|
||||
mutable std::unordered_map<Key, std::shared_ptr<RenderPass>, Hasher, EqualityChecker> m_renderPasses;
|
||||
RenderDevice& m_device;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Renderer/RenderPassCache.inl>
|
||||
|
||||
#endif // NAZARA_RENDERPASS_HPP
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/RenderPassCache.hpp>
|
||||
#include <cassert>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline RenderPassCache::RenderPassCache(RenderDevice& device) :
|
||||
m_device(device)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::size_t RenderPassCache::Hasher::operator()(const T& key) const
|
||||
{
|
||||
return operator()(ToRenderPassData(key));
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
inline bool RenderPassCache::EqualityChecker::operator()(const T1& lhs, const T2& rhs) const
|
||||
{
|
||||
return operator()(ToRenderPassData(lhs), ToRenderPassData(rhs));
|
||||
}
|
||||
|
||||
inline auto RenderPassCache::ToRenderPassData(const Key& key)
|
||||
{
|
||||
return std::visit([&](auto&& arg)
|
||||
{
|
||||
return ToRenderPassData(arg);
|
||||
}, key);
|
||||
}
|
||||
|
||||
inline auto RenderPassCache::ToRenderPassData(const std::shared_ptr<RenderPass>& renderPass) -> RenderPassData
|
||||
{
|
||||
const auto& attachments = renderPass->GetAttachments();
|
||||
const auto& subpassDeps = renderPass->GetSubpassDependencies();
|
||||
const auto& subpassDesc = renderPass->GetSubpassDescriptions();
|
||||
|
||||
RenderPassData data;
|
||||
data.attachmentCount = attachments.size();
|
||||
data.attachments = attachments.data();
|
||||
|
||||
data.dependencyCount = subpassDeps.size();
|
||||
data.subpassDependencies = subpassDeps.data();
|
||||
|
||||
data.descriptionCount = subpassDesc.size();
|
||||
data.subpassDescriptions = subpassDesc.data();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
inline auto RenderPassCache::ToRenderPassData(const RenderPassData& renderPassData) -> const RenderPassData&
|
||||
{
|
||||
return renderPassData;
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Renderer/DebugOff.hpp>
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/RenderPassCache.hpp>
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Renderer/RenderDevice.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
const std::shared_ptr<RenderPass>& RenderPassCache::Get(const std::vector<RenderPass::Attachment>& attachments, const std::vector<RenderPass::SubpassDescription>& subpassDescriptions, const std::vector<RenderPass::SubpassDependency>& subpassDependencies) const
|
||||
{
|
||||
RenderPassData data;
|
||||
data.attachmentCount = attachments.size();
|
||||
data.attachments = attachments.data();
|
||||
|
||||
data.dependencyCount = subpassDependencies.size();
|
||||
data.subpassDependencies = subpassDependencies.data();
|
||||
|
||||
data.descriptionCount = subpassDescriptions.size();
|
||||
data.subpassDescriptions = subpassDescriptions.data();
|
||||
|
||||
auto it = m_renderPasses.find(data);
|
||||
if (it != m_renderPasses.end())
|
||||
return it->second;
|
||||
|
||||
std::shared_ptr<RenderPass> renderPass = m_device.InstantiateRenderPass(attachments, subpassDescriptions, subpassDependencies);
|
||||
|
||||
return m_renderPasses.emplace(renderPass, renderPass).first->second;
|
||||
}
|
||||
|
||||
std::size_t RenderPassCache::Hasher::operator()(const RenderPassData& renderPassData) const
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
for (std::size_t i = 0; i < renderPassData.attachmentCount; ++i)
|
||||
{
|
||||
const auto& attachment = renderPassData.attachments[i];
|
||||
|
||||
HashCombine(seed, attachment.format);
|
||||
HashCombine(seed, attachment.loadOp);
|
||||
HashCombine(seed, attachment.stencilLoadOp);
|
||||
HashCombine(seed, attachment.storeOp);
|
||||
HashCombine(seed, attachment.stencilStoreOp);
|
||||
HashCombine(seed, attachment.initialLayout);
|
||||
HashCombine(seed, attachment.finalLayout);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < renderPassData.descriptionCount; ++i)
|
||||
{
|
||||
const auto& subpassDesc = renderPassData.subpassDescriptions[i];
|
||||
|
||||
auto CombineAttachment = [&](const RenderPass::AttachmentReference& attachmentReference)
|
||||
{
|
||||
HashCombine(seed, attachmentReference.attachmentIndex);
|
||||
HashCombine(seed, attachmentReference.attachmentLayout);
|
||||
};
|
||||
|
||||
for (const auto& colorAttachment : subpassDesc.colorAttachment)
|
||||
CombineAttachment(colorAttachment);
|
||||
|
||||
for (const auto& inputAttachment : subpassDesc.inputAttachments)
|
||||
CombineAttachment(inputAttachment);
|
||||
|
||||
if (subpassDesc.depthStencilAttachment)
|
||||
CombineAttachment(*subpassDesc.depthStencilAttachment);
|
||||
|
||||
for (const auto& attachmentIndex : subpassDesc.preserveAttachments)
|
||||
HashCombine(seed, attachmentIndex);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < renderPassData.dependencyCount; ++i)
|
||||
{
|
||||
const auto& subpassDep = renderPassData.subpassDependencies[i];
|
||||
|
||||
HashCombine(seed, subpassDep.fromSubpassIndex);
|
||||
HashCombine(seed, subpassDep.fromStages);
|
||||
HashCombine(seed, subpassDep.fromAccessFlags);
|
||||
|
||||
HashCombine(seed, subpassDep.toSubpassIndex);
|
||||
HashCombine(seed, subpassDep.toStages);
|
||||
HashCombine(seed, subpassDep.toAccessFlags);
|
||||
|
||||
HashCombine(seed, subpassDep.tilable);
|
||||
}
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
bool RenderPassCache::EqualityChecker::operator()(const RenderPassData& lhs, const RenderPassData& rhs) const
|
||||
{
|
||||
if (lhs.attachmentCount != rhs.attachmentCount ||
|
||||
lhs.dependencyCount != rhs.dependencyCount ||
|
||||
lhs.descriptionCount != rhs.descriptionCount)
|
||||
return false;
|
||||
|
||||
for (std::size_t i = 0; i < lhs.attachmentCount; ++i)
|
||||
{
|
||||
const auto& lhsAttachment = lhs.attachments[i];
|
||||
const auto& rhsAttachment = rhs.attachments[i];
|
||||
|
||||
if (lhsAttachment.format != rhsAttachment.format ||
|
||||
lhsAttachment.loadOp != rhsAttachment.loadOp ||
|
||||
lhsAttachment.stencilLoadOp != rhsAttachment.stencilLoadOp ||
|
||||
lhsAttachment.storeOp != rhsAttachment.storeOp ||
|
||||
lhsAttachment.stencilStoreOp != rhsAttachment.stencilStoreOp ||
|
||||
lhsAttachment.initialLayout != rhsAttachment.initialLayout ||
|
||||
lhsAttachment.finalLayout != rhsAttachment.finalLayout)
|
||||
return false;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < lhs.dependencyCount; ++i)
|
||||
{
|
||||
const auto& lhsDependency = lhs.subpassDependencies[i];
|
||||
const auto& rhsDependency = rhs.subpassDependencies[i];
|
||||
|
||||
if (lhsDependency.fromSubpassIndex != rhsDependency.fromSubpassIndex ||
|
||||
lhsDependency.fromStages != rhsDependency.fromStages ||
|
||||
lhsDependency.fromAccessFlags != rhsDependency.fromAccessFlags ||
|
||||
lhsDependency.toSubpassIndex != rhsDependency.toSubpassIndex ||
|
||||
lhsDependency.toStages != rhsDependency.toStages ||
|
||||
lhsDependency.toAccessFlags != rhsDependency.toAccessFlags ||
|
||||
lhsDependency.tilable != rhsDependency.tilable)
|
||||
return false;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < lhs.descriptionCount; ++i)
|
||||
{
|
||||
const auto& lhsSubpassDesc = lhs.subpassDescriptions[i];
|
||||
const auto& rhsSubpassDesc = rhs.subpassDescriptions[i];
|
||||
|
||||
auto CompareAttachments = [&](const RenderPass::AttachmentReference& lhsAttachmentReference, const RenderPass::AttachmentReference& rhsAttachmentReference)
|
||||
{
|
||||
if (lhsAttachmentReference.attachmentIndex != rhsAttachmentReference.attachmentIndex)
|
||||
return false;
|
||||
|
||||
if (lhsAttachmentReference.attachmentLayout != rhsAttachmentReference.attachmentLayout)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
if (std::equal(lhsSubpassDesc.colorAttachment.begin(), lhsSubpassDesc.colorAttachment.end(), rhsSubpassDesc.colorAttachment.begin(), CompareAttachments) &&
|
||||
!std::equal(lhsSubpassDesc.inputAttachments.begin(), lhsSubpassDesc.inputAttachments.end(), rhsSubpassDesc.inputAttachments.begin(), CompareAttachments))
|
||||
return false;
|
||||
|
||||
if (lhsSubpassDesc.depthStencilAttachment.has_value() != rhsSubpassDesc.depthStencilAttachment.has_value())
|
||||
return false;
|
||||
|
||||
if (lhsSubpassDesc.depthStencilAttachment.has_value() && CompareAttachments(*lhsSubpassDesc.depthStencilAttachment, *rhsSubpassDesc.depthStencilAttachment))
|
||||
return false;
|
||||
|
||||
if (lhsSubpassDesc.preserveAttachments != rhsSubpassDesc.preserveAttachments)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue