Oculus Quest supports dynamic Fixed Foveated Rendering (FFR), where the level of eye texture foveation is automatically adjusted based on GPU utilization.
FFR renders the edges of your eye textures at a lower resolution than the center. The effect lowers the fidelity of the scene in the viewer’s peripheral vision and is nearly imperceptible. This reduces the GPU load due to the reduction in pixel shading requirements. In addition, apps using FFR can increase the resolution of the eye texture, improving the image shown in the headset. Complex fragment shaders also benefit from this form of multi-resolution rendering.
With dynamic FFR, the foveation level is adjusted automatically based on the GPU utilization. Non-dynamic FFR is also available, where the foveation level must be adjusted manually, but dynamic FFR is the recommended way to use the feature most effectively, especially now that content will run on 2 headsets (Quest and Quest2) with different GPU performance baselines.
Note that unlike some other forms of foveation technologies, Oculus Quest’s fixed foveation system is not based on eye tracking. The highest-resolution pixels are “fixed” in the center of the eye texture.
A detailed look at the benefits of using FFR can be found in our Optimizing Oculus Go for Performance blog post.
Dynamic foveation adjustment is the recommended way to use FFR. Dynamic FFR can be enabled with:
vrapi_SetPropertyInt( &Java, VRAPI_DYNAMIC_FOVEATION_ENABLED, true );
Dynamic foveation is disabled by default. When dynamic foveation is enabled, the foveation level will be adjusted automatically with a maximum level set to VRAPI_FOVEATION_LEVEL
. To set this, call the following:
vrapi_SetPropertyInt( &Java, VRAPI_FOVEATION_LEVEL, level );
When calling, level
can be 0, 1, 2, 3, or 4. Foveation levels 3 (high) and level 4 (high top) are treated as the same level under dynamic foveation. Which of these two levels is chosen coincides with the VRAPI_FOVEATION_LEVEL
selection. For example, if VRAPI_FOVEATION_LEVEL
is set to level 4, dynamic foveation will vary between levels 0, 1, 2, and 4 exclusively.
Because dynamic foveation uses GPU utilization to increase or decrease foveation level, it’s fairly reactive and the level should increase before a stale frame is created in comparison to a fixed FFR level, but if increased stale frames are noticed in specific levels, dynamic FFR can be enabled and disabled in those areas. Use of dynamic FFR is highly recommended.
If developers with a dynamic FFR app want to visualize what their app looks like to see if their FFR level is too high, they can use the following setprop command:
setprop debug.oculus.foveation.dynamic 0
This command will instantly disable dynamic FFR, and the foveation level will instantly go to VRAPI_FOVEATION_LEVEL
without the need to recompile a non-dynamic FFR version of the app.
First, if you want to check if the device supports foveated rendering. Check the system property VRAPI_SYS_PROP_FOVEATION_AVAILABLE
, which will return VRAPI_TRUE
if foveated rendering is supported.
Then, to use FFR, call the following to set the degree of foveation:
vrapi_SetPropertyInt( &Java, VRAPI_FOVEATION_LEVEL, level );
When calling, level
can be 0, 1, 2, 3, or 4.
In the following images, the resolution in the center white areas is native: every pixel of the texture will be computed independently by the GPU. However, in the red areas, only 1/2 of the pixels will be calculated, 1/4 for the green areas, 1/8 for the blue areas, and 1/16 for the magenta tiles. The missing pixels will be interpolated from the calculated pixels at resolve time, when the GPU stores the result of its computation in general memory.
Low FFR (1)
Medium FFR (2)
High FFR (3)
High Top FFR (4)
You may choose to change the degree of foveation based on the scene elements. Apps or scenes with high pixel shader costs will see the most benefit from using FFR. Apps with very simple shaders may see a net performance loss from the overhead of using FFR. Proper implementation of FFR requires testing and tuning to balance visual quality and GPU performance.
Many developers simply use the high FFR setting for their entire app as a general solution for performance, which some have found to have a very noticeable impact on visuals. Here are some tips and best practices on better tuning the FFR settings in-game:
debug.oculus.foveation.level
is a system-wide FFR setting override that can be used to quickly test different FFR settings without changing/reinstalling/restarting the app, with 0 = Off, 1 = Low, 2 = Medium, 3 = High, 4 = High Top (for example, adb shell setprop debug.oculus.foveation.level 2
will set the FFR level to medium).FPS=72,Prd=45ms,Tear=0,Early=67,Stale=0,VSnc=1,Lat=1,Fov=3,CPU4/GPU=2/2,1651/414MHz,OC=FF,TA=0/0/0,SP=N/N/N,Mem=1017MHz,Free=1576MB,PSM=0,PLS=0,Temp=27.0C/0.0C,TW=2.25ms,App=5.51ms,GD=0.77ms
shows an app running at 72 fps (FPS=72), with the app’s GPU rendering time at 5.51ms (App=5.51ms), and FFR on high (Fov=3). Regardless of visuals, in this case there is more than enough room to turn the FFR level down for a general improvement in the visual quality.