From 78d519cb9a71ab42a506c0f5018b6d417f2bf426 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 29 Jun 2025 19:16:41 +0200 Subject: [PATCH] Fix `ConcurrentSystemLocker` to have exclusive lock as an option --- Source/Engine/Level/Scene/SceneRendering.cpp | 6 +++--- Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp | 8 +++++--- Source/Engine/Threading/ConcurrentSystemLocker.cpp | 6 +++--- Source/Engine/Threading/ConcurrentSystemLocker.h | 6 +++--- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Source/Engine/Level/Scene/SceneRendering.cpp b/Source/Engine/Level/Scene/SceneRendering.cpp index 4a88703ae..e55dbd43f 100644 --- a/Source/Engine/Level/Scene/SceneRendering.cpp +++ b/Source/Engine/Level/Scene/SceneRendering.cpp @@ -127,7 +127,7 @@ void SceneRendering::CollectPostFxVolumes(RenderContext& renderContext) void SceneRendering::Clear() { - ConcurrentSystemLocker::WriteScope lock(Locker); + ConcurrentSystemLocker::WriteScope lock(Locker, true); for (auto* listener : _listeners) { listener->OnSceneRenderingClear(this); @@ -149,7 +149,7 @@ void SceneRendering::AddActor(Actor* a, int32& key) return; PROFILE_MEM(Graphics); const int32 category = a->_drawCategory; - ConcurrentSystemLocker::WriteScope lock(Locker); + ConcurrentSystemLocker::WriteScope lock(Locker, true); auto& list = Actors[category]; if (FreeActors[category].HasItems()) { @@ -193,7 +193,7 @@ void SceneRendering::UpdateActor(Actor* a, int32& key, ISceneRenderingListener:: void SceneRendering::RemoveActor(Actor* a, int32& key) { const int32 category = a->_drawCategory; - ConcurrentSystemLocker::WriteScope lock(Locker); + ConcurrentSystemLocker::WriteScope lock(Locker, true); auto& list = Actors[category]; if (list.Count() > key) // Ignore invalid key softly (eg. list after batch clear during scene unload) { diff --git a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp index 56dd196a5..e0d227b6b 100644 --- a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp +++ b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp @@ -396,7 +396,7 @@ public: { if (GLOBAL_SDF_ACTOR_IS_STATIC(a) && ObjectTypes.Contains(a->GetTypeHandle())) { - ConcurrentSystemLocker::WriteScope lock(Locker); + ConcurrentSystemLocker::WriteScope lock(Locker, true); OnSceneRenderingDirty(a->GetBox()); } } @@ -405,7 +405,7 @@ public: { if (GLOBAL_SDF_ACTOR_IS_STATIC(a) && ObjectTypes.Contains(a->GetTypeHandle())) { - ConcurrentSystemLocker::WriteScope lock(Locker); + ConcurrentSystemLocker::WriteScope lock(Locker, true); OnSceneRenderingDirty(BoundingBox::FromSphere(prevBounds)); OnSceneRenderingDirty(a->GetBox()); } @@ -415,13 +415,14 @@ public: { if (GLOBAL_SDF_ACTOR_IS_STATIC(a) && ObjectTypes.Contains(a->GetTypeHandle())) { - ConcurrentSystemLocker::WriteScope lock(Locker); + ConcurrentSystemLocker::WriteScope lock(Locker, true); OnSceneRenderingDirty(a->GetBox()); } } void OnSceneRenderingClear(SceneRendering* scene) override { + ConcurrentSystemLocker::WriteScope lock(Locker, true); for (auto& cascade : Cascades) cascade.StaticChunks.Clear(); } @@ -719,6 +720,7 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex } sdfData.LastFrameUsed = currentFrame; PROFILE_GPU_CPU("Global SDF"); + ConcurrentSystemLocker::WriteScope lock(sdfData.Locker); // Setup options int32 resolution, cascadesCount, resolutionMip; diff --git a/Source/Engine/Threading/ConcurrentSystemLocker.cpp b/Source/Engine/Threading/ConcurrentSystemLocker.cpp index c8debb561..d936f8307 100644 --- a/Source/Engine/Threading/ConcurrentSystemLocker.cpp +++ b/Source/Engine/Threading/ConcurrentSystemLocker.cpp @@ -8,7 +8,7 @@ ConcurrentSystemLocker::ConcurrentSystemLocker() _counters[0] = _counters[1] = 0; } -void ConcurrentSystemLocker::Begin(bool write) +void ConcurrentSystemLocker::Begin(bool write, bool exclusively) { volatile int64* thisCounter = &_counters[write]; volatile int64* otherCounter = &_counters[!write]; @@ -22,8 +22,8 @@ RETRY: goto RETRY; } - // Writers have to check themselves to (one write at the same time - just like a mutex) - if (write && Platform::AtomicRead(thisCounter) != 0) + // Writers might want to check themselves for a single writer at the same time - just like a mutex + if (exclusively && Platform::AtomicRead(thisCounter) != 0) { // Someone else is doing opposite operation so wait for it's end Platform::Sleep(0); diff --git a/Source/Engine/Threading/ConcurrentSystemLocker.h b/Source/Engine/Threading/ConcurrentSystemLocker.h index dd214a308..031b7e685 100644 --- a/Source/Engine/Threading/ConcurrentSystemLocker.h +++ b/Source/Engine/Threading/ConcurrentSystemLocker.h @@ -17,7 +17,7 @@ public: NON_COPYABLE(ConcurrentSystemLocker); ConcurrentSystemLocker(); - void Begin(bool write); + void Begin(bool write, bool exclusively = false); void End(bool write); public: @@ -26,10 +26,10 @@ public: { NON_COPYABLE(Scope); - Scope(ConcurrentSystemLocker& locker) + Scope(ConcurrentSystemLocker& locker, bool exclusively = false) : _locker(locker) { - _locker.Begin(Write); + _locker.Begin(Write, exclusively); } ~Scope()