Graphics: Fix issue when unregistering viewer then adding it again before resources are cleaned

This commit is contained in:
SirLynix 2024-01-14 16:01:55 +01:00
parent 5c7059c8fc
commit db83413536
4 changed files with 40 additions and 31 deletions

View File

@ -16,6 +16,7 @@
#include <NazaraUtils/FixedVector.hpp>
#include <NazaraUtils/SparsePtr.hpp>
#include <unordered_map>
#include <vector>
namespace Nz
{
@ -79,6 +80,7 @@ namespace Nz
};
std::size_t m_cascadeCount;
std::vector<std::unique_ptr<PerViewerData>> m_destructionQueue;
std::unordered_map<const AbstractViewer*, std::unique_ptr<PerViewerData>> m_viewerData;
ElementRendererRegistry& m_elementRegistry;
FramePipeline& m_pipeline;

View File

@ -142,12 +142,13 @@ namespace Nz
std::size_t finalColorAttachment;
std::vector<std::unique_ptr<FramePipelinePass>> passes;
FrameData frame;
PipelineViewer* viewer;
Int32 renderOrder = 0;
RenderQueueRegistry forwardRegistry;
RenderQueue<RenderElement*> forwardRenderQueue;
ShaderBindingPtr blitShaderBinding;
FrameData frame;
UInt32 renderMask;
bool pendingDestruction = false;
NazaraSlot(TransferInterface, OnTransferRequired, onTransferRequired);
@ -167,6 +168,7 @@ namespace Nz
robin_hood::unordered_set<TransferInterface*> m_transferSet;
BakedFrameGraph m_bakedFrameGraph;
Bitset<UInt64> m_activeLights;
Bitset<UInt64> m_removedLightInstances;
Bitset<UInt64> m_removedSkeletonInstances;
Bitset<UInt64> m_removedViewerInstances;
Bitset<UInt64> m_removedWorldInstances;

View File

@ -42,6 +42,11 @@ namespace Nz
void DirectionalLightShadowData::PrepareRendering(RenderResources& renderResources, const AbstractViewer* viewer)
{
// Push unregistered viewers data for release
for (auto& perViewerData : m_destructionQueue)
renderResources.PushForRelease(std::move(perViewerData));
m_destructionQueue.clear();
assert(viewer);
PerViewerData& viewerData = *Retrieve(m_viewerData, viewer);
@ -304,7 +309,11 @@ namespace Nz
void DirectionalLightShadowData::UnregisterViewer(const AbstractViewer* viewer)
{
m_viewerData.erase(viewer);
auto it = m_viewerData.find(viewer);
assert(it != m_viewerData.end());
m_destructionQueue.push_back(std::move(it->second));
m_viewerData.erase(it);
}
template<typename F>

View File

@ -115,7 +115,7 @@ namespace Nz
if (viewerData.pendingDestruction)
continue;
if ((viewerData.viewer->GetRenderMask() & lightData->renderMask) != 0)
if ((viewerData.renderMask & lightData->renderMask) != 0)
lightData->shadowData->RegisterViewer(viewerData.viewer);
}
}
@ -140,7 +140,7 @@ namespace Nz
if (viewerData.pendingDestruction)
continue;
if ((viewerData.viewer->GetRenderMask() & lightData->renderMask) != 0)
if ((viewerData.renderMask & lightData->renderMask) != 0)
lightData->shadowData->RegisterViewer(viewerData.viewer);
}
}
@ -170,9 +170,7 @@ namespace Nz
if (viewerData.pendingDestruction)
continue;
UInt32 viewerRenderMask = viewerData.viewer->GetRenderMask();
if (viewerRenderMask & renderMask)
if (viewerData.renderMask & renderMask)
{
for (auto& passPtr : viewerData.passes)
{
@ -280,11 +278,11 @@ namespace Nz
m_transferSet.insert(&viewerInstance->GetViewerInstance());
UInt32 renderMask = viewerInstance->GetRenderMask();
viewerData.renderMask = viewerInstance->GetRenderMask();
for (std::size_t i : m_shadowCastingLights.IterBits())
{
LightData* lightData = m_lightPool.RetrieveFromIndex(i);
if (lightData->shadowData->IsPerViewer() && (renderMask & lightData->renderMask) != 0)
if (lightData->shadowData->IsPerViewer() && (viewerData.renderMask & lightData->renderMask) != 0)
lightData->shadowData->RegisterViewer(viewerInstance);
}
@ -332,9 +330,15 @@ namespace Nz
void ForwardFramePipeline::Render(RenderResources& renderResources)
{
Graphics* graphics = Graphics::Instance();
// Destroy instances at the end of the frame
for (std::size_t lightIndex : m_removedLightInstances.IterBits())
{
renderResources.PushForRelease(std::move(*m_lightPool.RetrieveFromIndex(lightIndex)));
m_lightPool.Free(lightIndex);
}
m_removedLightInstances.Clear();
for (std::size_t skeletonInstanceIndex : m_removedSkeletonInstances.IterBits())
{
renderResources.PushForRelease(std::move(*m_skeletonInstances.RetrieveFromIndex(skeletonInstanceIndex)));
@ -344,7 +348,8 @@ namespace Nz
for (std::size_t viewerIndex : m_removedViewerInstances.IterBits())
{
renderResources.PushForRelease(std::move(*m_viewerPool.RetrieveFromIndex(viewerIndex)));
auto& viewerData = *m_viewerPool.RetrieveFromIndex(viewerIndex);
renderResources.PushForRelease(std::move(viewerData));
m_viewerPool.Free(viewerIndex);
}
m_removedViewerInstances.Clear();
@ -385,8 +390,6 @@ namespace Nz
m_activeLights.Clear();
for (ViewerData* viewerData : m_orderedViewers)
{
UInt32 renderMask = viewerData->viewer->GetRenderMask();
// Extract frustum from viewproj matrix
const Matrix4f& viewProjMatrix = viewerData->viewer->GetViewerInstance().GetViewProjMatrix();
viewerData->frame.frustum = Frustumf::Extract(viewProjMatrix);
@ -397,7 +400,7 @@ namespace Nz
const LightData& lightData = *it;
std::size_t lightIndex = it.GetIndex();
if ((lightData.renderMask & renderMask) == 0)
if ((lightData.renderMask & viewerData->renderMask) == 0)
continue;
m_activeLights.UnboundedSet(lightIndex);
@ -418,19 +421,17 @@ namespace Nz
// Viewer handling (second pass)
for (ViewerData* viewerData : m_orderedViewers)
{
UInt32 renderMask = viewerData->viewer->GetRenderMask();
// Per-viewer shadow map handling
for (std::size_t lightIndex : viewerData->frame.visibleLights.IterBits())
{
LightData* lightData = m_lightPool.RetrieveFromIndex(lightIndex);
if (lightData->shadowData && lightData->shadowData->IsPerViewer() && (renderMask & lightData->renderMask) != 0)
if (lightData->shadowData && lightData->shadowData->IsPerViewer() && (viewerData->renderMask & lightData->renderMask) != 0)
lightData->shadowData->PrepareRendering(renderResources, viewerData->viewer);
}
// Frustum culling
std::size_t visibilityHash = 5;
const auto& visibleRenderables = FrustumCull(viewerData->frame.frustum, renderMask, visibilityHash);
const auto& visibleRenderables = FrustumCull(viewerData->frame.frustum, viewerData->renderMask, visibilityHash);
FramePipelinePass::FrameData passData = {
&viewerData->frame.visibleLights,
@ -472,7 +473,8 @@ namespace Nz
void ForwardFramePipeline::UnregisterLight(std::size_t lightIndex)
{
m_lightPool.Free(lightIndex);
m_removedLightInstances.UnboundedSet(lightIndex);
if (m_shadowCastingLights.UnboundedTest(lightIndex))
{
m_shadowCastingLights.Reset(lightIndex);
@ -517,11 +519,10 @@ namespace Nz
auto& viewerData = *m_viewerPool.RetrieveFromIndex(viewerIndex);
viewerData.pendingDestruction = true;
UInt32 renderMask = viewerData.viewer->GetRenderMask();
for (std::size_t i : m_shadowCastingLights.IterBits())
{
LightData* lightData = m_lightPool.RetrieveFromIndex(i);
if (lightData->shadowData->IsPerViewer() && (renderMask & lightData->renderMask) != 0)
if (lightData->shadowData->IsPerViewer() && (viewerData.renderMask & lightData->renderMask) != 0)
lightData->shadowData->UnregisterViewer(viewerData.viewer);
}
@ -559,9 +560,7 @@ namespace Nz
if (viewerData.pendingDestruction)
continue;
UInt32 viewerRenderMask = viewerData.viewer->GetRenderMask();
if (viewerRenderMask & renderableData->renderMask)
if (viewerData.renderMask & renderableData->renderMask)
{
for (auto& passPtr : viewerData.passes)
{
@ -583,9 +582,7 @@ namespace Nz
if (viewerData.pendingDestruction)
continue;
UInt32 viewerRenderMask = viewerData.viewer->GetRenderMask();
if (viewerRenderMask & renderableData->renderMask)
if (viewerData.renderMask & renderableData->renderMask)
{
for (auto& passPtr : viewerData.passes)
{
@ -661,11 +658,10 @@ namespace Nz
for (ViewerData* viewerData : viewers)
{
UInt32 renderMask = viewerData->viewer->GetRenderMask();
for (std::size_t i : m_shadowCastingLights.IterBits())
{
LightData* lightData = m_lightPool.RetrieveFromIndex(i);
if (lightData->shadowData->IsPerViewer() && (renderMask & lightData->renderMask) != 0)
if (lightData->shadowData->IsPerViewer() && (viewerData->renderMask & lightData->renderMask) != 0)
lightData->shadowData->RegisterToFrameGraph(frameGraph, viewerData->viewer);
}
@ -681,7 +677,7 @@ namespace Nz
for (std::size_t i : m_shadowCastingLights.IterBits())
{
LightData* lightData = m_lightPool.RetrieveFromIndex(i);
if ((renderMask & lightData->renderMask) != 0)
if ((viewerData->renderMask & lightData->renderMask) != 0)
lightData->shadowData->RegisterPassInputs(framePass, (lightData->shadowData->IsPerViewer()) ? viewerData->viewer : nullptr);
}
}