diff --git a/Source/Engine/Level/Scene/SceneRendering.cpp b/Source/Engine/Level/Scene/SceneRendering.cpp index fac756af8..dc3a57ea8 100644 --- a/Source/Engine/Level/Scene/SceneRendering.cpp +++ b/Source/Engine/Level/Scene/SceneRendering.cpp @@ -191,20 +191,25 @@ void SceneRendering::AddActor(Actor* a, int32& key) void SceneRendering::UpdateActor(Actor* a, int32& key, ISceneRenderingListener::UpdateFlags flags) { const int32 category = a->_drawCategory; - ScopeReadLock lock(Locker); // Read-access only as list doesn't get resized (like Add/Remove do) so allow updating actors from different threads at once + bool lock = !_isRendering || ((int32)flags & (int32)ISceneRenderingListener::AutoDelayDuringRendering) == 0; // Allow updating actors during rendering + if (lock) + Locker.ReadLock(); // 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 || key < 0) // Ignore invalid key softly - return; - auto& e = list[key]; - if (e.Actor == a) + if (list.Count() > key && key >= 0) // Ignore invalid key softly { - for (auto* listener : _listeners) - listener->OnSceneRenderingUpdateActor(a, e.Bounds, flags); - if (flags & ISceneRenderingListener::Layer) - e.LayerMask = a->GetLayerMask(); - if (flags & ISceneRenderingListener::Bounds) - e.Bounds = a->GetSphere(); + auto& e = list[key]; + if (e.Actor == a) + { + for (auto* listener : _listeners) + listener->OnSceneRenderingUpdateActor(a, e.Bounds, flags); + if (flags & ISceneRenderingListener::Layer) + e.LayerMask = a->GetLayerMask(); + if (flags & ISceneRenderingListener::Bounds) + e.Bounds = a->GetSphere(); + } } + if (lock) + Locker.ReadUnlock(); } void SceneRendering::RemoveActor(Actor* a, int32& key) diff --git a/Source/Engine/Level/Scene/SceneRendering.h b/Source/Engine/Level/Scene/SceneRendering.h index c11c94de8..25dfc63fa 100644 --- a/Source/Engine/Level/Scene/SceneRendering.h +++ b/Source/Engine/Level/Scene/SceneRendering.h @@ -55,6 +55,7 @@ public: Bounds = 2, Layer = 4, StaticFlags = 8, + AutoDelayDuringRendering = 16, // Conditionally allow updating data during rendering when writes are locked Auto = Visual | Bounds | Layer, }; @@ -68,6 +69,8 @@ public: virtual void OnSceneRenderingClear(SceneRendering* scene) = 0; }; +DECLARE_ENUM_OPERATORS(ISceneRenderingListener::UpdateFlags); + /// /// Scene rendering helper subsystem that boosts the level rendering by providing efficient objects cache and culling implementation. /// diff --git a/Source/Engine/UI/TextRender.cpp b/Source/Engine/UI/TextRender.cpp index 3a0d03c68..52132b972 100644 --- a/Source/Engine/UI/TextRender.cpp +++ b/Source/Engine/UI/TextRender.cpp @@ -352,7 +352,7 @@ void TextRender::UpdateLayout() BoundingBox::Transform(_localBox, _transform, _box); BoundingSphere::FromBox(_box, _sphere); if (_sceneRenderingKey != -1) - GetSceneRendering()->UpdateActor(this, _sceneRenderingKey); + GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Auto | ISceneRenderingListener::AutoDelayDuringRendering); } bool TextRender::HasContentLoaded() const