Jul 21, 2021
Qualcomm products mentioned within this post are offered by Qualcomm Technologies, Inc. and/or its subsidiaries.
Occasionally, there’s a feature that is thought to be too good to be true. In the case of Variable Rate Shading (VRS), it is the real deal! VRS is a feature that can result in huge performance and power benefits without compromising the visual quality of your game.
Shading is the process of calculating the resulting color of each pixel on the screen. This process is done via fragment shaders. Shaders are powerful tools in programmable graphics pipelines as they allow game developers to take full advantage of GPU’s horsepower by allowing custom code to be executed. Perhaps one of the most important shader types is the fragment shader (aka pixel shader) which is executed after the GPU has rasterized the geometry and uses inputs such as textures, normals, mathematical operations, etc., to produce the ultimate color for a given pixel. With increased demand for high-fidelity and physically-based graphics, fragment shaders have grown in complexity and size over the years and account for most of the heavy lifting the GPU does to render a scene from a game.
VRS takes the fragment shader to a whole new level. In a nutshell, VRS allows a fragment shader to color one or more pixels at a time (where a fragment can represent one pixel or a group of pixels). You can think of VRS as solving the inverse problem that anti-aliasing techniques solve. Anti-aliasing techniques seek to sample each pixel more frequently in an attempt to avoid aliasing and jagged edges by smoothing the content with high variation. But if the surfaces to be rendered don’t have high color variation or will be blurred on a subsequent pass (e.g., with motion blur), performing shading operations on a 1:1 basis (i.e., one shading operation per one pixel) can be inefficient.
VRS allows developers to specify shading rates where only one shader computation is performed for a fragment and the result operation is applied to the specified pixel group configuration. When used properly, this should result in no visual quality degradation while significantly alleviating the GPU’s work to render a frame, thus conserving power and improving performance. With several high display rate mobile devices commercially available, like those powered by our Snapdragon mobile platforms and their embedded Qualcomm Adreno GPU's, the need for shading every pixel for all surfaces being rendered is diminished.
The following screenshot (Figure 1) from our Variable Rate Shading demo shows how higher rate (i.e., per-pixel) shading should be used on highly detailed areas, while lower rates (i.e., shading fragments comprising groups of pixels) can be done on lower detail areas.
How does Variable Rate Shading work?
When the GPU renders and rasterizes objects into a surface, it does so at a rate of one sample per pixel (assuming no multi-sampling is used, although this concept can be applied to multi-sampled as well). Through graphics API extensions, a developer can modify the shading rate of a given surface to be coarser than a pixel, as shown in Figure 2.
We’ve exposed VRS for mobile through the QCOM_shading_rate extension for OpenGL ES and the VK_KHR_fragment_shading_rate extension for Vulkan. The OpenGL ES extension includes a number of enumerations (e.g., GL_SHADING_RATE_1X1_PIXELS_QCOM, GL_SHADING_RATE_1X2_PIXELS_QCOM, etc.) for controlling the different fragment sizes. You can see a demonstration of the extension’s usage on our new Adreno GPU OpenGL ES Code Sample Framework in GitHub.
Vulkan’s VK_KHR_fragment_shading_rate takes in a VkExtent2D struct in which developers specify the width and height of the desired fragment size. Note that support for VK_KHR_fragment_shading_rate on Snapdragon mobile platforms is coming soon.
Effective ways to modify shading rate
These extensions can improve performance on heavy fragment-bound draw calls such as:
- Surfaces where the color variance is small.
- Surface areas that don’t require per-pixel shading accuracy. These can be color targets that will be downscaled through motion blur and where there are significant velocity field changes. If depth of field is used, there will be areas outside of the focus point that will be blurred.
- Effects like motion volumetric rendering where a portion of the scene is processed at full shading rate and a portion can be processed at a reduced shading rate.
Note that reducing the shading rate can impact the visual quality of a rendered object if used inappropriately. On mobile devices where performance and power are tightly coupled, the use of courser shading rates can also improve power consumption and reduce the thermal profile of your game, ultimately increasing the user’s play time.
VRS in practice
Our team collaborated with Netease to provide Snapdragon Elite Gaming features to their games. Netease has implemented VRS into their upcoming game: Revelation Mobile (Tianyu). Through this collaboration and the improvements provided by VRS, the game saw a boost of over 30% in power efficiency and 38% in framerate.
You can download the game from here to witness VRS in action!
Developers interested in building games and graphic-intensive apps for Snapdragon should check out some of the hardware development kits (HDK) available on Qualcomm Developer Network, including the Snapdragon 888 mobile HDK and the Snapdragon 865 mobile HDK.
For additional information about the Adreno shader support in OpenGL ES, download the Adreno SDK and check out the Snapdragon OpenCL General Programming and Optimization and Adreno OpenGL ES Developer guides included in the SDK.