diff --git a/Source/Engine/Core/Collections/ConcurrentArray.h b/Source/Engine/Core/Collections/ConcurrentArray.h index df0ebbcb2..f22fbf4a9 100644 --- a/Source/Engine/Core/Collections/ConcurrentArray.h +++ b/Source/Engine/Core/Collections/ConcurrentArray.h @@ -299,7 +299,7 @@ public: { const int32 count = (int32)Platform::AtomicRead(&_count); const int32 capacity = (int32)Platform::AtomicRead(&_capacity); - const int32 minCapacity = count + PLATFORM_THREADS_LIMIT; // Ensure there is a room for all threads (eg. all possible threads add item at once) + const int32 minCapacity = GetMinCapacity(count); if (minCapacity > capacity) EnsureCapacity(minCapacity); auto ptr = _allocation.Get(); @@ -318,7 +318,7 @@ public: { const int32 count = (int32)Platform::AtomicRead(&_count); const int32 capacity = (int32)Platform::AtomicRead(&_capacity); - const int32 minCapacity = count + PLATFORM_THREADS_LIMIT; // Ensure there is a room for all threads (eg. all possible threads add item at once) + const int32 minCapacity = GetMinCapacity(count); if (minCapacity > capacity) EnsureCapacity(minCapacity); auto ptr = _allocation.Get(); @@ -327,4 +327,14 @@ public: ASSERT(ptr == _allocation.Get()); return index; } + +private: + FORCE_INLINE static int32 GetMinCapacity(const int32 count) + { + // Ensure there is a room for all threads (for example if all possible threads add multiple items at once) + // It's kind of UB if ConstructItems or MoveItems is short enough for other threads to append multiple items causing resize + // Thus increase the minimum slack space for smaller items (eg. int32 indices which are fast to copy) + constexpr int32 slack = PLATFORM_THREADS_LIMIT * (sizeof(T) <= 64 ? 16 : (sizeof(T) <= 512 ? 4 : 2)); + return count + slack; + } }; diff --git a/Source/Engine/Foliage/Foliage.cpp b/Source/Engine/Foliage/Foliage.cpp index 5b85ff0d3..1fa246913 100644 --- a/Source/Engine/Foliage/Foliage.cpp +++ b/Source/Engine/Foliage/Foliage.cpp @@ -1216,7 +1216,7 @@ void Foliage::Draw(RenderContextBatch& renderContextBatch) #if !FOLIAGE_USE_SINGLE_QUAD_TREE // Run async job for each foliage type const RenderView& view = renderContextBatch.GetMainContext().View; - if ((view.Pass & DrawPass::GBuffer) && !(view.Pass & (DrawPass::GlobalSDF | DrawPass::GlobalSurfaceAtlas))) + if ((view.Pass & DrawPass::GBuffer) && !(view.Pass & (DrawPass::GlobalSDF | DrawPass::GlobalSurfaceAtlas)) && renderContextBatch.EnableAsync) { // Cache data per foliage instance type for (FoliageType& type : FoliageTypes) diff --git a/Source/Engine/Graphics/RenderTask.h b/Source/Engine/Graphics/RenderTask.h index 343289d0a..92a48cf76 100644 --- a/Source/Engine/Graphics/RenderTask.h +++ b/Source/Engine/Graphics/RenderTask.h @@ -472,6 +472,11 @@ API_STRUCT(NoDefault) struct RenderContextBatch /// API_FIELD() Array> WaitLabels; + /// + /// Enables using async tasks via Job System when performing drawing. + /// + API_FIELD() bool EnableAsync = true; + RenderContextBatch() = default; RenderContextBatch(SceneRenderTask* task); RenderContextBatch(const RenderContext& context); diff --git a/Source/Engine/Level/Scene/SceneRendering.cpp b/Source/Engine/Level/Scene/SceneRendering.cpp index e36f6c49e..8b262ee61 100644 --- a/Source/Engine/Level/Scene/SceneRendering.cpp +++ b/Source/Engine/Level/Scene/SceneRendering.cpp @@ -62,7 +62,7 @@ void SceneRendering::Draw(RenderContextBatch& renderContextBatch, DrawCategory c // Draw all visual components _drawListIndex = -1; - if (_drawListSize >= 64 && category == SceneDrawAsync) + if (_drawListSize >= 64 && category == SceneDrawAsync && renderContextBatch.EnableAsync) { // Run in async via Job System Function func; diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp index 3efa812fa..29e72d369 100644 --- a/Source/Engine/Renderer/Renderer.cpp +++ b/Source/Engine/Renderer/Renderer.cpp @@ -353,7 +353,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont // Wait for async jobs to finish JobSystem::SetJobStartingOnDispatch(true); - for (const int64 label : renderContextBatch.WaitLabels) + for (const uint64 label : renderContextBatch.WaitLabels) JobSystem::Wait(label); renderContextBatch.WaitLabels.Clear();