Oculus-VR Fork Game Engine Performance Enhancement
Updated: Jan 23, 2025
Unreal Engine provides a great amount of performance optimization features. However, some of them have limited performance benefits on Quest and other MR devices.
Meta Github Fork supports more performance optimization features by enhancing Unreal game engine specifically for Quest and other MR devices.
Enhanced LightGrid Based Dynamic Local Lights
Unreal Engine 5 (UE5) uses LightGrid, a forward+ shading technique, for dynamic local lighting. However, the current implementation of LightGrid in UE5 is performance-intensive on mobile devices, particularly on Quest.
Starting from version 72, we have optimized LightGrid by packing all light data into Uniform Buffer Objects (UBOs) instead of using shader storage buffer objects (SSBOs). This change significantly improves performance.
Note that GPU hardware has a limited size for constant buffers to hold UBO data. Consequently, there is a limit to the number of dynamic local lights that can be held by the GPU constant buffer. By default, 32 lights are supported, specified by GMaxForwardMovableLights. Reducing this number saves GPU constant buffer space for other uniform buffer data, while increasing it may reduce performance due to increased constant buffer pressure.
Note: GMaxForwardMovableLights is a hardcoded constant instead of CVar. The UE5 source code must be rebuilt if this value is changed.
Further, when there are no dynamic local lights and no reflection captures, the LightGrid pass is disabled by default, saving approximately 0.14ms of GPU time. This behavior is toggled by a CVar below.
Our performance tests show a GPU App Time improvement ranging from 3% to 22.5% compared to the stock UE5 LightGrid implementation.
This feature is enabled by default.
The following new CVars are introduced:
r.Mobile.PackLightGridLightDataToUBO.Enable (default 1)
Pack LightGrid light data to UBO.
r.Forward.NoLightGridIfNoLightOpt (default 1)
Skip LightGrid pass on mobile forward+ if no dynamic local lights or reflection captures at all.
Uniform Based Dynamic Local Lights
As discussed above, UE5’s default LightGrid-based dynamic local lights can be heavy on Quest. Even with the enhancement above, there are still cases where LightGrid shading is expensive, especially if there are not many dynamic local lights across the whole scene.
Starting from v65 of the Meta UE5 integration, an alternative implementation of dynamic point and spot lights for the mobile renderer is added. This implementation binds lights via uniforms to every lit draw call (classic forward shading) and disables the default LightGrid (Forward+ shading).
In performance tests, we measured a 10% ~ 15% performance difference in some scenes compared to LightGrid on Quest 3.
In certain cases this change may increase the amount of draw thread work. It has a hard limit of eight lights per draw call which can be changed by a CVar listed below. For cases with a small numbers of lights, shaders may be specialized with an unrolled lighting loop modifiable by CVar below.
To enable this, go to System Settings >> Rendering >> Mobile >> Enable uniform local lights support on mobile forward.
The number of lights to be unrolled in a loop. The maximum value for this CVar is 4.
r.Mobile.UniformLocalLights.MaxLights (default 8)
The maximum number of lights that can be bound to one draw call.
Note: This value cannot be set to be greater than 8. Any lights higher than 8 will be discarded in a non-sorted order. Changing this will significantly increase the number of shader permutations and PSOs.
Further, this feature NOT compatible with GPUScene.
These CVars are all ReadOnly, modifying any of them requires rebuilding the mobile shaders.
Emulated Uniform Buffers
Emulated Uniform Buffers were originally introduced in the OpenGL backend for support of low spec mobile devices in Unreal Engine. It consolidated constant buffers into a single global uniform buffer for improved shader optimization. In UE5, emulated uniform buffers were removed from the engine due to switching to the DXC compiler.
However, in some scenes, emulated uniform buffers provide a decent speedup over “real” uniform buffers. In performance tests, we measured a 5% difference in some scenes on the Quest 3.
In v65 of the UE5 integration, in Meta Github fork, Emulated Uniform Buffers are supported.
To enable this, go to System Settings >> Rendering >> VR >> Enable Emulated Uniform Buffers.
The following new CVars are introduced:
r.Vulkan.UseEmulatedUBs (default False)
Enables the emulated uniform buffers
Note: EUB is NOT compatible with GPUScene or LateLatching.
Visibility and Occlusion
Qualcomm Adreno GPUs have a hardware fast path for occlusion queries that provides a substantial improvement. This has been integrated into Meta Github fork and it enhances Unreal Engine 5.4 Hardware Occlusion Queries further.
In performance tests, we measured a 5% performance difference in some scenes compared with the default occlusion query on Quest 3.
Note: r.NeverOcclusionTestDistance is default to 2000 for Android platform which means any objects closer than 2000 cm are not sent to Occlusion Query. This might need to be carefully tuned case by case.
The following new CVars are introduced:
r.Mobile.AdrenoOcclusionMode (default 1)
Enables the Adreno occlusion path (Occlusion Culling must be enabled first).