From db834135362efe37f20fcaea97f1c8f631544335 Mon Sep 17 00:00:00 2001 From: SirLynix Date: Sun, 14 Jan 2024 16:01:55 +0100 Subject: [PATCH] Graphics: Fix issue when unregistering viewer then adding it again before resources are cleaned --- .../Graphics/DirectionalLightShadowData.hpp | 2 + .../Nazara/Graphics/ForwardFramePipeline.hpp | 4 +- .../Graphics/DirectionalLightShadowData.cpp | 11 +++- src/Nazara/Graphics/ForwardFramePipeline.cpp | 54 +++++++++---------- 4 files changed, 40 insertions(+), 31 deletions(-) diff --git a/include/Nazara/Graphics/DirectionalLightShadowData.hpp b/include/Nazara/Graphics/DirectionalLightShadowData.hpp index b5d1d6cf2..56f3e5f9d 100644 --- a/include/Nazara/Graphics/DirectionalLightShadowData.hpp +++ b/include/Nazara/Graphics/DirectionalLightShadowData.hpp @@ -16,6 +16,7 @@ #include #include #include +#include namespace Nz { @@ -79,6 +80,7 @@ namespace Nz }; std::size_t m_cascadeCount; + std::vector> m_destructionQueue; std::unordered_map> m_viewerData; ElementRendererRegistry& m_elementRegistry; FramePipeline& m_pipeline; diff --git a/include/Nazara/Graphics/ForwardFramePipeline.hpp b/include/Nazara/Graphics/ForwardFramePipeline.hpp index 264202866..637df1c05 100644 --- a/include/Nazara/Graphics/ForwardFramePipeline.hpp +++ b/include/Nazara/Graphics/ForwardFramePipeline.hpp @@ -142,12 +142,13 @@ namespace Nz std::size_t finalColorAttachment; std::vector> passes; + FrameData frame; PipelineViewer* viewer; Int32 renderOrder = 0; RenderQueueRegistry forwardRegistry; RenderQueue forwardRenderQueue; ShaderBindingPtr blitShaderBinding; - FrameData frame; + UInt32 renderMask; bool pendingDestruction = false; NazaraSlot(TransferInterface, OnTransferRequired, onTransferRequired); @@ -167,6 +168,7 @@ namespace Nz robin_hood::unordered_set m_transferSet; BakedFrameGraph m_bakedFrameGraph; Bitset m_activeLights; + Bitset m_removedLightInstances; Bitset m_removedSkeletonInstances; Bitset m_removedViewerInstances; Bitset m_removedWorldInstances; diff --git a/src/Nazara/Graphics/DirectionalLightShadowData.cpp b/src/Nazara/Graphics/DirectionalLightShadowData.cpp index b6af366f4..b9be59e84 100644 --- a/src/Nazara/Graphics/DirectionalLightShadowData.cpp +++ b/src/Nazara/Graphics/DirectionalLightShadowData.cpp @@ -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 diff --git a/src/Nazara/Graphics/ForwardFramePipeline.cpp b/src/Nazara/Graphics/ForwardFramePipeline.cpp index 3b10ddd11..d28920edb 100644 --- a/src/Nazara/Graphics/ForwardFramePipeline.cpp +++ b/src/Nazara/Graphics/ForwardFramePipeline.cpp @@ -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); } }