FMaterialRenderProxy::UpdateDeferredCachedUniformExpressions Crash, Android

Hi! We’ve encountered another render-related crash on all Android devices besides the one I’ve reported recently here: [Content removed]

libUnreal +0x15265a9c const::lambda::operator() (MaterialRenderProxy.cpp:781)
libUnreal +0x15265a9c UMaterialInterface::IterateOverActiveFeatureLevels<T> (MaterialInterface.h:1142)
libUnreal +0x15265a9c FMaterialRenderProxy::UpdateDeferredCachedUniformExpressions::lambda::operator() (MaterialRenderProxy.cpp:778)
libUnreal +0x15264700 FMaterialRenderProxy::UpdateDeferredCachedUniformExpressions (MaterialRenderProxy.cpp:805)
libUnreal +0x12c10078 FScene::Update (RendererScene.cpp:5503)
libUnreal +0x12ca768c FSceneRenderer::OnRenderBegin (SceneRendering.cpp:4063)
libUnreal +0x12884280 FMobileSceneRenderer::Render (MobileShadingRenderer.cpp:953)
libUnreal +0x12d18a6c RenderViewFamilies_RenderThread (SceneRendering.cpp:5442)
libUnreal +0x12d18a6c FRendererModule::BeginRenderingViewFamilies::lambda::operator() (SceneRendering.cpp:5745)
libUnreal +0x12d1aaf0 TEnqueueUniqueRenderCommandType<T>::DoTask (RenderingThread.h:235)
libUnreal +0x12d1aaf0 TGraphTask<T>::ExecuteTask (TaskGraphInterfaces.h:634)
libUnreal +0x0eb21e70 UE::Tasks::Private::FTaskBase::TryExecuteTask (TaskPrivate.h:504)
libUnreal +0x0eb2c1fc FBaseGraphTask::Execute (TaskGraphInterfaces.h:482)
libUnreal +0x0eb2c1fc FNamedTaskThread::ProcessTasksNamedThread (TaskGraph.cpp:779)
libUnreal +0x0eb2b0d0 FNamedTaskThread::ProcessTasksUntilQuit (TaskGraph.cpp:667)
libUnreal +0x10a8959c RenderingThreadMain (RenderingThread.cpp:317)
libUnreal +0x10ade864 FRenderingThread::Run (RenderingThread.cpp:468)
libUnreal +0x0ed13828 FRunnableThreadPThread::Run (PThreadRunnableThread.cpp:25)
libUnreal +0x0eb26038 FRunnableThreadPThread::_ThreadProc (PThreadRunnableThread.h:187)
libc +0x0006f114 <unknown> 
libc +0x00061230 <unknown>

It’s related to MaterialRenderProxy andunfortunately I don’t have a reproduction on a clean sample 5.5 project, but in our game it happens after we go to battle and open a specific screen in the menu afterwards (both battle and the screen in the menu have a couple of same objects with the same materials and that’s the only clue I have for now).

Unfortunately, as I’ve mentioned in the task mentioned above, I cannot properly debug Android builds and the only way to keep getting more info is adding logs to the engine code and keep crashing the game.

Interestingly, I’ve noticed this log in the original engine code and this comment from you which refers to some bug with a deleted render proxy, which is likely the thing that we’ve started encountering while upgrading to 5.5.

Unfortunately, with such an insufficient amount of information, I would like to ask you for help in investigating this crash as you might be aware of something related (and also in solving debugging issue on Android, which would be invaluably useful in investigations of issues like this further).

Best regards,

Daniil Yaskevich.

UPD: I’ve managed to find out the reason of debugger issues - it’s the android device itself, I’ve switched to another one and it’s all ok, gonna investigate with this further.

Best regards,

Daniil.

Thanks for the update Daniil, let us know if you have more information.

Best regards.

Hi!

I’ve got an update on this issue: the cause of it is the difference between FDefaultMaterialInstance and FMaterialInstanceResource, the latter has overrides for StartCacheUniformExpressions and FinishCacheUniformExpressions and there’s logics processing cancelation (CancelCacheUniformExpressions) in UMaterialInstance::BeginDestroy related to this overrides, and in the meanwhile even though the classes are very similar, FDefaultMaterialInstance (in pair with UMaterial) does not have such logics so we can get a crash in MaterialRenderProxy::UpdateDeferredCachedUniformExpressions when we end up processing UniformExpressions set when it contains a dead element which has not been removed from it in the cancel function.

As from what I’ve found out, normally this removal from the cache requests set happens in the FMaterialRenderProxy::ReleaseRHI, but for some reason it can be NOT called on object destruction because FRenderResource::ReleaseResource contains if ( !GIsCriticalError ) condition in it and the global critical error flag is set. I don’t remember exactly (and unfortunately I’ve lost the log / debug data where I had it :\) why the flag is set (if I recall correctly it’s set because some check() was triggered), but it seems that it might be set without something really critical for the ReleaseRHI method (and eventually just removing this condition and allowing the call for ReleaseRHI solves the crash).

As the solution for this I’ve just implemented the same logics with tracking the state of request in the set and it’s cancelation for the FDefaultMaterialInstance + UMaterial pair as in the FMaterialInstanceResource + UMaterialInstance pair.

Hope this is helpful and might help someone else.

Best regards,

Daniil Yaskevich.

Thank you for the update Daniil. If you wanted to share your deltas, I’d be happy to evaluate and get into mainline to reduce divergence on your end.

Best regards.

Hi, Stephane! Sorry for the late reply, I was out of the office for a while :slight_smile:

Here you go, attaching the diff here.

Best regards,

Daniil.

Thank you Daniil. The fix appears to be correct for you stream. Integration will be different on our and as the codebase has diverged a bit since 5.5.

Best regards.