Description

Nanite::BuildShadingCommands() launches two asynchronous tasks:

ShadingCommands.SetupTask

ShadingCommands.BuildCommandsTask

BuildCommandsTask is responsible for modifying ShadingCommands.Commands.

However, in Nanite::DispatchBasePass(), currently only call: ShadingCommands.SetupTask.Wait();

There is no corresponding ShadingCommands.BuildCommandsTask.Wait().

And for ParallelDispatch, the "ShadeGBufferCS" is processed within the DispatchPass lambda rather than the RDG pass lambda. As a result, BuildCommandsTask may still be running at the time ShadingCommands.Commands is accessed. If this occurs before BuildCommandsTask completes, it can lead to a race condition.

Steps to Reproduce

This is a rare crash caused by a multi-thread race condition. It is difficult to reproduce or debug in a normal environment. The issue was identified through analysis of call stacks and a review of the source code.

Callstack

25) FReadOnlyMeshDrawSingleShaderBindings::SetShaderBindings() [MeshPassProcessor.cpp:251]

24) FMeshDrawShaderBindings::SetParameters() [MeshPassProcessor.cpp:1009]

23) Nanite::RecordShadingParameters() [NaniteShading.cpp:807]

22) ``Nanite::DispatchBasePass'::`35'::<lambda_2>::operator()'::`10'::<lambda_2>::operator()() [NaniteShading.cpp:1395]

21) Invoke() [Invoke.h:47]

20) UE::Tasks::Private::TExecutableTaskBase<``Nanite::DispatchBasePass'::`35'::<lambda_2>::operator()'::`10'::<lambda_2>,void,void>::ExecuteTask() [TaskPrivate.h:898]

19) UE::Tasks::Private::FTaskBase::TryExecuteTask() [TaskPrivate.h:518]

18) UE::Tasks::Private::FTaskBase::Init::__l2::<lambda_1>::operator()() [TaskPrivate.h:180]

17) LowLevelTasks::FTask::Init::__l13::<lambda_1>::operator()() [Task.h:500]

16) Invoke() [Invoke.h:47]

15) LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::TTaskDelegateImpl<`LowLevelTasks::FTask::Init<`UE::Tasks::Private::FTaskBase::Init'::`2'::<lambda_1> >'::`13'::<lambda_1>,0>::Call() [TaskDelegate.h:162]

14) LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::TTaskDelegateImpl<`LowLevelTasks::FTask::Init<`UE::Tasks::Private::FTaskBase::Init'::`2'::<lambda_1> >'::`13'::<lambda_1>,0>::CallAndMove() [TaskDelegate.h:171]

13) LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::CallAndMove() [TaskDelegate.h:309]

12) LowLevelTasks::FTask::ExecuteTask() [Task.h:628]

11) LowLevelTasks::FScheduler::ExecuteTask() [Scheduler.cpp:400]

10) LowLevelTasks::FScheduler::TryExecuteTaskFrom() [Scheduler.cpp:701]

9) LowLevelTasks::FScheduler::WorkerLoop() [Scheduler.cpp:760]

8) LowLevelTasks::FScheduler::WorkerMain() [Scheduler.cpp:819]

7) `LowLevelTasks::FScheduler::CreateWorker'::`2'::<lambda_1>::operator()() [Scheduler.cpp:220]

6) UE::Core::Private::Function::TFunctionRefBase<UE::Core::Private::Function::TFunctionStorage<1>,void __cdecl(void)>::operator()() [Function.h:414]

5) FThreadImpl::Run() [Thread.cpp:69]

4) FRunnableThreadWin::Run() [WindowsRunnableThread.cpp:159]

3) FRunnableThreadWin::GuardedRun() [WindowsRunnableThread.cpp:79]

2) BaseThreadInitThunk() [:0]

1) RtlUserThreadStart() [:0]

Have Comments or More Details?

There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-367483 in the post.

0
Login to Vote

Unresolved
CreatedFeb 25, 2026
UpdatedFeb 25, 2026
View Jira Issue