From 2e10d776e9bc4e80323a3bb82f62337e21b36971 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 19 Jun 2025 14:04:06 +0200 Subject: [PATCH] Optimize updating actor rendering entry with better thread locking that support async writes on actor update --- Source/Engine/Level/Scene/SceneRendering.cpp | 14 +++++++------- Source/Engine/Level/Scene/SceneRendering.h | 4 ++-- Source/Engine/Threading/ConcurrentSystemLocker.cpp | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Source/Engine/Level/Scene/SceneRendering.cpp b/Source/Engine/Level/Scene/SceneRendering.cpp index fe2bc310f..4a88703ae 100644 --- a/Source/Engine/Level/Scene/SceneRendering.cpp +++ b/Source/Engine/Level/Scene/SceneRendering.cpp @@ -43,7 +43,7 @@ FORCE_INLINE bool FrustumsListCull(const BoundingSphere& bounds, const ArrayScenes.Add(this); // Add additional lock during scene rendering (prevents any Actors cache modifications on content streaming threads - eg. when model residency changes) - Locker.Lock(); + Locker.Begin(false); } else if (category == PostRender) { // Release additional lock - Locker.Unlock(); + Locker.End(false); } auto& view = renderContextBatch.GetMainContext().View; auto& list = Actors[(int32)category]; @@ -127,7 +127,7 @@ void SceneRendering::CollectPostFxVolumes(RenderContext& renderContext) void SceneRendering::Clear() { - ScopeLock lock(Locker); + ConcurrentSystemLocker::WriteScope lock(Locker); 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; - ScopeLock lock(Locker); + ConcurrentSystemLocker::WriteScope lock(Locker); auto& list = Actors[category]; if (FreeActors[category].HasItems()) { @@ -174,7 +174,7 @@ void SceneRendering::AddActor(Actor* a, int32& key) void SceneRendering::UpdateActor(Actor* a, int32& key, ISceneRenderingListener::UpdateFlags flags) { const int32 category = a->_drawCategory; - ScopeLock lock(Locker); + ConcurrentSystemLocker::ReadScope lock(Locker); // Read-access only as list doesn't get resized (like Add/Remove do) so allow updating actors from different threads at once auto& list = Actors[category]; if (list.Count() <= key) // Ignore invalid key softly return; @@ -193,7 +193,7 @@ void SceneRendering::UpdateActor(Actor* a, int32& key, ISceneRenderingListener:: void SceneRendering::RemoveActor(Actor* a, int32& key) { const int32 category = a->_drawCategory; - ScopeLock lock(Locker); + ConcurrentSystemLocker::WriteScope lock(Locker); 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/Level/Scene/SceneRendering.h b/Source/Engine/Level/Scene/SceneRendering.h index b24dcdfa9..59f997f6b 100644 --- a/Source/Engine/Level/Scene/SceneRendering.h +++ b/Source/Engine/Level/Scene/SceneRendering.h @@ -7,7 +7,7 @@ #include "Engine/Core/Math/BoundingSphere.h" #include "Engine/Core/Math/BoundingFrustum.h" #include "Engine/Level/Actor.h" -#include "Engine/Platform/CriticalSection.h" +#include "Engine/Threading/ConcurrentSystemLocker.h" class SceneRenderTask; class SceneRendering; @@ -102,7 +102,7 @@ public: Array Actors[MAX]; Array FreeActors[MAX]; Array PostFxProviders; - CriticalSection Locker; + ConcurrentSystemLocker Locker; private: #if USE_EDITOR diff --git a/Source/Engine/Threading/ConcurrentSystemLocker.cpp b/Source/Engine/Threading/ConcurrentSystemLocker.cpp index c8569b119..f8eab96d9 100644 --- a/Source/Engine/Threading/ConcurrentSystemLocker.cpp +++ b/Source/Engine/Threading/ConcurrentSystemLocker.cpp @@ -18,7 +18,7 @@ RETRY: { // Someone else is doing opposite operation so wait for it's end // TODO: use ConditionVariable+CriticalSection to prevent active-waiting - Platform::Sleep(1); + Platform::Sleep(0); goto RETRY; }