Graphics: Add data-driven pipeline passes

Fix compilation
This commit is contained in:
SirLynix
2023-11-02 16:19:41 +01:00
committed by Jérôme Leclercq
parent 4995364418
commit 8fb6ea728d
41 changed files with 876 additions and 264 deletions

View File

@@ -3,11 +3,25 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/Camera.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/PipelinePassList.hpp>
#include <cassert>
#include <stdexcept>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
Camera::Camera(const RenderTarget* renderTarget, ProjectionType projectionType) :
Camera(renderTarget, Graphics::Instance()->GetDefaultPipelinePasses(), projectionType)
{
}
std::vector<std::unique_ptr<FramePipelinePass>> Camera::BuildPasses(FramePipelinePass::PassData& passData) const
{
assert(m_framePipelinePasses);
return m_framePipelinePasses->BuildPasses(passData);
}
const Color& Camera::GetClearColor() const
{
return m_clearColor;
@@ -41,6 +55,12 @@ namespace Nz
return m_viewport;
}
std::size_t Camera::RegisterPasses(const std::vector<std::unique_ptr<FramePipelinePass>>& passes, FrameGraph& frameGraph) const
{
assert(m_framePipelinePasses);
return m_framePipelinePasses->RegisterPasses(passes, frameGraph);
}
void Camera::UpdateTarget(const RenderTarget* renderTarget)
{
m_onRenderTargetRelease.Disconnect();

View File

@@ -8,31 +8,36 @@
#include <Nazara/Graphics/FramePipeline.hpp>
#include <Nazara/Graphics/ViewerInstance.hpp>
#include <Nazara/Renderer/DebugDrawer.hpp>
#include <Nazara/Renderer/RenderFrame.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
DebugDrawPipelinePass::DebugDrawPipelinePass(FramePipeline& owner, AbstractViewer* viewer) :
m_viewer(viewer),
m_pipeline(owner)
{
}
void DebugDrawPipelinePass::Prepare(RenderFrame& renderFrame)
void DebugDrawPipelinePass::Prepare(FrameData& frameData)
{
DebugDrawer& debugDrawer = m_pipeline.GetDebugDrawer();
debugDrawer.SetViewerData(m_viewer->GetViewerInstance().GetViewProjMatrix());
debugDrawer.Prepare(renderFrame);
debugDrawer.Prepare(frameData.renderFrame);
}
FramePass& DebugDrawPipelinePass::RegisterToFrameGraph(FrameGraph& frameGraph, std::size_t inputColorBufferIndex, std::size_t outputColorBufferIndex)
FramePass& DebugDrawPipelinePass::RegisterToFrameGraph(FrameGraph& frameGraph, const PassInputOuputs& inputOuputs)
{
FramePass& debugDrawPass = frameGraph.AddPass("Debug draw pass");
debugDrawPass.AddInput(inputColorBufferIndex);
debugDrawPass.AddOutput(outputColorBufferIndex);
if (inputOuputs.inputCount != 1)
throw std::runtime_error("one input expected");
debugDrawPass.SetExecutionCallback([&]()
if (inputOuputs.outputCount != 1)
throw std::runtime_error("one output expected");
FramePass& debugDrawPass = frameGraph.AddPass("Debug draw pass");
debugDrawPass.AddInput(inputOuputs.inputAttachments[0]);
debugDrawPass.AddOutput(inputOuputs.outputAttachments[0]);
if (inputOuputs.depthStencilInput != InvalidAttachmentIndex)
debugDrawPass.SetDepthStencilInput(inputOuputs.depthStencilInput);
if (inputOuputs.depthStencilOutput != InvalidAttachmentIndex)
debugDrawPass.SetDepthStencilOutput(inputOuputs.depthStencilInput);
debugDrawPass.SetExecutionCallback([&]
{
return FramePassExecution::UpdateAndExecute;
});

View File

@@ -8,6 +8,7 @@
#include <Nazara/Graphics/ElementRendererRegistry.hpp>
#include <Nazara/Graphics/FrameGraph.hpp>
#include <Nazara/Graphics/FramePipeline.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/InstancedRenderable.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Renderer/RenderFrame.hpp>
@@ -15,26 +16,14 @@
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(FrameData& frameData)
{
}
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
if (m_lastVisibilityHash != frameData.visibilityHash || m_rebuildElements) //< FIXME
{
renderFrame.PushForRelease(std::move(m_renderElements));
frameData.renderFrame.PushForRelease(std::move(m_renderElements));
m_renderElements.clear();
for (const auto& renderableData : visibleRenderables)
for (const auto& renderableData : frameData.visibleRenderables)
{
InstancedRenderable::ElementData elementData{
&renderableData.scissorBox,
@@ -56,14 +45,14 @@ namespace Nz
m_renderQueueRegistry.Finalize();
m_lastVisibilityHash = visibilityHash;
m_lastVisibilityHash = frameData.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);
return element->ComputeSortingScore(frameData.frustum, m_renderQueueRegistry);
});
if (m_rebuildElements)
@@ -78,7 +67,7 @@ namespace Nz
m_elementRendererData[elementType] = elementRenderer.InstanciateData();
}
elementRenderer.Reset(*m_elementRendererData[elementType], renderFrame);
elementRenderer.Reset(*m_elementRendererData[elementType], frameData.renderFrame);
});
const auto& viewerInstance = m_viewer->GetViewerInstance();
@@ -89,12 +78,12 @@ namespace Nz
{
ElementRenderer& elementRenderer = m_elementRegistry.GetElementRenderer(elementType);
elementRenderer.Prepare(viewerInstance, *m_elementRendererData[elementType], renderFrame, elementCount, elements, SparsePtr(&defaultRenderStates, 0));
elementRenderer.Prepare(viewerInstance, *m_elementRendererData[elementType], frameData.renderFrame, elementCount, elements, SparsePtr(&defaultRenderStates, 0));
});
m_elementRegistry.ForEachElementRenderer([&](std::size_t elementType, ElementRenderer& elementRenderer)
{
elementRenderer.PrepareEnd(renderFrame, *m_elementRendererData[elementType]);
elementRenderer.PrepareEnd(frameData.renderFrame, *m_elementRendererData[elementType]);
});
m_rebuildCommandBuffer = true;
@@ -128,13 +117,25 @@ namespace Nz
it->second.usedCount++;
}
FramePass& DepthPipelinePass::RegisterToFrameGraph(FrameGraph& frameGraph, std::size_t outputAttachment)
FramePass& DepthPipelinePass::RegisterToFrameGraph(FrameGraph& frameGraph, const PassInputOuputs& inputOuputs)
{
if (inputOuputs.inputCount > 0)
throw std::runtime_error("no input expected");
if (inputOuputs.outputCount > 0)
throw std::runtime_error("no output expected");
if (inputOuputs.depthStencilInput != InvalidAttachmentIndex)
throw std::runtime_error("no depth-stencil input expected");
if (inputOuputs.depthStencilOutput == InvalidAttachmentIndex)
throw std::runtime_error("expected depth-stencil output");
FramePass& depthPrepass = frameGraph.AddPass(m_passName);
depthPrepass.SetDepthStencilOutput(outputAttachment);
depthPrepass.SetDepthStencilOutput(inputOuputs.depthStencilOutput);
depthPrepass.SetDepthStencilClear(1.f, 0);
depthPrepass.SetExecutionCallback([&]()
depthPrepass.SetExecutionCallback([&]
{
return (m_rebuildCommandBuffer) ? FramePassExecution::UpdateAndExecute : FramePassExecution::Execute;
});
@@ -169,4 +170,24 @@ namespace Nz
m_materialInstances.erase(it);
}
}
std::size_t DepthPipelinePass::GetMaterialPassIndex(const ParameterList& parameters)
{
Result<long long, ParameterList::Error> passIndexResult = parameters.GetIntegerParameter("MatPassIndex");
if (passIndexResult.IsOk())
return passIndexResult.GetValue();
// TODO: Log error if key is present but not of the right
Result<std::string_view, ParameterList::Error> passResult = parameters.GetStringViewParameter("MatPass");
if (passIndexResult.IsOk())
{
auto& materialPassRegistry = Graphics::Instance()->GetMaterialPassRegistry();
std::string_view passName = passResult.GetValue();
return materialPassRegistry.GetPassIndex(passName);
}
// TODO: Log error if key is present but not of the right
throw std::runtime_error("DepthPipelinePass expect either MatPass or MatPassIndex parameter");
}
}

View File

@@ -118,7 +118,15 @@ namespace Nz
std::size_t visibilityHash = 5U;
const auto& visibleRenderables = m_pipeline.FrustumCull(lightFrustum, 0xFFFFFFFF, visibilityHash);
cascade.depthPass->Prepare(renderFrame, lightFrustum, visibleRenderables, visibilityHash);
FramePipelinePass::FrameData passData = {
nullptr,
frustum,
renderFrame,
visibleRenderables,
visibilityHash
};
cascade.depthPass->Prepare(passData);
}
}
@@ -233,7 +241,11 @@ namespace Nz
CascadeData& cascade = viewerData.cascades[i];
cascade.attachmentIndex = frameGraph.AddAttachmentArrayLayer(viewerData.textureArrayAttachmentIndex, i);
cascade.depthPass->RegisterToFrameGraph(frameGraph, cascade.attachmentIndex);
FramePipelinePass::PassInputOuputs passInputOuputs;
passInputOuputs.depthStencilOutput = cascade.attachmentIndex;
cascade.depthPass->RegisterToFrameGraph(frameGraph, passInputOuputs);
}
}
@@ -254,7 +266,13 @@ namespace Nz
shadowViewer.UpdateRenderMask(0xFFFFFFFF);
shadowViewer.UpdateViewport(Recti(0, 0, SafeCast<int>(shadowMapSize), SafeCast<int>(shadowMapSize)));
cascade.depthPass.emplace(m_pipeline, m_elementRegistry, &shadowViewer, shadowPassIndex, Format("Cascade #{}", cascadeIndex++));
FramePipelinePass::PassData passData = {
&shadowViewer,
m_elementRegistry,
m_pipeline
};
cascade.depthPass.emplace(passData, Format("Cascade #{}", cascadeIndex++), shadowPassIndex);
}
m_pipeline.ForEachRegisteredMaterialInstance([&](const MaterialInstance& matInstance)

View File

@@ -3,11 +3,11 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/ForwardFramePipeline.hpp>
#include <Nazara/Graphics/AbstractViewer.hpp>
#include <Nazara/Graphics/FrameGraph.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/InstancedRenderable.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/PipelineViewer.hpp>
#include <Nazara/Graphics/PointLight.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Graphics/RenderElement.hpp>
@@ -110,16 +110,6 @@ namespace Nz
lightData->onLightInvalidated.Connect(lightData->light->OnLightDataInvalided, [=](Light*)
{
//TODO: Switch lights to storage buffers so they can all be part of GPU memory
for (auto& viewerData : m_viewerPool)
{
if (viewerData.pendingDestruction)
continue;
UInt32 viewerRenderMask = viewerData.viewer->GetRenderMask();
if (viewerRenderMask & renderMask)
viewerData.forwardPass->InvalidateElements();
}
});
lightData->onLightShadowCastingChanged.Connect(lightData->light->OnLightShadowCastingChanged, [=](Light* light, bool isCastingShadows)
@@ -194,10 +184,11 @@ namespace Nz
if (viewerRenderMask & renderMask)
{
if (viewerData.depthPrepass)
viewerData.depthPrepass->InvalidateElements();
viewerData.forwardPass->InvalidateElements();
for (auto& passPtr : viewerData.passes)
{
if (passPtr->ShouldNotify(FramePipelineNotification::ElementInvalidation))
passPtr->InvalidateElements();
}
}
}
});
@@ -213,10 +204,11 @@ namespace Nz
if (viewerData.pendingDestruction)
continue;
if (viewerData.depthPrepass)
viewerData.depthPrepass->RegisterMaterialInstance(*newMaterial);
viewerData.forwardPass->RegisterMaterialInstance(*newMaterial);
for (auto& passPtr : viewerData.passes)
{
if (passPtr->ShouldNotify(FramePipelineNotification::MaterialInstanceRegistration))
passPtr->RegisterMaterialInstance(*newMaterial);
}
}
}
@@ -230,10 +222,11 @@ namespace Nz
if (viewerData.pendingDestruction)
continue;
if (viewerData.depthPrepass)
viewerData.depthPrepass->UnregisterMaterialInstance(*prevMaterial);
viewerData.forwardPass->UnregisterMaterialInstance(*prevMaterial);
for (auto& passPtr : viewerData.passes)
{
if (passPtr->ShouldNotify(FramePipelineNotification::MaterialInstanceRegistration))
passPtr->UnregisterMaterialInstance(*prevMaterial);
}
}
}
});
@@ -250,10 +243,11 @@ namespace Nz
if (viewerData.pendingDestruction)
continue;
if (viewerData.depthPrepass)
viewerData.depthPrepass->RegisterMaterialInstance(*mat);
viewerData.forwardPass->RegisterMaterialInstance(*mat);
for (auto& passPtr : viewerData.passes)
{
if (passPtr->ShouldNotify(FramePipelineNotification::MaterialInstanceRegistration))
passPtr->RegisterMaterialInstance(*mat);
}
}
}
}
@@ -275,28 +269,24 @@ namespace Nz
return skeletonInstanceIndex;
}
std::size_t ForwardFramePipeline::RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder, FramePipelineExtraPassFlags passFlags)
std::size_t ForwardFramePipeline::RegisterViewer(PipelineViewer* viewerInstance, Int32 renderOrder)
{
std::size_t depthPassIndex = Graphics::Instance()->GetMaterialPassRegistry().GetPassIndex("DepthPass");
std::size_t viewerIndex;
auto& viewerData = *m_viewerPool.Allocate(viewerIndex);
viewerData.renderOrder = renderOrder;
viewerData.forwardPass = std::make_unique<ForwardPipelinePass>(*this, m_elementRegistry, viewerInstance);
viewerData.viewer = viewerInstance;
viewerData.onTransferRequired.Connect(viewerInstance->GetViewerInstance().OnTransferRequired, [this](TransferInterface* transferInterface)
{
m_transferSet.insert(transferInterface);
});
if (passFlags.Test(FramePipelineExtraPass::DebugDraw))
viewerData.debugDrawPass = std::make_unique<DebugDrawPipelinePass>(*this, viewerInstance);
FramePipelinePass::PassData passData = {
viewerInstance,
m_elementRegistry,
*this
};
if (passFlags.Test(FramePipelineExtraPass::DepthPrepass))
viewerData.depthPrepass = std::make_unique<DepthPipelinePass>(*this, m_elementRegistry, viewerInstance, depthPassIndex, "Depth pre-pass");
if (passFlags.Test(FramePipelineExtraPass::GammaCorrection))
viewerData.gammaCorrectionPass = std::make_unique<PostProcessPipelinePass>(*this, "Gamma correction", "PostProcess.GammaCorrection");
viewerData.passes = viewerInstance->BuildPasses(passData);
m_transferSet.insert(&viewerInstance->GetViewerInstance());
@@ -446,16 +436,16 @@ namespace Nz
std::size_t visibilityHash = 5;
const auto& visibleRenderables = FrustumCull(viewerData.frame.frustum, renderMask, visibilityHash);
if (viewerData.depthPrepass)
viewerData.depthPrepass->Prepare(renderFrame, viewerData.frame.frustum, visibleRenderables, visibilityHash);
FramePipelinePass::FrameData passData = {
&viewerData.frame.visibleLights,
viewerData.frame.frustum,
renderFrame,
visibleRenderables,
visibilityHash
};
viewerData.forwardPass->Prepare(renderFrame, viewerData.frame.frustum, visibleRenderables, viewerData.frame.visibleLights, visibilityHash);
if (viewerData.gammaCorrectionPass)
viewerData.gammaCorrectionPass->Prepare(renderFrame);
if (viewerData.debugDrawPass)
viewerData.debugDrawPass->Prepare(renderFrame);
for (auto& passPtr : viewerData.passes)
passPtr->Prepare(passData);
}
if (frameGraphInvalidated)
@@ -587,10 +577,11 @@ namespace Nz
if (viewerData.pendingDestruction)
continue;
if (viewerData.depthPrepass)
viewerData.depthPrepass->UnregisterMaterialInstance(*material);
viewerData.forwardPass->UnregisterMaterialInstance(*material);
for (auto& passPtr : viewerData.passes)
{
if (passPtr->ShouldNotify(FramePipelineNotification::MaterialInstanceRegistration))
passPtr->UnregisterMaterialInstance(*material);
}
}
}
@@ -654,10 +645,11 @@ namespace Nz
if (viewerRenderMask & renderableData->renderMask)
{
if (viewerData.depthPrepass)
viewerData.depthPrepass->InvalidateElements();
viewerData.forwardPass->InvalidateElements();
for (auto& passPtr : viewerData.passes)
{
if (passPtr->ShouldNotify(FramePipelineNotification::ElementInvalidation))
passPtr->InvalidateElements();
}
}
}
}
@@ -677,10 +669,11 @@ namespace Nz
if (viewerRenderMask & renderableData->renderMask)
{
if (viewerData.depthPrepass)
viewerData.depthPrepass->InvalidateElements();
viewerData.forwardPass->InvalidateElements();
for (auto& passPtr : viewerData.passes)
{
if (passPtr->ShouldNotify(FramePipelineNotification::ElementInvalidation))
passPtr->InvalidateElements();
}
}
}
}
@@ -720,46 +713,7 @@ namespace Nz
lightData->shadowData->RegisterToFrameGraph(frameGraph, viewerData.viewer);
}
viewerData.forwardColorAttachment = frameGraph.AddAttachment({
"Forward output",
PixelFormat::RGBA8
});
viewerData.depthStencilAttachment = frameGraph.AddAttachment({
"Depth-stencil buffer",
Graphics::Instance()->GetPreferredDepthStencilFormat()
});
if (viewerData.depthPrepass)
viewerData.depthPrepass->RegisterToFrameGraph(frameGraph, viewerData.depthStencilAttachment);
FramePass& forwardPass = viewerData.forwardPass->RegisterToFrameGraph(frameGraph, viewerData.forwardColorAttachment, viewerData.depthStencilAttachment, viewerData.depthPrepass != nullptr);
for (std::size_t i : m_shadowCastingLights.IterBits())
{
LightData* lightData = m_lightPool.RetrieveFromIndex(i);
if ((renderMask & lightData->renderMask) != 0)
lightData->shadowData->RegisterPassInputs(forwardPass, (lightData->shadowData->IsPerViewer()) ? viewerData.viewer : nullptr);
}
viewerData.finalColorAttachment = viewerData.forwardColorAttachment;
if (viewerData.gammaCorrectionPass)
{
std::size_t postGammaColorAttachment = frameGraph.AddAttachment({
"Gamma-corrected output",
PixelFormat::RGBA8
});
viewerData.gammaCorrectionPass->RegisterToFrameGraph(frameGraph, viewerData.finalColorAttachment, postGammaColorAttachment);
viewerData.finalColorAttachment = postGammaColorAttachment;
}
if (viewerData.debugDrawPass)
{
viewerData.debugColorAttachment = frameGraph.AddAttachmentProxy("Debug draw output", viewerData.finalColorAttachment);
viewerData.debugDrawPass->RegisterToFrameGraph(frameGraph, viewerData.finalColorAttachment, viewerData.debugColorAttachment);
viewerData.finalColorAttachment = viewerData.debugColorAttachment;
}
viewerData.finalColorAttachment = viewerData.viewer->RegisterPasses(viewerData.passes, frameGraph);
}
using ViewerPair = std::pair<const RenderTarget*, const ViewerData*>;

View File

@@ -5,6 +5,7 @@
#include <Nazara/Graphics/ForwardPipelinePass.hpp>
#include <Nazara/Graphics/AbstractViewer.hpp>
#include <Nazara/Graphics/DirectionalLight.hpp>
#include <Nazara/Graphics/DirectionalLightShadowData.hpp>
#include <Nazara/Graphics/ElementRendererRegistry.hpp>
#include <Nazara/Graphics/FrameGraph.hpp>
#include <Nazara/Graphics/FramePipeline.hpp>
@@ -12,9 +13,8 @@
#include <Nazara/Graphics/InstancedRenderable.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/PointLight.hpp>
#include <Nazara/Graphics/SpotLight.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Graphics/DirectionalLightShadowData.hpp>
#include <Nazara/Graphics/SpotLight.hpp>
#include <Nazara/Graphics/SpotLightShadowData.hpp>
#include <Nazara/Graphics/ViewerInstance.hpp>
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
@@ -23,11 +23,13 @@
namespace Nz
{
ForwardPipelinePass::ForwardPipelinePass(FramePipeline& owner, ElementRendererRegistry& elementRegistry, AbstractViewer* viewer) :
ForwardPipelinePass::ForwardPipelinePass(PassData& passData, std::string passName, const ParameterList& /*parameters*/) :
FramePipelinePass(FramePipelineNotification::ElementInvalidation | FramePipelineNotification::MaterialInstanceRegistration),
m_lastVisibilityHash(0),
m_viewer(viewer),
m_elementRegistry(elementRegistry),
m_pipeline(owner),
m_passName(std::move(passName)),
m_viewer(passData.viewer),
m_elementRegistry(passData.elementRegistry),
m_pipeline(passData.pipeline),
m_pendingLightUploadAllocation(nullptr),
m_rebuildCommandBuffer(false),
m_rebuildElements(false)
@@ -42,14 +44,16 @@ namespace Nz
m_renderState.lightData = RenderBufferView(m_lightDataBuffer.get());
}
void ForwardPipelinePass::Prepare(RenderFrame& renderFrame, const Frustumf& frustum, const std::vector<FramePipelinePass::VisibleRenderable>& visibleRenderables, const Bitset<UInt64>& visibleLights, std::size_t visibilityHash)
void ForwardPipelinePass::Prepare(FrameData& frameData)
{
if (m_lastVisibilityHash != visibilityHash || m_rebuildElements) //< FIXME
NazaraAssert(frameData.visibleLights, "visible lights must be valid");
if (m_lastVisibilityHash != frameData.visibilityHash || m_rebuildElements) //< FIXME
{
renderFrame.PushForRelease(std::move(m_renderElements));
frameData.renderFrame.PushForRelease(std::move(m_renderElements));
m_renderElements.clear();
for (const auto& renderableData : visibleRenderables)
for (const auto& renderableData : frameData.visibleRenderables)
{
InstancedRenderable::ElementData elementData{
&renderableData.scissorBox,
@@ -71,17 +75,17 @@ namespace Nz
m_renderQueueRegistry.Finalize();
m_lastVisibilityHash = visibilityHash;
m_lastVisibilityHash = frameData.visibilityHash;
InvalidateElements();
}
// 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);
return element->ComputeSortingScore(frameData.frustum, m_renderQueueRegistry);
});
PrepareLights(renderFrame, frustum, visibleLights);
PrepareLights(frameData.renderFrame, frameData.frustum, *frameData.visibleLights);
if (m_rebuildElements)
{
@@ -93,7 +97,7 @@ namespace Nz
if (!m_elementRendererData[elementType])
m_elementRendererData[elementType] = elementRenderer.InstanciateData();
elementRenderer.Reset(*m_elementRendererData[elementType], renderFrame);
elementRenderer.Reset(*m_elementRendererData[elementType], frameData.renderFrame);
});
const auto& viewerInstance = m_viewer->GetViewerInstance();
@@ -101,12 +105,12 @@ namespace Nz
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.Prepare(viewerInstance, *m_elementRendererData[elementType], renderFrame, elementCount, elements, SparsePtr(&m_renderState, 0));
elementRenderer.Prepare(viewerInstance, *m_elementRendererData[elementType], frameData.renderFrame, elementCount, elements, SparsePtr(&m_renderState, 0));
});
m_elementRegistry.ForEachElementRenderer([&](std::size_t elementType, ElementRenderer& elementRenderer)
{
elementRenderer.PrepareEnd(renderFrame, *m_elementRendererData[elementType]);
elementRenderer.PrepareEnd(frameData.renderFrame, *m_elementRendererData[elementType]);
});
m_rebuildCommandBuffer = true;
@@ -140,14 +144,23 @@ namespace Nz
it->second.usedCount++;
}
FramePass& ForwardPipelinePass::RegisterToFrameGraph(FrameGraph& frameGraph, std::size_t colorBufferIndex, std::size_t depthBufferIndex, bool hasDepthPrepass)
FramePass& ForwardPipelinePass::RegisterToFrameGraph(FrameGraph& frameGraph, const PassInputOuputs& inputOuputs)
{
FramePass& forwardPass = frameGraph.AddPass("Forward pass");
forwardPass.AddOutput(colorBufferIndex);
if (hasDepthPrepass)
forwardPass.SetDepthStencilInput(depthBufferIndex);
if (inputOuputs.inputCount > 0)
throw std::runtime_error("no input expected");
forwardPass.SetDepthStencilOutput(depthBufferIndex);
if (inputOuputs.outputCount != 1)
throw std::runtime_error("one output expected");
if (inputOuputs.depthStencilOutput == InvalidAttachmentIndex)
throw std::runtime_error("expected depth-stencil output");
FramePass& forwardPass = frameGraph.AddPass(m_passName);
forwardPass.AddOutput(inputOuputs.outputAttachments[0]);
if (inputOuputs.depthStencilInput != FramePipelinePass::InvalidAttachmentIndex)
forwardPass.SetDepthStencilInput(inputOuputs.depthStencilInput);
forwardPass.SetDepthStencilOutput(inputOuputs.depthStencilOutput);
forwardPass.SetClearColor(0, m_viewer->GetClearColor());
forwardPass.SetDepthStencilClear(1.f, 0);
@@ -188,7 +201,7 @@ namespace Nz
}
}
void ForwardPipelinePass::OnTransfer(RenderFrame& renderFrame, CommandBufferBuilder& builder)
void ForwardPipelinePass::OnTransfer(RenderFrame& /*renderFrame*/, CommandBufferBuilder& builder)
{
assert(m_pendingLightUploadAllocation);
builder.CopyBuffer(*m_pendingLightUploadAllocation, RenderBufferView(m_lightDataBuffer.get()));

View File

@@ -8,4 +8,16 @@
namespace Nz
{
FramePipelinePass::~FramePipelinePass() = default;
void FramePipelinePass::InvalidateElements()
{
}
void FramePipelinePass::RegisterMaterialInstance(const MaterialInstance& materialInstance)
{
}
void FramePipelinePass::UnregisterMaterialInstance(const MaterialInstance& materialInstance)
{
}
}

View File

@@ -5,9 +5,13 @@
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Core/AppFilesystemComponent.hpp>
#include <Nazara/Core/CommandLineParameters.hpp>
#include <Nazara/Graphics/DepthPipelinePass.hpp>
#include <Nazara/Graphics/ForwardPipelinePass.hpp>
#include <Nazara/Graphics/GuillotineTextureAtlas.hpp>
#include <Nazara/Graphics/MaterialInstance.hpp>
#include <Nazara/Graphics/MaterialPipeline.hpp>
#include <Nazara/Graphics/PipelinePassList.hpp>
#include <Nazara/Graphics/PostProcessPipelinePass.hpp>
#include <Nazara/Graphics/PredefinedMaterials.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Graphics/Formats/TextureLoader.hpp>
@@ -148,6 +152,8 @@ namespace Nz
MaterialPipeline::Initialize();
BuildDefaultMaterials();
RegisterPipelinePasses();
BuildDefaultPipelinePasses();
Font::SetDefaultAtlas(std::make_shared<GuillotineTextureAtlas>(*m_renderDevice));
@@ -364,6 +370,43 @@ namespace Nz
}
}
void Graphics::BuildDefaultPipelinePasses()
{
m_defaultPipelinePasses = std::make_shared<PipelinePassList>();
// Forward pass
std::size_t forwardColorOutput = m_defaultPipelinePasses->AddAttachment({
"Forward output",
PixelFormat::RGBA16F
});
std::size_t forwardDepthOutput = m_defaultPipelinePasses->AddAttachment({
"Depth-stencil buffer",
m_preferredDepthStencilFormat
});
std::size_t forwardPass = m_defaultPipelinePasses->AddPass("ForwardPass", m_pipelinePassRegistry.GetPassIndex("Forward"));
m_defaultPipelinePasses->SetPassOutput(forwardPass, 0, forwardColorOutput);
m_defaultPipelinePasses->SetPassDepthStencilOutput(forwardPass, forwardDepthOutput);
// Gamma correction
std::size_t gammaCorrectionOutput = m_defaultPipelinePasses->AddAttachment({
"Gamma-corrected output",
PixelFormat::RGBA8
});
ParameterList gammaCorrectionParameters;
gammaCorrectionParameters.SetParameter("Shader", "PostProcess.GammaCorrection");
std::size_t gammaCorrectionPass = m_defaultPipelinePasses->AddPass("Gamma correction", m_pipelinePassRegistry.GetPassIndex("PostProcess"), gammaCorrectionParameters);
m_defaultPipelinePasses->SetPassInput(gammaCorrectionPass, 0, forwardColorOutput);
m_defaultPipelinePasses->SetPassOutput(gammaCorrectionPass, 0, gammaCorrectionOutput);
m_defaultPipelinePasses->SetFinalOutput(gammaCorrectionOutput);
}
void Graphics::BuildDefaultTextures()
{
// Depth textures (white but with a depth format)
@@ -419,6 +462,12 @@ namespace Nz
m_materialPassRegistry.RegisterPass("DistanceShadowPass");
}
void Graphics::RegisterPipelinePasses()
{
m_pipelinePassRegistry.RegisterPass<DepthPipelinePass>("Depth");
m_pipelinePassRegistry.RegisterPass<ForwardPipelinePass>("Forward");
m_pipelinePassRegistry.RegisterPass<PostProcessPipelinePass>("PostProcess");
}
void Graphics::RegisterShaderModules()
{
m_shaderModuleResolver = std::make_shared<nzsl::FilesystemModuleResolver>();

View File

@@ -0,0 +1,67 @@
// 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/PipelinePassList.hpp>
#include <Nazara/Graphics/FrameGraph.hpp>
#include <Nazara/Graphics/FramePipelinePassRegistry.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <NazaraUtils/StackArray.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
std::vector<std::unique_ptr<FramePipelinePass>> PipelinePassList::BuildPasses(FramePipelinePass::PassData& passData) const
{
auto& passRegistry = Graphics::Instance()->GetFramePipelinePassRegistry();
std::vector<std::unique_ptr<FramePipelinePass>> passes;
for (const Pass& pass : m_passes)
passes.emplace_back(passRegistry.BuildPass(pass.implIndex, passData, pass.name, pass.parameterList));
return passes;
}
std::size_t PipelinePassList::RegisterPasses(const std::vector<std::unique_ptr<FramePipelinePass>>& passes, FrameGraph& frameGraph) const
{
NazaraAssert(m_passes.size() == passes.size(), "pass vector size doesn't match passlist size");
StackArray<std::size_t> attachmentIndices = NazaraStackArrayNoInit(std::size_t, m_attachments.size());
for (std::size_t i = 0; i < m_attachments.size(); ++i)
attachmentIndices[i] = frameGraph.AddAttachment(m_attachments[i]);
auto GetAttachmentIndex = [&](std::size_t attachmentIndex)
{
if (attachmentIndex == NoAttachment)
return NoAttachment;
assert(attachmentIndex < m_attachments.size());
return attachmentIndices[attachmentIndex];
};
for (std::size_t i = 0; i < passes.size(); ++i)
{
const Pass& passData = m_passes[i];
std::array<std::size_t, MaxPassAttachment> inputs;
for (std::size_t j = 0; j < passData.inputs.size(); ++j)
inputs[j] = GetAttachmentIndex(passData.inputs[j]);
std::array<std::size_t, MaxPassAttachment> outputs;
for (std::size_t j = 0; j < passData.outputs.size(); ++j)
outputs[j] = GetAttachmentIndex(passData.outputs[j]);
FramePipelinePass::PassInputOuputs passInputOuputs;
passInputOuputs.depthStencilInput = GetAttachmentIndex(passData.depthStencilInput);
passInputOuputs.depthStencilOutput = GetAttachmentIndex(passData.depthStencilOutput);
passInputOuputs.inputAttachments = inputs.data();
passInputOuputs.inputCount = passData.inputs.size();
passInputOuputs.outputAttachments = outputs.data();
passInputOuputs.outputCount = passData.outputs.size();
passes[i]->RegisterToFrameGraph(frameGraph, passInputOuputs);
}
return GetAttachmentIndex(m_finalOutputAttachment);
}
}

View File

@@ -83,7 +83,13 @@ namespace Nz
m_pipeline.QueueTransfer(&viewerInstance);
m_directions[i].depthPass.emplace(m_pipeline, elementRegistry, &viewer, shadowPassIndex, std::string(s_dirNames[i]));
FramePipelinePass::PassData passData = {
&viewer,
elementRegistry,
m_pipeline
};
m_directions[i].depthPass.emplace(passData, std::string(s_dirNames[i]), shadowPassIndex);
}
m_pipeline.ForEachRegisteredMaterialInstance([this](const MaterialInstance& matInstance)
@@ -106,7 +112,15 @@ namespace Nz
std::size_t visibilityHash = 5U;
const auto& visibleRenderables = m_pipeline.FrustumCull(frustum, 0xFFFFFFFF, visibilityHash);
direction.depthPass->Prepare(renderFrame, frustum, visibleRenderables, visibilityHash);
FramePipelinePass::FrameData passData = {
nullptr,
frustum,
renderFrame,
visibleRenderables,
visibilityHash
};
direction.depthPass->Prepare(passData);
}
}
@@ -144,7 +158,11 @@ namespace Nz
{
DirectionData& direction = m_directions[i];
direction.attachmentIndex = frameGraph.AddAttachmentCubeFace(m_cubeAttachmentIndex, static_cast<CubemapFace>(i));
direction.depthPass->RegisterToFrameGraph(frameGraph, direction.attachmentIndex);
FramePipelinePass::PassInputOuputs passInputOuputs;
passInputOuputs.depthStencilOutput = direction.attachmentIndex;
direction.depthPass->RegisterToFrameGraph(frameGraph, passInputOuputs);
}
}

View File

@@ -11,10 +11,11 @@
namespace Nz
{
PostProcessPipelinePass::PostProcessPipelinePass(FramePipeline& owner, std::string passName, std::string shaderName) :
PostProcessPipelinePass::PostProcessPipelinePass(PassData& passData, std::string passName, std::string shaderName) :
FramePipelinePass({}),
m_passName(std::move(passName)),
m_shader(nzsl::ShaderStageType::Fragment | nzsl::ShaderStageType::Vertex, std::move(shaderName)),
m_pipeline(owner)
m_pipeline(passData.pipeline)
{
RenderPipelineLayoutInfo layoutInfo;
layoutInfo.bindings.assign({
@@ -37,25 +38,39 @@ namespace Nz
BuildPipeline();
}
void PostProcessPipelinePass::Prepare(RenderFrame& renderFrame)
void PostProcessPipelinePass::Prepare(FrameData& frameData)
{
if (m_nextRenderPipeline)
{
if (m_renderPipeline)
renderFrame.PushForRelease(std::move(m_renderPipeline));
frameData.renderFrame.PushForRelease(std::move(m_renderPipeline));
m_renderPipeline = std::move(m_nextRenderPipeline);
m_rebuildFramePass = true;
}
}
FramePass& PostProcessPipelinePass::RegisterToFrameGraph(FrameGraph& frameGraph, std::size_t inputColorBufferIndex, std::size_t outputColorBufferIndex)
FramePass& PostProcessPipelinePass::RegisterToFrameGraph(FrameGraph& frameGraph, const PassInputOuputs& inputOuputs)
{
if (inputOuputs.inputCount != 1)
throw std::runtime_error("one input expected");
if (inputOuputs.outputCount != 1)
throw std::runtime_error("one output expected");
if (inputOuputs.depthStencilInput != InvalidAttachmentIndex)
throw std::runtime_error("unexpected depth-stencil output");
if (inputOuputs.depthStencilOutput != InvalidAttachmentIndex)
throw std::runtime_error("unexpected depth-stencil output");
std::size_t inputColorBufferIndex = inputOuputs.inputAttachments[0];
FramePass& postProcess = frameGraph.AddPass(m_passName);
postProcess.AddInput(inputColorBufferIndex);
postProcess.AddOutput(outputColorBufferIndex);
postProcess.AddOutput(inputOuputs.outputAttachments[0]);
postProcess.SetExecutionCallback([&]()
postProcess.SetExecutionCallback([&]
{
return (m_rebuildFramePass) ? FramePassExecution::UpdateAndExecute : FramePassExecution::Execute;
});
@@ -94,6 +109,16 @@ namespace Nz
return postProcess;
}
std::string PostProcessPipelinePass::GetShaderName(const ParameterList& parameters)
{
Result<std::string, ParameterList::Error> shaderResult = parameters.GetStringParameter("Shader");
if (shaderResult.IsOk())
return std::move(shaderResult).GetValue();
// TODO: Log error if key is present but not of the right
throw std::runtime_error("PostProcessPipelinePass expect a Shader parameter");
}
void PostProcessPipelinePass::BuildPipeline()
{
std::shared_ptr<RenderDevice> renderDevice = Graphics::Instance()->GetRenderDevice();

View File

@@ -48,7 +48,13 @@ namespace Nz
std::size_t shadowPassIndex = Graphics::Instance()->GetMaterialPassRegistry().GetPassIndex("ShadowPass");
m_depthPass.emplace(m_pipeline, elementRegistry, &m_viewer, shadowPassIndex, "Spotlight shadow mapping");
FramePipelinePass::PassData passData = {
&m_viewer,
elementRegistry,
m_pipeline
};
m_depthPass.emplace(passData, "Spotlight shadow mapping", shadowPassIndex);
m_pipeline.ForEachRegisteredMaterialInstance([this](const MaterialInstance& matInstance)
{
m_depthPass->RegisterMaterialInstance(matInstance);
@@ -66,7 +72,15 @@ namespace Nz
std::size_t visibilityHash = 5U;
const auto& visibleRenderables = m_pipeline.FrustumCull(frustum, 0xFFFFFFFF, visibilityHash);
m_depthPass->Prepare(renderFrame, frustum, visibleRenderables, visibilityHash);
FramePipelinePass::FrameData passData = {
nullptr,
frustum,
renderFrame,
visibleRenderables,
visibilityHash
};
m_depthPass->Prepare(passData);
}
void SpotLightShadowData::RegisterMaterialInstance(const MaterialInstance& matInstance)
@@ -94,7 +108,10 @@ namespace Nz
shadowMapSize, shadowMapSize,
});
m_depthPass->RegisterToFrameGraph(frameGraph, m_attachmentIndex);
FramePipelinePass::PassInputOuputs passInputOuputs;
passInputOuputs.depthStencilOutput = m_attachmentIndex;
m_depthPass->RegisterToFrameGraph(frameGraph, passInputOuputs);
}
const Texture* SpotLightShadowData::RetrieveLightShadowmap(const BakedFrameGraph& bakedGraph, const AbstractViewer* /*viewer*/) const

View File

@@ -344,7 +344,7 @@ namespace Nz
CameraEntity* cameraEntity = m_cameraEntityPool.Allocate(poolIndex);
cameraEntity->poolIndex = poolIndex;
cameraEntity->entity = entity;
cameraEntity->viewerIndex = m_pipeline->RegisterViewer(&entityCamera, entityCamera.GetRenderOrder(), entityCamera.GetFramePipelineExtraPassFlags());
cameraEntity->viewerIndex = m_pipeline->RegisterViewer(&entityCamera, entityCamera.GetRenderOrder());
cameraEntity->onNodeInvalidation.Connect(entityNode.OnNodeInvalidation, [this, cameraEntity](const Node* /*node*/)
{
m_invalidatedCameraNode.insert(cameraEntity);

View File

@@ -53,7 +53,7 @@ namespace Nz
pipelineInfo.pipelineLayout = m_renderPipelineLayout;
pipelineInfo.shaderModules.push_back(std::move(debugDrawShader));
pipelineInfo.depthBuffer = true;
pipelineInfo.depthWrite = false;
pipelineInfo.depthWrite = true;
pipelineInfo.blending = true;
pipelineInfo.blend.srcColor = BlendFunc::SrcAlpha;