Very slow PIE starts with UE 5.5

Our Project is split into several Game Feature Plugins. Not all are active by default. We noticed that PIE start times have become problematic for us.

Upon further investigation, we found that updating the state of a GFP leads to a flush async loading, and for every material encountered during that flush (many not part of the GFP that caused the flush) we get a call to UpdateAllPrimitiveSceneInfos(), which goes and re-adds all Primitives for all Scenes for two minutes.

[Image Removed]

Adding an extra FGlobalComponentRecreateRenderStateContext before the flush, and commenting in the the ref-counts on ActiveGlobalRecreateRenderStateContextCount (which were commented out in UE5.5) avoids this.

[Image Removed]

Can you provide context on why ActiveGlobalRecreateRenderStateContextCount was commented out, if this is a safe change, or what the expected setup is to avoid this cost?

Steps to Reproduce

Hey Christian,

the change that commented out the ref-counts can be viewed here on Github or CL33876145 in UE5/Main.

The description is:

Disable ActiveGlobalRecreateRenderStateContextCount (which is used to reduce the amount of times component need primitive updates on recursive calls) because it doesn't work well with the version which provides list of components to recreate causing possible crashes due to stale skin cache dataSo there seems to have been some issues specifically with skin cache data.

I’ll forward this to the graphics engineers, they should hopefully be able to give you a better assessment of the risks involved.

Best,

Sebastian

Hmm - good question. I remember adding ActiveGlobalRecreateRenderStateContextCount to improve glocal render state creation for PSO precaching during client loading and render setting changes a while back. I will have to follow up internally why it was commented out due to stale skin cache data because I don’t remember the details anymore, but I do know that a lot of this code has changed for 5.6 so it would be good to investigate this again.

But if you don’t run into any crashes with stale GPU skin cache data then I would re-enable it again for sure.

I don’t know anything about GFP but I wonder if this can be fixed at a higher level by not adding a FGlobalComponentRecreateRenderStateContext for each plugin but do it once for all as you have suggested.

Thanks for looking into this!

  • We won’t be upgrading to 5.6 until late November, but we’ll definitely re-check this once we do.
  • Meanwhile, we set all our GFP to “ACTIVE”, which means most of the assets that would be loaded during the sync flush are now loaded during UE start, where we don’t have ScenePrimitives, yet. This increases our RAM usage and UE startup slightly (1:20 -> 1:25), but reduces PIE startup significantly (4:30 -> 1:35)
  • That said, we still call AddPrimitive 1M time (down from 3M times) in another (non GFP) async flush when a number of non-GPF assets finish their async loading and trigger UpdateAllPrimitiveSceneInfos() several times in a 30s long frame. So maybe the we need to fix this at an even higher level, maybe limiting calls to UpdateAllPrimitiveSceneInfos() to once at the end of a frame (during PIE startup)?

[Image Removed]

Hi,

calls to UpdateAllPrimitiveSceneInfos() will always be expensive. Are you making these calls explicitly somewhere or is this done by the engine as a side effect.

Cheers,

Kenzo

Hi,

I am adding [mention removed]​ regarding the Niagara calls to UpdateAllPrimiveSceneInfos() to see if they are needed or not. Perhaps something can be done to make sure they are not called per system but once when done (using a FGlobalComponentRecreateRenderStateContext perhaps). Stu is still on holiday and will be back next week normally. Sorry for all the delays.

Kind regards,

Kenzo

Hello! My team has also encountered this issue in 5.4 and I’m now seeing it via a new code path as we’re updating to 5.5. I’m able to resolve it with another targeted use of FGlobalComponentRecreateRenderStateContext and by commenting out the same ActiveGlobalRecreateRenderStateContextCount logic that Christian mentioned.

Is there a chance the changes coming in 5.6 will address this issue in a way that avoids needed to use these context objects? It seems plausible to me that the scene could track a dirty flag and only update the PrimitiveSceneInfo once per frame when dirtied.

We are not calling UpdateAllPrimiveSceneInfos() ourselves.

As far as I can tell the main culprits are Niagara Systems with the built in sprite shader that check if they need to update variants (e.g. use MaskA) when they load and decide that they indeed need to update everything. Then the next one does the same…

There might be other scenarios, but when stopping at a breakpoint Niagara systems showed up frequently.

Unfortunately I am AFK (for an extended time so I cannot re-check.

Can you provide information on where these are being invoked from Niagara?

Thanks,

Stu