Description

From the body of the ticket:

We aim to do as much of the work off the game thread as possible to avoid impacting frame rate. We've recently found a crash during collection of the geometry slices from a Chaos Landscape Heightfield.

The `INavRelevantInterface` comments that `PrepareGeometryExportSync` must be called on the Game thread, and that `GatherGeometrySlice` can be called "on demand", which we thought meant it could be called on a worker thread after `PrepareGeometryExportSync` had been called on the game thread. However, it seems this doesn't work as in this case the cached heightfield data is cleared by level streaming.

Could you clarify whether this is intended to be possible? Is there anything we could do to lock the cached heightfield between the prepare call and the end of the gather call, to prevent it potentially being cleared until we have finished using it?

Steps to Reproduce

A repro project was supplied via EPS. Open the project and PIE in ReproMap.

Callstack

Game thread:
```
[External Code]
[Inline Frame] UnrealEditor-Landscape.dll!FGenericPlatformMemory::Memcpy(void *) Line 593
[Inline Frame] UnrealEditor-Landscape.dll!FMemory::Memcpy(void * Dest, const void *) Line 162
UnrealEditor-Landscape.dll!TMemoryWriterBase<TSizedDefaultAllocator<32>>::Serialize(void * Data, __int64 Num) Line 61
[Inline Frame] UnrealEditor-Landscape.dll!operator<<(FArchive & Value, unsigned char &) Line 1349
UnrealEditor-Landscape.dll!Chaos::operator<<<unsigned char,TSizedDefaultAllocator<32>>(Chaos::FChaosArchive & Ar, TArray<unsigned char,TSizedDefaultAllocator<32>> & Array) Line 389
UnrealEditor-Landscape.dll!Chaos::FHeightField::FData<unsigned short>::Serialize(Chaos::FChaosArchive & Ar) Line 786
UnrealEditor-Landscape.dll!Chaos::FHeightField::Serialize(Chaos::FChaosArchive & Ar) Line 370
UnrealEditor-Landscape.dll!Chaos::FChaosArchive::SerializePtr<Chaos::FHeightField>(Chaos::TSerializablePtr<Chaos::FHeightField> & Obj) Line 238
UnrealEditor-Landscape.dll!Chaos::FChaosArchive::SerializePtr<Chaos::FHeightField>(TRefCountPtr<Chaos::FHeightField> & Obj) Line 269
[Inline Frame] UnrealEditor-Landscape.dll!Chaos::operator<<(Chaos::FChaosArchive &) Line 434
UnrealEditor-Landscape.dll!ULandscapeHeightfieldCollisionComponent::WriteRuntimeData(const ULandscapeHeightfieldCollisionComponent::FWriteRuntimeDataParams & Params, TArray<unsigned char,TSizedDefaultAllocator<32>> & OutHeightfieldData, TArray<UPhysicalMaterial *,TSizedDefaultAllocator<32>> & InOutMaterials) Line 1181
UnrealEditor-Landscape.dll!ULandscapeHeightfieldCollisionComponent::CookCollisionData(const FName & Format, bool bUseDefaultMaterialOnly, bool bCheckDDC, TArray<unsigned char,TSizedDefaultAllocator<32>> & OutCookedData, TArray<UPhysicalMaterial *,TSizedDefaultAllocator<32>> & InOutMaterials) Line 1304
UnrealEditor-Landscape.dll!ULandscapeHeightfieldCollisionComponent::CreateCollisionObject() Line 882
UnrealEditor-Landscape.dll!ULandscapeHeightfieldCollisionComponent::OnCreatePhysicsState() Line 347
UnrealEditor-Engine.dll!UActorComponent::CreatePhysicsState(bool bAllowDeferral) Line 1767
UnrealEditor-Engine.dll!UActorComponent::ExecuteRegisterEvents(FRegisterComponentContext * Context) Line 1824
UnrealEditor-Engine.dll!UActorComponent::RegisterComponentWithWorld(UWorld * InWorld, FRegisterComponentContext * Context) Line 1481
UnrealEditor-Engine.dll!AActor::IncrementalRegisterComponents(int NumComponentsToRegister, FRegisterComponentContext * Context) Line 5597
UnrealEditor-Engine.dll!ULevel::IncrementalRegisterComponents(bool bPreRegisterComponents, int NumComponentsToUpdate, FRegisterComponentContext * Context) Line 1814
UnrealEditor-Engine.dll!ULevel::IncrementalUpdateComponents(int NumComponentsToUpdate, bool bRerunConstructionScripts, FRegisterComponentContext * Context) Line 1733
UnrealEditor-Engine.dll!UWorld::AddToWorld(ULevel * Level, const UE::Math::TTransform<double> & LevelTransform, bool bConsiderTimeLimit, FNetLevelVisibilityTransactionId TransactionId, ULevelStreaming * InOwningLevelStreaming) Line 3349
UnrealEditor-Engine.dll!ULevelStreaming::UpdateStreamingState(bool & bOutUpdateAgain, bool & bOutRedetermineTarget) Line 1048
[Inline Frame] UnrealEditor-Engine.dll!FStreamingLevelPrivateAccessor::UpdateStreamingState(ULevelStreaming *) Line 791
UnrealEditor-Engine.dll!UWorld::UpdateLevelStreaming() Line 4425
UnrealEditor-Engine.dll!UGameViewportClient::Draw(FViewport * InViewport, FCanvas * SceneCanvas) Line 1752
UnrealEditor-Engine.dll!FViewport::Draw(bool bShouldPresent) Line 1806
UnrealEditor-UnrealEd.dll!UEditorEngine::Tick(float DeltaSeconds, bool bIdleMode) Line 2404
UnrealEditor-UnrealEd.dll!UUnrealEdEngine::Tick(float DeltaSeconds, bool bIdleMode) Line 550
UnrealEditor-Win64-DebugGame.exe!FEngineLoop::Tick() Line 5877
[Inline Frame] UnrealEditor-Win64-DebugGame.exe!EngineTick() Line 69
UnrealEditor-Win64-DebugGame.exe!GuardedMain(const wchar_t * CmdLine) Line 188
UnrealEditor-Win64-DebugGame.exe!LaunchWindowsStartup(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * __formal, int nCmdShow, const wchar_t * CmdLine) Line 266
UnrealEditor-Win64-DebugGame.exe!WinMain(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * pCmdLine, int nCmdShow) Line 317
[External Code]
```

Worker thread gathering heightfield geometry (in our Mercuna Navigation plugin):
```
> UnrealEditor-Mercuna-Win64-DebugGame.dll!FMercunaGeometryExport::ExportChaosHeightFieldSlice(const FNavHeightfieldSamples & PrefetchedHeightfieldSamples, const int NumRows, const int NumCols, const UE::Math::TTransform<double> & LocalToWorld, const UE::Math::TBox<double> & SliceBox) Line 392 C++
UnrealEditor-Landscape.dll!ULandscapeHeightfieldCollisionComponent::GatherGeometrySlice(FNavigableGeometryExport & GeomExport, const UE::Math::TBox<double> & SliceBox) Line 2412 C++
UnrealEditor-Mercuna-Win64-DebugGame.dll!mercuna::MerEngineGeometryCollector::CollectComponent::__l19::<lambda_1>::operator()(mercuna::MerEngineGeometryCollector::MerUnrealTriMesh & mesh) Line 1600 C++
[External Code]
UnrealEditor-Mercuna-Win64-DebugGame.dll!mercuna::MerEngineGeometryCollector::SetupTriMesh(mercuna::MerEngineGeometryCollector::MerUnrealTriMesh & mesh) Line 1352 C++
UnrealEditor-Mercuna-Win64-DebugGame.dll!mercuna::MerEngineGeometryCollector::SetupTriMeshes(mercuna::MerPtr<mercuna::MerNavCollectedGeometry> pCollectedGeometry) Line 963 C++
UnrealEditor-Mercuna-Win64-DebugGame.dll!mercuna::MerEngineGeometryCollector::DoTask::__l5::<lambda_1>::operator()() Line 1075 C++
[External Code]
UnrealEditor-MercunaCore-Win64-DebugGame.dll!mercuna::MerJobSystem::DoScheduleJobs::__l4::<lambda_1>::operator()() Line 957 C++
[External Code]
UnrealEditor-Mercuna-Win64-DebugGame.dll!MercunaAutoDeleteAsyncTask::DoThreadedWork() Line 29 C++
[Inline Frame] UnrealEditor-Win64-DebugGame.exe!FQueuedLowLevelThreadPool::AddQueuedWork::__l2::<lambda_1>::operator()() Line 484 C++
UnrealEditor-Win64-DebugGame.exe!R<lambda_1>@?N@?$Init@V<lambda_1>@?1??AddQueuedWork@FQueuedLowLevelThreadPool@@EEAAXPEAVIQueuedWork@@W4EQueuedWorkPriority@@@Z@@FTask@LowLevelTasks@@QEAAXPEB_WW4ETaskPriority@2@$$QEAV0?1??AddQueuedWork@FQueuedLowLevelThreadPool@@EEAAXPEAVIQueuedWork@@W4EQueuedWorkPriority@@@Z@W4ETaskFlags@2@@Z@QEAAPEAV12@_N@Z(const bool bNotCanceled) Line 499 C++
[Inline Frame] UnrealEditor-Win64-DebugGame.exe!Invoke(LowLevelTasks::FTask::Init::__l13::<lambda_1> &) Line 47 C++
[Inline Frame] UnrealEditor-Win64-DebugGame.exe!LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::TTaskDelegateImpl<`LowLevelTasks::FTask::Init<`FQueuedLowLevelThreadPool::AddQueuedWork'::`2'::<lambda_1>>'::`13'::<lambda_1>,0>::Call(void *) Line 162 C++
UnrealEditor-Win64-DebugGame.exe!?CallAndMove@?$TTaskDelegateImpl@V<lambda_1>@?N@???$Init@V<lambda_1>@?1??AddQueuedWork@FQueuedLowLevelThreadPool@@EEAAXPEAVIQueuedWork@@W4EQueuedWorkPriority@@@Z@@FTask@LowLevelTasks@@QEAAXPEB_WW4ETaskPriority@3@$$QEAV1?1??AddQueuedWork@FQueuedLowLevelThreadPool@@EEAAXPEAVIQueuedWork@@W4EQueuedWorkPriority@@@Z@W4ETaskFlags@3@@Z@$0A@@?$TTaskDelegate@$$A6APEAVFTask@LowLevelTasks@@_N@Z$0DA@@LowLevelTasks@@UEAAPEAVFTask@3@AEAV23@PEAXI_N@Z(LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48> & Destination, void * InlineData, unsigned int DestInlineSize, bool <Params_0>) Line 171 C++
[Inline Frame] UnrealEditor-Core.dll!LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::CallAndMove(LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48> &) Line 308 C++
UnrealEditor-Core.dll!LowLevelTasks::FTask::ExecuteTask() Line 627 C++
UnrealEditor-Core.dll!LowLevelTasks::FScheduler::ExecuteTask(LowLevelTasks::FTask * InTask) Line 267 C++
[Inline Frame] UnrealEditor-Core.dll!LowLevelTasks::FScheduler::TryExecuteTaskFrom(LowLevelTasks::Private::FWaitEvent *) Line 457 C++
UnrealEditor-Core.dll!LowLevelTasks::FScheduler::WorkerLoop(LowLevelTasks::Private::FWaitEvent * WorkerEvent, LowLevelTasks::Private::TLocalQueueRegistry<1024,1024>::TLocalQueue * WorkerLocalQueue, unsigned int WaitCycles, bool bPermitBackgroundWork) Line 514 C++
[Inline Frame] UnrealEditor-Core.dll!LowLevelTasks::FScheduler::WorkerMain(LowLevelTasks::Private::FWaitEvent * WorkerEvent, LowLevelTasks::Private::TLocalQueueRegistry<1024,1024>::TLocalQueue * WorkerLocalQueue, unsigned int WaitCycles, bool bPermitBackgroundWork) Line 571 C++
UnrealEditor-Core.dll!LowLevelTasks::FScheduler::CreateWorker::__l2::<lambda>() Line 75 C++
[Inline Frame] UnrealEditor-Core.dll!UE::Core::Private::Function::TFunctionRefBase<UE::Core::Private::Function::TFunctionStorage<1>,void __cdecl(void)>::operator()() Line 470 C++
UnrealEditor-Core.dll!FThreadImpl::Run() Line 69 C++
UnrealEditor-Core.dll!FRunnableThreadWin::Run() Line 159 C++
UnrealEditor-Core.dll!FRunnableThreadWin::GuardedRun() Line 71 C++

Have Comments or More Details?

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

0
Login to Vote

Unresolved
ComponentUE - AI - Navigation
Affects Versions5.55.6
Target Fix5.7
CreatedJun 25, 2025
UpdatedJul 28, 2025
View Jira Issue