Foliage Static Mesh LOD issue

So, I’ve been profiling our game recently and found an issue where the foliage was kind of a bottleneck since it did a lot of draw calls. After investigation, I found that this was due to a lot of my meshes having LODs that would multiply the draw calls since I would view the same mesh but at different distances thus causing the foliage to react this way.

So far so good, so I reimported my meshes with a lot of LODs, so they would now have only 1 LOD. This solved my issue, and I now have 3 to 4 time less draw calls for the foliage, performance is way improved, it’s a win.

Now, I want to build the ligthing, here is where my problem arise!

In UInstancedStaticMeshComponent::ApplyLightMapping(), there is a check to ensure we have enough place to store the lightmaps for every LODs:

// Ensure LODData has enough entries in it, free not required.
SetLODDataCount(StaticMesh->GetNumLODs(), StaticMesh->GetNumLODs());

In SetLODDataCount() it will enter this condition:

if (MaxSize < (uint32)LODData.Num())
{
	// call destructors
	LODData.RemoveAt(MaxSize, LODData.Num() - MaxSize);
}

With LODData.Num() being 3 (which was the number of LODs that mesh had before). I assume this is normal, and the code just wants to clean the LODData array. However, this seems to cause my problem. When calling FStaticMeshComponentLODInfo::CleanUp(), the editor crashes with this line:

Fatal error: [File:C:\Users\mdube\Perforce\prodperforce\Jotunn\EngineFrima\Engine\Source\Runtime\RenderCore\Private\RenderResource.cpp] [Line: 118] 
A FRenderResource was deleted without being released first!

Now, deleting that brush from the folaige actor solves this issue, but I did that for like 15 differents brushes, meaning the artist on our team would need to redo pretty much everything.

Here is the entire stack:

[2015.05.05-21.38.54:252][772]LogWindows: === Critical error: ===
Fatal error: [File:C:\Users\mdube\Perforce\prodperforce\Jotunn\EngineFrima\Engine\Source\Runtime\RenderCore\Private\RenderResource.cpp] [Line: 118] 
A FRenderResource was deleted without being released first!


KERNELBASE.dll!UnknownFunction (0x00007ffe91195bf8) + 0 bytes [UnknownFile:0]
UE4Editor-Core.dll!FOutputDeviceWindowsError::Serialize() (0x00007ffe67328364) + 0 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\runtime\core\private\windows\windowsplatformoutputdevices.cpp:95]
UE4Editor-Core.dll!FMsg::Logf__VA() (0x00007ffe671a76ef) + 0 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\runtime\core\private\misc\outputdevice.cpp:526]
UE4Editor-RenderCore.dll!FRenderResource::~FRenderResource() (0x00007ffe730491d9) + 0 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\runtime\rendercore\private\renderresource.cpp:120]
UE4Editor-Engine.dll!FColorVertexBuffer::`vector deleting destructor'() (0x00007ffe6360a74f) + 0 bytes [UnknownFile:0]
UE4Editor-Engine.dll!FStaticMeshComponentLODInfo::CleanUp() (0x00007ffe63c30c61) + 0 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\runtime\engine\private\staticmeshcomponent.cpp:1776]
UE4Editor-Engine.dll!TArray<FStaticMeshComponentLODInfo,FDefaultAllocator>::RemoveAt() (0x00007ffe63c5f59a) + 39 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\runtime\core\public\containers\array.h:1430]
UE4Editor-Engine.dll!UStaticMeshComponent::SetLODDataCount() (0x00007ffe63c664b5) + 0 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\runtime\engine\private\staticmeshrender.cpp:150]
UE4Editor-Engine.dll!UInstancedStaticMeshComponent::ApplyLightMapping() (0x00007ffe6381813e) + 0 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\runtime\engine\private\instancedstaticmesh.cpp:1074]
UE4Editor-Engine.dll!FStaticLightingTextureMapping_InstancedStaticMesh::Apply() (0x00007ffe63816e44) + 0 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\runtime\engine\private\instancedstaticmesh.h:661]
UE4Editor-UnrealEd.dll!FLightmassProcessor::ProcessMapping() (0x00007ffe62876920) + 0 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\editor\unrealed\private\lightmass\lightmass.cpp:3666]
UE4Editor-UnrealEd.dll!FLightmassProcessor::ProcessAvailableMappings() (0x00007ffe62876690) + 0 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\editor\unrealed\private\lightmass\lightmass.cpp:3703]
UE4Editor-UnrealEd.dll!FLightmassProcessor::CompleteRun() (0x00007ffe62848a60) + 8 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\editor\unrealed\private\lightmass\lightmass.cpp:2871]
UE4Editor-UnrealEd.dll!FStaticLightingSystem::FinishLightmassProcess() (0x00007ffe628d2df3) + 12 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\editor\unrealed\private\staticlightingsystem\staticlightingsystem.cpp:1908]
UE4Editor-UnrealEd.dll!FStaticLightingManager::ProcessLightingData() (0x00007ffe628fb26a) + 8 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\editor\unrealed\private\staticlightingsystem\staticlightingsystem.cpp:118]
UE4Editor-UnrealEd.dll!FStaticLightingSystem::UpdateLightingBuild() (0x00007ffe62921608) + 0 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\editor\unrealed\private\staticlightingsystem\staticlightingsystem.cpp:2056]
UE4Editor-UnrealEd.dll!UEditorEngine::UpdateBuildLighting() (0x00007ffe62920a04) + 85 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\editor\unrealed\private\staticlightingsystem\staticlightingsystem.cpp:2150]
UE4Editor-UnrealEd.dll!UUnrealEdEngine::Tick() (0x00007ffe624b8761) + 0 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\editor\unrealed\private\unrealedengine.cpp:388]
UE4Editor.exe!FEngineLoop::Tick() (0x00007ff70bb60ce3) + 0 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\runtime\launch\private\launchengineloop.cpp:2257]
UE4Editor.exe!GuardedMain() (0x00007ff70bb538bc) + 0 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\runtime\launch\private\launch.cpp:142]
UE4Editor.exe!GuardedMainWrapper() (0x00007ff70bb5392a) + 5 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\runtime\launch\private\windows\launchwindows.cpp:126]
UE4Editor.exe!WinMain() (0x00007ff70bb62c89) + 17 bytes [c:\users\mdube\perforce\prodperforce\jotunn\enginefrima\engine\source\runtime\launch\private\windows\launchwindows.cpp:202]
UE4Editor.exe!__tmainCRTStartup() (0x00007ff70bb63c59) + 21 bytes [f:\dd\vctools\crt\crtw32\dllstuff\crtexe.c:618]
KERNEL32.DLL!UnknownFunction (0x00007ffe939b16ad) + 0 bytes [UnknownFile:0]
ntdll.dll!UnknownFunction (0x00007ffe93d45444) + 0 bytes [UnknownFile:0]
ntdll.dll!UnknownFunction (0x00007ffe93d45444) + 0 bytes [UnknownFile:0]

Is there a workaround so that my team does not need to redo everything, or a fix for that issue? We are runnning on a custom 4.7.1 version of the engine.

Thanks in advance!

Mick

Hey Dubé -

Just so I understand, the crash occurs when LODData.Num() returns 1 (after your fixes) rather than returning 3 (before changes), correct? Where is the call to FStaticMeshComponentLODInfo::CleanUp() being made? Also, what is the MaxSize variable set to? Additionally, could you include the log files from the crash inside the Saved->Logs folder of the project?

Cheers

Hi , I had maybe 20 different brushes where I removed LODs from the static meshes after the foliage was painted.

I finally found out that 2 out them were crashing when attempting to clean their LODData arrays.

So, to be clear, the crash occurs when trying to clean the LODData array, that is when LODData.Num() > StaticMesh->GetNumLODs(). So in the case of the problematic component, LODData.Num() was 3 and StaticMesh->GetNumLODs() was 1.

Step by step of what happens:

  1. Have a static mesh with more than 1 LOD
  2. Use this static mesh in foliage
  3. Build the lighting
  4. Reimport said static mesh to have only one LOD
  5. Rebuild the lighting
  6. When the lighting is done, the engine will call UInstancedStaticMeshComponent::ApplyLightMapping()
  7. It will detect that LODData.Num() > StaticMesh->GetNumLODs()
  8. It will do LODData.RemoveAt(MaxSize, LODData.Num() - MaxSize);
  9. Upon doing this, since LODData is an array of FStaticMeshComponentLODInfo it will delete 2 elements and call FStaticMeshComponentLODInfo destructor.
  10. In FStaticMeshComponentLODInfo destructor you have the CleanUp call.
  11. CleanUp does this : delete OverrideVertexColors;
  12. CRASH!

Interesting note I just found which I believe is the source of the problem:

/** Destructor */
FStaticMeshComponentLODInfo::~FStaticMeshComponentLODInfo()
{
	// Note: OverrideVertexColors had BeginReleaseResource called in UStaticMeshComponent::BeginDestroy, 
	// And waits on a fence for that command to complete in UStaticMeshComponent::IsReadyForFinishDestroy,
	// So we know it is safe to delete OverrideVertexColors here (RT can't be referencing it anymore)
	CleanUp();
}

Obviously, the “we know it’s safe to to delete OverrideVertexColors here” is wrong in that case.

I don’t have the logs anymore, but hopefully I have all the repro steps in here!

Mick

Looks like the issue was found and solved here : What is causing this crash when encoding lightmaps? - Programming & Scripting - Unreal Engine Forums