Crash in BuildSRVTable, in both AMD/Nvidia drivers from CDevice::CopyDescriptors

During normal gameplay, shipping and test configurations, we’re encountering a moderately rare crash. See provided callstack. We’ve integrated RHI parallel submission CL backported from 5.5, and related fixes. So far I’ve been unable to repro locally in any configuration, and ASAN report is clean. I anticipate a race condition of some sort.

00007ffd02fba4c1()
00007ffd02fb9a2b()
CDevice::CopyDescriptors(unsigned int,struct D3D12_CPU_DESCRIPTOR_HANDLE const *,unsigned int const *,unsigned int,struct D3D12_CPU_DESCRIPTOR_HANDLE const *,unsigned int const *,enum D3D12_DESCRIPTOR_HEAP_TYPE)
FD3D12DescriptorCache::BuildSRVTable(EShaderFrequency, const FD3D12RootSignature *, FD3D12ShaderResourceViewCache &, const unsigned __int64 &, unsigned int, unsigned int &)
FD3D12StateCache::ApplyResources(const FD3D12RootSignature * const, unsigned int, unsigned int)
FD3D12StateCache::ApplyState(ERHIPipeline, ED3D12PipelineType)
FD3D12CommandContext::SetupDispatch(unsigned int, unsigned int, unsigned int)
FD3D12CommandContext::RHIDispatchComputeShader(unsigned int, unsigned int, unsigned int)
FRHICommandListBase::Execute()
FRHICommandListExecutor::FTranslateState::Translate(FRHICommandListBase *)
[Inline Frame] FCpuProfilerTrace::FEventScope::{ctor}(unsigned int &, const char *, bool, const char *, unsigned int)
FRHICommandListExecutor::FSubmitState::Dispatch::__l13::<lambda>()
[Inline Frame] UE::Core::Private::Function::TFunctionRefBase<UE::Core::Private::Function::TFunctionStorage<0>,void __cdecl(void)>::operator()()
FRHICommandListExecutor::FTaskPipe::Execute(FRHICommandListExecutor::FTaskPipe::FTask *, const TRefCountPtr<FGraphEvent> &)
[Inline Frame] UE::Core::Private::Function::TFunctionRefBase<UE::Core::Private::Function::TFunctionStorage<1>,void __cdecl(enum ENamedThreads::Type,TRefCountPtr<FGraphEvent> const &)>::operator()(ENamedThreads::Type, const TRefCountPtr<FGraphEvent> &)
[Inline Frame] TFunctionGraphTaskImpl<void __cdecl(enum ENamedThreads::Type,TRefCountPtr<FGraphEvent> const &),0>::DoTaskImpl(TUniqueFunction<void __cdecl(enum ENamedThreads::Type,TRefCountPtr<FGraphEvent> const &)> &, ENamedThreads::Type, const TRefCountPtr<FGraphEvent> &)
[Inline Frame] TFunctionGraphTaskImpl<void __cdecl(enum ENamedThreads::Type,TRefCountPtr<FGraphEvent> const &),0>::DoTask(ENamedThreads::Type, const TRefCountPtr<FGraphEvent> &)
TGraphTask<TFunctionGraphTaskImpl<void __cdecl(enum ENamedThreads::Type,TRefCountPtr<FGraphEvent> const &),0>>::ExecuteTask(TArray<FBaseGraphTask *,TSizedDefaultAllocator<32>> &, ENamedThreads::Type, bool)
[Inline Frame] FBaseGraphTask::Execute(TArray<FBaseGraphTask *,TSizedDefaultAllocator<32>> &, ENamedThreads::Type, bool)
[Inline Frame] FTaskGraphCompatibilityImplementation::QueueTask::__l5::<lambda>()
LowLevelTasks::FTask::Init::__l5::<lambda>(const bool)
[Inline Frame] Invoke(LowLevelTasks::FTask::Init::__l5::void <lambda>(const TArray<FString,TSizedDefaultAllocator<32>> &, UWorld *, FOutputDevice &) &, bool &)
[Inline Frame] LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::TTaskDelegateImpl<`LowLevelTasks::FTask::Init<`FTaskGraphCompatibilityImplementation::QueueTask'::`5'::void <lambda>(const TArray<FString,TSizedDefaultAllocator<32>> &, UWorld *, FOutputDevice &)>'::`5'::void <lambda>(const TArray<FString,TSizedDefaultAllocator<32>> &, UWorld *, FOutputDevice &),0>::Call(void *, bool)
LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::TTaskDelegateImpl<`LowLevelTasks::FTask::Init<`FTaskGraphCompatibilityImplementation::QueueTask'::`5'::void <lambda>(const TArray<FString,TSizedDefaultAllocator<32>> &, UWorld *, FOutputDevice &)>'::`5'::void <lambda>(const TArray<FString,TSizedDefaultAllocator<32>> &, UWorld *, FOutputDevice &),0>::CallAndMove(LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48> &, void *, unsigned int, bool)
[Inline Frame] LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::CallAndMove(LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48> &, bool)
LowLevelTasks::FTask::ExecuteTask()
[Inline Frame] FCpuProfilerTrace::FEventScope::{ctor}(unsigned int &, const char *, bool, const char *, unsigned int)
LowLevelTasks::FScheduler::ExecuteTask(LowLevelTasks::FTask *)
[Inline Frame] LowLevelTasks::FScheduler::TryExecuteTaskFrom(LowLevelTasks::Private::FWaitEvent *, LowLevelTasks::Private::TLocalQueueRegistry<1024>::TLocalQueue *, LowLevelTasks::Private::FOutOfWork &, bool)

Searching our team editor logs for similar crashes, I see a few in this area. What is a reasonable strategy tracking this down:

[2025.09.22-16.17.54:661][262]LogWindows: Error: appError called: Assertion failed: SrcDescriptors[SlotIndex].ptr != 0 [File:D:\Phoenix\Engine\Source\Runtime\D3D12RHI\Private\D3D12DescriptorCache.cpp] [Line: 504]

Steps to Reproduce

Hello,

We saw a similar crash issue in 5.5 when there was a race condition deleting RHI resources, have you backported this fix?

CL#33039917 Remove “nested” RHI resource deletion to fix race condition between the render and RHI threads.

What is a reasonable strategy tracking this down:

In the past we encountered a crash in this area and uncovered the issue by reproing it with -rdgimmediate -forcerhibypass -norhithread and also with -rhivalidation. The issue was due to a visualization mode, and the fix was committed in

CL#34286515 Fixes crash when previewing skeletal mesh normals.

Without a repro it’s going to be more difficult, but -rhivalidation can sometimes provide more data.

Thanks Alex, will give that CL a go and report back.

Knocking on wood, https://github.com/EpicGames/UnrealEngine/commit/84799f9f01446e893b7ef02f223f88bb13fd3e0c, appears to have addressed the crash here. Thanks again.