I’ve discovered an issue which is causing the Instanced Foliage Actor (maybe also some other actors that are based on instancing but I haven’t verified it, instanced foliage is 100% sure to be causing this) to heavily affect the performance (mainly on GPU) when toggling visibility of ordinary static meshes (probably for those that are in close proximity to this foliage).
I’ve discovered this since, with my team, in our game we are using a lot of spline meshes and we have developed a custom solution that is replacing the spline meshes with static meshes when they are far away from the player to reduce the draw calls and to increase performance. On UE4 this was working very well and we had no issues, but when we switched to UE5, we had massive lag when our pawn was moving and the view was changing, so we had to temporarily disable the mentioned solution for the spline meshes. I’ve recently started to investigate it and I found out that the foliage is the reason of the huge performance drop.
It looks like it has probably something to do with the changes in the GPUScene class. When the static mesh visibility is being changed, its scene info is being either removed or added and the primitive is added as a primitive to update. Those primitives are being processed in the FScene::UpdateAllPrimitiveSceneInfos, and here, inside the FScene_SwapPrimitiveSceneInfos scoped events, the swap may cause more primitives to be marked to be updates as well. If primitives related to the part of the instanced foliage will be marked this way, then during the GPU Scene Update, for the FGPUScene::UploadGeneral call it will re-upload all such instances related to the updated primitive to the GPU, and since there will be foliage instances, there will be tens of thousands or even hundreds of thousands instances that are uploaded to the GPU this way (NumInstanceDataUploads becomes very large). I’ve compared this file with version from UE 4.26.2 and instances uploading was not present there (no NumInstanceDataUploads) so it must be something new or that has been refactored. This is at least what seemed to be happening when I was debugging our game with our spline mesh optimization enabled, where the game was lagging causing frames to be rendered for so long that single frame could take more than a second(!) to render on a more complex map.
I managed to reproduce this issue (although on a smaller performance impact scale) on an empty project. I wrote a very simple script that every frame selects one mesh from array of specified meshes and toggles its visibility. I’ve placed foliage on the basic floor mesh using Foliage Editing Mode (around 70k instances), and also put around 160 actors with mesh that were selected as actors that will have their visibility toggled by this test script. I was facing the view in the opposite direction than the foliage was placed to show that this is not related to the fact of the foliage being in the view frustum. Here are the performance result:
Script enabled, foliage present:
Script disabled, foliage present:
Script enabled, foliage removed:
Script disabled, foliage removed:
As you can se, the performance drop is only here if both the script is enabled and so it is toggling a single mesh visibility every frame (the foliage is not being changed or affected and the script itself is only changing the UE’s MatPreviewMesh which are just Static Mesh Actors) and the foliage instances are present on the map. If the script is disabled or the the foliage is removed, the performance is almost the same in such cases.
Is there any way we can currently prevent this issue to happen? Maybe there is a setting or a CVar that we are missing or can change that will help with the instancing affecting the performance in a such heavy way? Has anyone else encountered this problem or managed to already fix it? Should I also report this bug via the Issue tracker or mentioning it here would be sufficient for Epic Games to notice it? I really hope that this can be fixed since even toggling visibility of a single mesh with a foliage present on a map can cause a spike on the performance and this prevents us from performing any complex operations on mesh visibility due to performance reasons, including the mentioned system for reducing spline mesh overhead and there was no such performance impact on UE4 in that case.
Thanks in advance for any suggestions.