Variable Rate Shading in Unreal 5

Variable Rate Shading (VRS) received a boost in usability in 5.4, including a similar method to Gear 5's VRS landing in the engine.

Title VRS Image

Unreal 5.4 supports Variable Rate Shading (VRS) Tier 2, and with that, I believe it's now worth talking about.

Variable Rate Shading isn't new, nor is it new to Unreal Engine-based games. Microsoft's The Coalition shipped Gears 5 with Tier 2 VRS back in September 2019. Fast forward almost five years, and the feature now has solid support in the latest mainline Unreal release.

What is Tier 2 Variable Rate Shading?

To simplify it a bit, Tier 1 supports per-draw shading rate adjustments. This is useful, but relatively limiting. Tier 2 Variable Rate Shading provides the ability to dynamically change the shading rate of the image on an image level.

Variable-rate shading (VRS) - Win32 apps
Variable-rate shading—or coarse pixel shading—is a mechanism that lets you allocate rendering performance/power at rates that vary across your rendered image.

VRS in Unreal

Tier 2 VRS in Unreal uses a feedback-driven approach. By identifying areas with limited contrast and reducing the shading rate in those areas, the system can maintain visual fidelity while reducing pixel shader load. As a result, performance gains here are largest when the GPU is limited by pixel shader work. I'll touch more on this in a second, as my test cases were both bound on different workloads.

Unreal supports two modes of VRS: a hardware method, and a compute-shader-based method. The above video shows the hardware method. One of the issues with the hardware method, and this is doubly true for the "Valley of the Ancients" demo project.

As the above images show, the Hardware approach struggles with the geometric density of Nanite. The hardware mode is limited to a block of pixels based on hardware features. This lower granularity leads to almost no VRS kicking in on the terrain. The compute-shader-based method added in Unreal 5.4 does allow us to have some performance wins in the scene.

By default, VRS uses "Conversative" mode for things like the BasePass and the Nanite GBuffer. When Nanite is in use, the "Full" mode leads to visual artifacts on the geometry. This does limit the effectiveness of VRS, but overall, we do still get some gains. It's worth noting that this scene is particularly challenging.

A less challenging scene shows far bigger wins from VRS. This example also shows the reason that the compute-shader approach is so important for Nanite heavy scenes.

Some Approximate Numbers

My testing is very approximate here. For a real use-case, benchmarking should be performed to get proper numbers. The below image is rendering at native 3840x2160 using Temporal Super-Resolution with ScreenPercentage set to 100%. Lastly, the GPU in question is an RTX 3090 Ti power-limited to 225W. In this configuration, the 3090-Ti performs similarly to a 2080/2080-Ti in benchmarks. It does, however, retain its significant memory bandwidth advance over the Turing cards and that can show up in certain situations.

Conversative VRS Example in Valley of the Ancients
Conservative CS Preview of the Testing Scene
Mode GPU Frametime (ms) Savings (ms)
No VRS ~22.8 ---
Conservative CS ~21.9 ~0.9
Global 2x2 Rate ~21.1 ~1.7
For Nanite, the 2x2 rate appears to be the highest supported. Some GPUs support 4x2, 2x4, and 4x4 modes, but this isn't applicable to Nanite.

In my testing, the RTX 3060 12G achieves similar or slightly higher percentage results. This relatively expected: the 3090Ti has a lot of shading power, and thusly reductions in pixel shader load don't affect it as much the 3060 12G at high resolutions.

Enabling VRS

Unreal's VRS is split into a few parts, each that controls a portion of the configuration. The settings you probably want to enable are below.

Command Note
r.VRS.Enable Ignored by EnableSoftware
r.VRS.EnableImage Enable for VRS Tier 2
r.VRS.EnableSoftware Works on hardware without Tier2 VRS support
r.VRS.ContrastAdaptiveShading Enable Feedback for VRS

If you're implementing this in a project, consider only exposing the options that you have vetted. There isn't a great reason to let users switch, for example, between full and conversative VRS modes on any given pass outside of academic interest. If full works and doesn't degrade the image, there isn't a good reason not to take the performance wins from the full mode. Likewise, exposing a switch from hardware VRS to software VRS is also pretty academic. Software VRS has broader support, works better with Nanite, and typically performs better.

r.VRS.ContrastAdaptiveShading is pretty much the toggle for Tier 2 VRS, despite what r.VRS.EnableImage says, it doesn't really do anything on its own. Nonetheless, r.VRS.EnableImage is probably the correct way to handle disabling Tier 2 VRS. In the future, it's possible that ContrastAdaptiveShading isn't the only Tier2 implementation.