Files
NazaraEngine/src/Nazara/Graphics/DepthPipelinePass.cpp
2023-01-22 17:41:18 +01:00

174 lines
5.8 KiB
C++

// Copyright (C) 2023 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/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/InstancedRenderable.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Renderer/RenderFrame.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
DepthPipelinePass::DepthPipelinePass(FramePipeline& owner, ElementRendererRegistry& elementRegistry, AbstractViewer* viewer, std::size_t passIndex, std::string passName) :
m_passIndex(passIndex),
m_lastVisibilityHash(0),
m_passName(std::move(passName)),
m_viewer(viewer),
m_elementRegistry(elementRegistry),
m_pipeline(owner),
m_rebuildCommandBuffer(false),
m_rebuildElements(false)
{
}
void DepthPipelinePass::Prepare(RenderFrame& renderFrame, const Frustumf& frustum, const std::vector<FramePipelinePass::VisibleRenderable>& visibleRenderables, std::size_t visibilityHash)
{
if (m_lastVisibilityHash != visibilityHash || m_rebuildElements) //< FIXME
{
renderFrame.PushForRelease(std::move(m_renderElements));
m_renderElements.clear();
for (const auto& renderableData : visibleRenderables)
{
InstancedRenderable::ElementData elementData{
&renderableData.scissorBox,
renderableData.skeletonInstance,
renderableData.worldInstance
};
renderableData.instancedRenderable->BuildElement(m_elementRegistry, elementData, m_passIndex, m_renderElements);
}
m_renderQueueRegistry.Clear();
m_renderQueue.Clear();
for (const auto& renderElement : m_renderElements)
{
renderElement->Register(m_renderQueueRegistry);
m_renderQueue.Insert(renderElement.GetElement());
}
m_renderQueueRegistry.Finalize();
m_lastVisibilityHash = visibilityHash;
m_rebuildElements = true;
}
// TODO: Don't sort every frame if no material pass requires distance sorting
m_renderQueue.Sort([&](const RenderElement* element)
{
return element->ComputeSortingScore(frustum, m_renderQueueRegistry);
});
if (m_rebuildElements)
{
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);
m_elementRendererData[elementType] = elementRenderer.InstanciateData();
}
elementRenderer.Reset(*m_elementRendererData[elementType], renderFrame);
});
const auto& viewerInstance = m_viewer->GetViewerInstance();
m_elementRegistry.ProcessRenderQueue(m_renderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
{
ElementRenderer& elementRenderer = m_elementRegistry.GetElementRenderer(elementType);
m_renderStates.clear();
m_renderStates.resize(elementCount);
elementRenderer.Prepare(viewerInstance, *m_elementRendererData[elementType], renderFrame, elementCount, elements, m_renderStates.data());
});
m_elementRegistry.ForEachElementRenderer([&](std::size_t elementType, ElementRenderer& elementRenderer)
{
elementRenderer.PrepareEnd(renderFrame, *m_elementRendererData[elementType]);
});
m_rebuildCommandBuffer = true;
m_rebuildElements = false;
}
}
void DepthPipelinePass::RegisterMaterialInstance(const MaterialInstance& materialInstance)
{
if (!materialInstance.HasPass(m_passIndex))
return;
auto it = m_materialInstances.find(&materialInstance);
if (it == m_materialInstances.end())
{
auto& matPassEntry = m_materialInstances[&materialInstance];
matPassEntry.onMaterialInstancePipelineInvalidated.Connect(materialInstance.OnMaterialInstancePipelineInvalidated, [=](const MaterialInstance*, std::size_t passIndex)
{
if (passIndex != m_passIndex)
return;
m_rebuildElements = true;
});
matPassEntry.onMaterialInstanceShaderBindingInvalidated.Connect(materialInstance.OnMaterialInstanceShaderBindingInvalidated, [=](const MaterialInstance*)
{
m_rebuildCommandBuffer = true;
});
}
else
it->second.usedCount++;
}
FramePass& DepthPipelinePass::RegisterToFrameGraph(FrameGraph& frameGraph, std::size_t outputAttachment)
{
FramePass& depthPrepass = frameGraph.AddPass(m_passName);
depthPrepass.SetDepthStencilOutput(outputAttachment);
depthPrepass.SetDepthStencilClear(1.f, 0);
depthPrepass.SetExecutionCallback([&]()
{
return (m_rebuildCommandBuffer) ? FramePassExecution::UpdateAndExecute : FramePassExecution::Execute;
});
depthPrepass.SetCommandCallback([this](CommandBufferBuilder& builder, const FramePassEnvironment& /*env*/)
{
Recti viewport = m_viewer->GetViewport();
builder.SetScissor(viewport);
builder.SetViewport(viewport);
const auto& viewerInstance = m_viewer->GetViewerInstance();
m_elementRegistry.ProcessRenderQueue(m_renderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
{
ElementRenderer& elementRenderer = m_elementRegistry.GetElementRenderer(elementType);
elementRenderer.Render(viewerInstance, *m_elementRendererData[elementType], builder, elementCount, elements);
});
m_rebuildCommandBuffer = false;
});
return depthPrepass;
}
void DepthPipelinePass::UnregisterMaterialInstance(const MaterialInstance& materialInstance)
{
auto it = m_materialInstances.find(&materialInstance);
if (it != m_materialInstances.end())
{
if (--it->second.usedCount == 0)
m_materialInstances.erase(it);
}
}
}