Graphics: Use memory pools for render elements

This commit is contained in:
SirLynix
2022-08-30 19:27:52 +02:00
parent 7949c57f16
commit 017a6c7af3
43 changed files with 528 additions and 133 deletions

View File

@@ -5,6 +5,7 @@
#include <Nazara/Graphics/DepthPipelinePass.hpp>
#include <Nazara/Graphics/AbstractViewer.hpp>
#include <Nazara/Graphics/ElementRenderer.hpp>
#include <Nazara/Graphics/ElementRendererRegistry.hpp>
#include <Nazara/Graphics/FrameGraph.hpp>
#include <Nazara/Graphics/FramePipeline.hpp>
#include <Nazara/Graphics/Graphics.hpp>
@@ -15,9 +16,10 @@
namespace Nz
{
DepthPipelinePass::DepthPipelinePass(FramePipeline& owner, AbstractViewer* viewer) :
DepthPipelinePass::DepthPipelinePass(FramePipeline& owner, ElementRendererRegistry& elementRegistry, AbstractViewer* viewer) :
m_lastVisibilityHash(0),
m_viewer(viewer),
m_elementRegistry(elementRegistry),
m_pipeline(owner),
m_rebuildCommandBuffer(false),
m_rebuildElements(false)
@@ -39,7 +41,15 @@ namespace Nz
m_renderElements.clear();
for (const auto& renderableData : visibleRenderables)
renderableData.instancedRenderable->BuildElement(m_depthPassIndex, *renderableData.worldInstance, renderableData.skeletonInstance, m_renderElements, renderableData.scissorBox);
{
InstancedRenderable::ElementData elementData{
&renderableData.scissorBox,
renderableData.skeletonInstance,
renderableData.worldInstance
};
renderableData.instancedRenderable->BuildElement(m_elementRegistry, elementData, m_depthPassIndex, m_renderElements);
}
m_renderQueueRegistry.Clear();
m_renderQueue.Clear();
@@ -47,7 +57,7 @@ namespace Nz
for (const auto& renderElement : m_renderElements)
{
renderElement->Register(m_renderQueueRegistry);
m_renderQueue.Insert(renderElement.get());
m_renderQueue.Insert(renderElement.GetElement());
}
m_renderQueueRegistry.Finalize();
@@ -64,7 +74,7 @@ namespace Nz
if (m_rebuildElements)
{
m_pipeline.ForEachElementRenderer([&](std::size_t elementType, ElementRenderer& elementRenderer)
m_elementRegistry.ForEachElementRenderer([&](std::size_t elementType, ElementRenderer& elementRenderer)
{
if (elementType >= m_elementRendererData.size() || !m_elementRendererData[elementType])
{
@@ -79,9 +89,9 @@ namespace Nz
const auto& viewerInstance = m_viewer->GetViewerInstance();
m_pipeline.ProcessRenderQueue(m_renderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
m_elementRegistry.ProcessRenderQueue(m_renderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
{
ElementRenderer& elementRenderer = m_pipeline.GetElementRenderer(elementType);
ElementRenderer& elementRenderer = m_elementRegistry.GetElementRenderer(elementType);
m_renderStates.clear();
m_renderStates.resize(elementCount);
@@ -89,7 +99,7 @@ namespace Nz
elementRenderer.Prepare(viewerInstance, *m_elementRendererData[elementType], renderFrame, elementCount, elements, m_renderStates.data());
});
m_pipeline.ForEachElementRenderer([&](std::size_t elementType, ElementRenderer& elementRenderer)
m_elementRegistry.ForEachElementRenderer([&](std::size_t elementType, ElementRenderer& elementRenderer)
{
elementRenderer.PrepareEnd(renderFrame, *m_elementRendererData[elementType]);
});
@@ -146,9 +156,9 @@ namespace Nz
const auto& viewerInstance = m_viewer->GetViewerInstance();
m_pipeline.ProcessRenderQueue(m_renderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
m_elementRegistry.ProcessRenderQueue(m_renderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
{
ElementRenderer& elementRenderer = m_pipeline.GetElementRenderer(elementType);
ElementRenderer& elementRenderer = m_elementRegistry.GetElementRenderer(elementType);
elementRenderer.Render(viewerInstance, *m_elementRendererData[elementType], builder, elementCount, elements);
});

View File

@@ -0,0 +1,21 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/ElementRendererRegistry.hpp>
#include <Nazara/Graphics/Enums.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/RenderSpriteChain.hpp>
#include <Nazara/Graphics/RenderSubmesh.hpp>
#include <Nazara/Graphics/SpriteChainRenderer.hpp>
#include <Nazara/Graphics/SubmeshRenderer.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
ElementRendererRegistry::ElementRendererRegistry()
{
RegisterElementRenderer<RenderSpriteChain>(std::make_unique<SpriteChainRenderer>(*Graphics::Instance()->GetRenderDevice()));
RegisterElementRenderer<RenderSubmesh>(std::make_unique<SubmeshRenderer>());
}
}

View File

@@ -26,7 +26,8 @@
namespace Nz
{
ForwardFramePipeline::ForwardFramePipeline() :
ForwardFramePipeline::ForwardFramePipeline(ElementRendererRegistry& elementRegistry) :
m_elementRegistry(elementRegistry),
m_renderablePool(4096),
m_lightPool(64),
m_skeletonInstances(1024),
@@ -182,8 +183,8 @@ namespace Nz
auto& viewerData = *m_viewerPool.Allocate(viewerIndex);
viewerData.renderOrder = renderOrder;
viewerData.debugDrawPass = std::make_unique<DebugDrawPipelinePass>(*this, viewerInstance);
viewerData.depthPrepass = std::make_unique<DepthPipelinePass>(*this, viewerInstance);
viewerData.forwardPass = std::make_unique<ForwardPipelinePass>(*this, viewerInstance);
viewerData.depthPrepass = std::make_unique<DepthPipelinePass>(*this, m_elementRegistry, viewerInstance);
viewerData.forwardPass = std::make_unique<ForwardPipelinePass>(*this, m_elementRegistry, viewerInstance);
viewerData.viewer = viewerInstance;
m_invalidatedViewerInstances.UnboundedSet(viewerIndex);

View File

@@ -4,6 +4,7 @@
#include <Nazara/Graphics/ForwardPipelinePass.hpp>
#include <Nazara/Graphics/AbstractViewer.hpp>
#include <Nazara/Graphics/ElementRendererRegistry.hpp>
#include <Nazara/Graphics/FrameGraph.hpp>
#include <Nazara/Graphics/FramePipeline.hpp>
#include <Nazara/Graphics/InstancedRenderable.hpp>
@@ -16,9 +17,10 @@
namespace Nz
{
ForwardPipelinePass::ForwardPipelinePass(FramePipeline& owner, AbstractViewer* viewer) :
ForwardPipelinePass::ForwardPipelinePass(FramePipeline& owner, ElementRendererRegistry& elementRegistry, AbstractViewer* viewer) :
m_lastVisibilityHash(0),
m_viewer(viewer),
m_elementRegistry(elementRegistry),
m_pipeline(owner),
m_rebuildCommandBuffer(false),
m_rebuildElements(false)
@@ -147,11 +149,17 @@ namespace Nz
else
lightUboView = it->second;
InstancedRenderable::ElementData elementData{
&renderableData.scissorBox,
renderableData.skeletonInstance,
renderableData.worldInstance
};
std::size_t previousCount = m_renderElements.size();
renderableData.instancedRenderable->BuildElement(m_forwardPassIndex, *renderableData.worldInstance, renderableData.skeletonInstance, m_renderElements, renderableData.scissorBox);
renderableData.instancedRenderable->BuildElement(m_elementRegistry, elementData, m_forwardPassIndex, m_renderElements);
for (std::size_t i = previousCount; i < m_renderElements.size(); ++i)
{
const RenderElement* element = m_renderElements[i].get();
const RenderElement* element = m_renderElements[i].GetElement();
m_lightPerRenderElement.emplace(element, lightUboView);
}
}
@@ -159,7 +167,7 @@ namespace Nz
for (const auto& renderElement : m_renderElements)
{
renderElement->Register(m_renderQueueRegistry);
m_renderQueue.Insert(renderElement.get());
m_renderQueue.Insert(renderElement.GetElement());
}
m_renderQueueRegistry.Finalize();
@@ -193,15 +201,13 @@ namespace Nz
if (m_rebuildElements)
{
m_pipeline.ForEachElementRenderer([&](std::size_t elementType, ElementRenderer& elementRenderer)
m_elementRegistry.ForEachElementRenderer([&](std::size_t elementType, ElementRenderer& elementRenderer)
{
if (elementType >= m_elementRendererData.size() || !m_elementRendererData[elementType])
{
if (elementType >= m_elementRendererData.size())
m_elementRendererData.resize(elementType + 1);
if (elementType >= m_elementRendererData.size())
m_elementRendererData.resize(elementType + 1);
if (!m_elementRendererData[elementType])
m_elementRendererData[elementType] = elementRenderer.InstanciateData();
}
elementRenderer.Reset(*m_elementRendererData[elementType], renderFrame);
});
@@ -209,9 +215,9 @@ namespace Nz
const auto& viewerInstance = m_viewer->GetViewerInstance();
auto& lightPerRenderElement = m_lightPerRenderElement;
m_pipeline.ProcessRenderQueue(m_renderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
m_elementRegistry.ProcessRenderQueue(m_renderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
{
ElementRenderer& elementRenderer = m_pipeline.GetElementRenderer(elementType);
ElementRenderer& elementRenderer = m_elementRegistry.GetElementRenderer(elementType);
m_renderStates.clear();
@@ -228,7 +234,7 @@ namespace Nz
elementRenderer.Prepare(viewerInstance, *m_elementRendererData[elementType], renderFrame, elementCount, elements, m_renderStates.data());
});
m_pipeline.ForEachElementRenderer([&](std::size_t elementType, ElementRenderer& elementRenderer)
m_elementRegistry.ForEachElementRenderer([&](std::size_t elementType, ElementRenderer& elementRenderer)
{
elementRenderer.PrepareEnd(renderFrame, *m_elementRendererData[elementType]);
});
@@ -291,9 +297,9 @@ namespace Nz
const auto& viewerInstance = m_viewer->GetViewerInstance();
m_pipeline.ProcessRenderQueue(m_renderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
m_elementRegistry.ProcessRenderQueue(m_renderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
{
ElementRenderer& elementRenderer = m_pipeline.GetElementRenderer(elementType);
ElementRenderer& elementRenderer = m_elementRegistry.GetElementRenderer(elementType);
elementRenderer.Render(viewerInstance, *m_elementRendererData[elementType], builder, elementCount, elements);
});

View File

@@ -3,20 +3,14 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/FramePipeline.hpp>
#include <Nazara/Graphics/Enums.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/SpriteChainRenderer.hpp>
#include <Nazara/Graphics/SubmeshRenderer.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
FramePipeline::FramePipeline() :
m_elementRenderers(BasicRenderElementCount),
m_debugDrawer(*Graphics::Instance()->GetRenderDevice())
{
m_elementRenderers[UnderlyingCast(BasicRenderElement::SpriteChain)] = std::make_unique<SpriteChainRenderer>(*Graphics::Instance()->GetRenderDevice());
m_elementRenderers[UnderlyingCast(BasicRenderElement::Submesh)] = std::make_unique<SubmeshRenderer>();
}
FramePipeline::~FramePipeline() = default;

View File

@@ -4,6 +4,7 @@
#include <Nazara/Graphics/LinearSlicedSprite.hpp>
#include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Graphics/ElementRendererRegistry.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/RenderSpriteChain.hpp>
#include <Nazara/Graphics/Debug.hpp>
@@ -22,7 +23,7 @@ namespace Nz
UpdateVertices();
}
void LinearSlicedSprite::BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, const SkeletonInstance* skeletonInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const
void LinearSlicedSprite::BuildElement(ElementRendererRegistry& registry, const ElementData& elementData, std::size_t passIndex, std::vector<RenderElementOwner>& elements) const
{
const auto& materialPass = m_material->GetPass(passIndex);
if (!materialPass)
@@ -42,7 +43,7 @@ namespace Nz
const auto& whiteTexture = Graphics::Instance()->GetDefaultTextures().whiteTextures[UnderlyingCast(ImageType::E2D)];
elements.emplace_back(std::make_unique<RenderSpriteChain>(GetRenderLayer(), materialPass, renderPipeline, worldInstance, vertexDeclaration, whiteTexture, m_spriteCount, m_vertices.data(), scissorBox));
elements.emplace_back(registry.AllocateElement<RenderSpriteChain>(GetRenderLayer(), materialPass, renderPipeline, *elementData.worldInstance, vertexDeclaration, whiteTexture, m_spriteCount, m_vertices.data(), *elementData.scissorBox));
}
const std::shared_ptr<Material>& LinearSlicedSprite::GetMaterial(std::size_t i) const

View File

@@ -3,6 +3,7 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/Model.hpp>
#include <Nazara/Graphics/ElementRendererRegistry.hpp>
#include <Nazara/Graphics/GraphicalMesh.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/Material.hpp>
@@ -37,7 +38,7 @@ namespace Nz
UpdateAABB(aabb);
}
void Model::BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, const SkeletonInstance* skeletonInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const
void Model::BuildElement(ElementRendererRegistry& registry, const ElementData& elementData, std::size_t passIndex, std::vector<RenderElementOwner>& elements) const
{
for (std::size_t i = 0; i < m_submeshes.size(); ++i)
{
@@ -54,7 +55,7 @@ namespace Nz
std::size_t indexCount = m_graphicalMesh->GetIndexCount(i);
IndexType indexType = m_graphicalMesh->GetIndexType(i);
elements.emplace_back(std::make_unique<RenderSubmesh>(GetRenderLayer(), materialPass, renderPipeline, worldInstance, skeletonInstance, indexCount, indexType, indexBuffer, vertexBuffer, scissorBox));
elements.emplace_back(registry.AllocateElement<RenderSubmesh>(GetRenderLayer(), materialPass, renderPipeline, *elementData.worldInstance, elementData.skeletonInstance, indexCount, indexType, indexBuffer, vertexBuffer, *elementData.scissorBox));
}
}

View File

@@ -0,0 +1,16 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/RenderElementOwner.hpp>
#include <Nazara/Graphics/RenderElementPool.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
RenderElementOwner::~RenderElementOwner()
{
if (m_pool)
m_pool->Free(m_poolIndex);
}
}

View File

@@ -0,0 +1,11 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/RenderElementPool.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
RenderElementPoolBase::~RenderElementPoolBase() = default;
}

View File

@@ -4,6 +4,7 @@
#include <Nazara/Graphics/SlicedSprite.hpp>
#include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Graphics/ElementRendererRegistry.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/RenderSpriteChain.hpp>
#include <Nazara/Graphics/Debug.hpp>
@@ -19,7 +20,7 @@ namespace Nz
UpdateVertices();
}
void SlicedSprite::BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, const SkeletonInstance* skeletonInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const
void SlicedSprite::BuildElement(ElementRendererRegistry& registry, const ElementData& elementData, std::size_t passIndex, std::vector<RenderElementOwner>& elements) const
{
const auto& materialPass = m_material->GetPass(passIndex);
if (!materialPass)
@@ -39,7 +40,7 @@ namespace Nz
const auto& whiteTexture = Graphics::Instance()->GetDefaultTextures().whiteTextures[UnderlyingCast(ImageType::E2D)];
elements.emplace_back(std::make_unique<RenderSpriteChain>(GetRenderLayer(), materialPass, renderPipeline, worldInstance, vertexDeclaration, whiteTexture, m_spriteCount, m_vertices.data(), scissorBox));
elements.emplace_back(registry.AllocateElement<RenderSpriteChain>(GetRenderLayer(), materialPass, renderPipeline, *elementData.worldInstance, vertexDeclaration, whiteTexture, m_spriteCount, m_vertices.data(), *elementData.scissorBox));
}
const std::shared_ptr<Material>& SlicedSprite::GetMaterial(std::size_t i) const

View File

@@ -4,6 +4,7 @@
#include <Nazara/Graphics/Sprite.hpp>
#include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Graphics/ElementRendererRegistry.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/RenderSpriteChain.hpp>
#include <Nazara/Graphics/WorldInstance.hpp>
@@ -23,7 +24,7 @@ namespace Nz
UpdateVertices();
}
void Sprite::BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, const SkeletonInstance* skeletonInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const
void Sprite::BuildElement(ElementRendererRegistry& registry, const ElementData& elementData, std::size_t passIndex, std::vector<RenderElementOwner>& elements) const
{
const auto& materialPass = m_material->GetPass(passIndex);
if (!materialPass)
@@ -43,7 +44,7 @@ namespace Nz
const auto& whiteTexture = Graphics::Instance()->GetDefaultTextures().whiteTextures[UnderlyingCast(ImageType::E2D)];
elements.emplace_back(std::make_unique<RenderSpriteChain>(GetRenderLayer(), materialPass, renderPipeline, worldInstance, vertexDeclaration, whiteTexture, 1, m_vertices.data(), scissorBox));
elements.emplace_back(registry.AllocateElement<RenderSpriteChain>(GetRenderLayer(), materialPass, renderPipeline, *elementData.worldInstance, vertexDeclaration, whiteTexture, 1, m_vertices.data(), *elementData.scissorBox));
}
const std::shared_ptr<Material>& Sprite::GetMaterial(std::size_t i) const

View File

@@ -45,6 +45,11 @@ namespace Nz
m_indexBuffer = m_device.InstantiateBuffer(BufferType::Index, indexCount * sizeof(UInt16), BufferUsage::DeviceLocal | BufferUsage::Write, indices.data());
}
RenderElementPool<RenderSpriteChain>& SpriteChainRenderer::GetPool()
{
return m_spriteChainPool;
}
std::unique_ptr<ElementRendererData> SpriteChainRenderer::InstanciateData()
{
return std::make_unique<SpriteChainRendererData>();

View File

@@ -13,6 +13,11 @@
namespace Nz
{
RenderElementPool<RenderSubmesh>& SubmeshRenderer::GetPool()
{
return m_submeshPool;
}
std::unique_ptr<ElementRendererData> SubmeshRenderer::InstanciateData()
{
return std::make_unique<SubmeshRendererData>();

View File

@@ -37,7 +37,7 @@ namespace Nz
m_sharedSkeletonDestroyConnection = registry.on_destroy<SharedSkeletonComponent>().connect<&RenderSystem::OnSharedSkeletonDestroy>(this);
m_skeletonDestroyConnection = registry.on_destroy<SkeletonComponent>().connect<&RenderSystem::OnSkeletonDestroy>(this);
m_pipeline = std::make_unique<ForwardFramePipeline>();
m_pipeline = std::make_unique<ForwardFramePipeline>(m_elementRegistry);
}
RenderSystem::~RenderSystem()
@@ -45,6 +45,7 @@ namespace Nz
m_cameraConstructObserver.disconnect();
m_graphicsConstructObserver.disconnect();
m_lightConstructObserver.disconnect();
m_pipeline.reset();
}
void RenderSystem::Update(float /*elapsedTime*/)

View File

@@ -3,6 +3,7 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/TextSprite.hpp>
#include <Nazara/Graphics/ElementRendererRegistry.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/RenderSpriteChain.hpp>
#include <Nazara/Graphics/WorldInstance.hpp>
@@ -18,7 +19,7 @@ namespace Nz
{
}
void TextSprite::BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, const SkeletonInstance* skeletonInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const
void TextSprite::BuildElement(ElementRendererRegistry& registry, const ElementData& elementData, std::size_t passIndex, std::vector<RenderElementOwner>& elements) const
{
const auto& materialPass = m_material->GetPass(passIndex);
if (!materialPass)
@@ -42,7 +43,7 @@ namespace Nz
RenderIndices& indices = pair.second;
if (indices.count > 0)
elements.emplace_back(std::make_unique<RenderSpriteChain>(GetRenderLayer(), materialPass, renderPipeline, worldInstance, vertexDeclaration, key.texture->shared_from_this(), indices.count, &m_vertices[indices.first * 4], scissorBox));
elements.emplace_back(registry.AllocateElement<RenderSpriteChain>(GetRenderLayer(), materialPass, renderPipeline, *elementData.worldInstance, vertexDeclaration, key.texture->shared_from_this(), indices.count, &m_vertices[indices.first * 4], *elementData.scissorBox));
}
}

View File

@@ -3,9 +3,9 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Utility/Components/NodeComponent.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Utility/Components/SharedSkeletonComponent.hpp>
#include <Nazara/Utility/Components/SkeletonComponent.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Utility/Debug.hpp>
namespace Nz