Dynamic resolution
Updated: Jan 10, 2025
Note: The features discussed here are only supported in the Oculus-VR fork of the Github repository and are not available in the Epic Games Marketplace.
Dynamic Resolution is a feature in the Horizon OS which allows applications to automatically increase their
render scale during frames where the GPU is not fully utilized, and decrease their render scale during frames where the GPU is fully utilized.
This means that applications using Dynamic Resolution automatically strike a balance between maintaining the frame rate of their application, and rendering at an optimal resolution.
- In scenes that do not fully utilize the GPU (i.e. simple corridors), Dynamic Resolution will increase render scale, improving visual quality.
- In scenes that fully utilize the GPU (i.e. large open viewpoints, cinematic character rendering), Dynamic Resolution will decrease render scale, to the extent needed to preserve framerate.
Additionally, for Meta Quest 2 headsets and later,
enabling dynamic resolution is a prerequisite for accessing the highest GPU levels. For instance,
GPU Level 5 on the Meta Quest 3 is available if dynamic resolution is enabled.
Scenes in an application often have varying levels of complexity, making it challenging to optimize for each one. Dynamic Resolution tackles this by scaling the rendered viewport based on GPU utilization to maintain the targeted frame rate.
If the application starts dropping frames, Dynamic Resolution transitions to a lower resolution. This reduces stale frames and maintains the target frame rate in heavy GPU scenes.
If the application isn’t fully utilizing the GPU, Dynamic Resolution transitions to a higher resolution to improve image quality while maintaining the frame rate.
To avoid reallocating the eye textures every time the recommended resolution changes, the eye textures are allocated once at the maximum resolution. The application will then scale the viewport to the recommended resolution, avoiding rendering outside of the viewport.
Enabling dynamic resolution also allows Horizon OS to expose higher GPU levels to the running application. Accessing these GPU levels is contingent upon using dynamic resolution, because these higher GPU levels consume more power, and therefore generate more heat -- increasing the chance of reaching the headset’s thermal limits.
By enabling dynamic resolution, the Horizon OS is able to dynamically throttle your application’s render scale down during a thermal event, restoring thermal limits in a manner which avoids dropped frames. Since maintaining a consistent framerate is an
essential part of comfortable VR experiences, the Horizon OS only allows access to these higher GPU levels if dynamic resolution is enabled.
Before you start using Dynamic Resolution, make sure to use the latest versions of the Meta Quest operating system and our Unreal Engine integration. Here are the requirements to enable Dynamic Resolution:
- Unreal Engine integration v53 or later
On v53 releases and above of UE4 and UE5, in the OculusXR/MetaXR project settings, there will be a new Dynamic Resolution subsystem at the end of the Mobile section.
In UE5 v71 and later, you can set Pixel Density Min and Max for each device in Tools > Platforms > Device Profiles or BaseDeviceProfiles.ini. Use r.Oculus.DynamicResolution.PixelDensityMin and r.Oculus.DynamicResolution.PixelDensityMax to configure these settings.
The Enable checkbox enables the feature. Pixel Density Min and Max are the boundaries of the dynamic resolution feature, defined by a factor of the default eyebuffer resolution driven by the runtime. The resolution of the game will never go below 0.7x default eyebuffer size, or above 1.3x default eyebuffer size. This means the rendertarget allocated by UE will be 1.3x default eyebuffer size, with the viewport and scissor used to render scaling up and down.
The XR swapchain allocated by the VR runtime, and all intermediate render targets that the engine needs to create such as the depth buffer, are allocated at the maximum pixel density that was configured in the dynamic resolution configuration. This will slightly increase the application’s RAM footprint.
Changing the render resolution
By default, the render resolution is dynamically controlled on a frame-to-frame basis by the runtime, but you can also override it by manually specifying the pixel density you want. Simply setting the CVar r.Oculus.DynamicResolution.PixelDensity to a value higher than 0, between the Min and Max values, will force the engine to choose that pixel density. Setting the CVar back to 0 will return resolution control to the runtime.
The Meta XR dynamic resolution implementation is integrated in the native UE dynamic resolution system (although the OpenXR runtime is driving the resolution, not the engine). You can therefore use the standard tools to visualize which resolution you’re running at.
For example, calling stat unit will print the current resolution factor on the UE runtime HMD console.
Dynamic Resolution can be a great tool to easily optimize your application depending on the content of your scenes. It’s important to understand the tradeoffs when enabling it:
- The maximum resolution scaling factor will be used to allocate the eye buffer at startup. This means that your application will be using more memory if you specify a maximum render scaling factor higher than 1.0x.
- Setting a low minimum render scaling factor might result in quality degradation when frame rate can’t be maintained.
If you can afford the extra memory cost, it might be worth increasing the maximum scaling factor as high as possible to have a better quality image in scenes where the GPU isn’t heavily used. For the minimum resolution scaling factor, if you choose a factor that is too high, you may start dropping frames in some of the more GPU-intensive scenes. On the other hand, if your minimum scaling factor is too low, it’s possible that users notice the quality degradation when the GPU utilization goes up. It might be less visible in scenes where there is a lot of action and FX and more in lower pace sequences.
Profiling an application with Dynamic Resolution
It’s really important to disable Dynamic Resolution when profiling your application because it will have an impact on the performance of the application.
Keep in mind that Dynamic Resolution isn’t a solution to every performance problem. Dynamic Resolution lowers the resolution of your application if it is poorly optimized to maintain frame rate. In order to maintain a high resolution at the targeted frame rate, you should always use the appropriate tools to profile and optimize your application to the fullest before enabling the feature.
Finally, your application will also need to respect the requirements regarding performance, which prevents applications from running at a low resolution most of the time. You can find the details for the
corresponding VRC here.
Dynamic Foveated Rendering
It is possible to enable Dynamic Foveated Rendering (both Fixed Foveated Rendering (FFR) and Eye Tracked Foveated Rendering (ETFR)) with Dynamic Resolution. The runtime will try to increase the foveated rendering level first before starting to scale the resolution down if the GPU utilization gets too high.
Check the recommended resolution with VrApi
You can verify what the recommended runtime resolution is by looking at the VrApi logs:
Here’s an example of the output:
FPS=65/72,Prd=50ms,Tear=0,Early=12,Stale=12,Stale2/5/10/max=1/0/0/2,VSnc=0,Lat=-1,Fov=2D,CPU4/GPU=4/4,1478/525MHz,OC=FF,TA=0/0/0,SP=N/N/N,Mem=2092MHz,Free=8191MB,PLS=0,Temp=26.5C/0.0C,TW=1.93ms,App=10.28ms,GD=0.00ms,CPU&GPU=20.74ms,LCnt=3(DR72,LM3),GPU%=0.92,CPU%=0.20(W0.28),DSF=1.00,CFL=16.86/20.74,LD=1,SF=1.03
Looking at the GPU utilization (GPU%), you can see that it’s starting to get quite high. The runtime will recommend a lower scaling factor (SF) to reduce the number of stale frames (Stale) and lower the GPU pressure. SF is a multiplier factor on top of the system’s default recommended eyebuffer resolution.