In Unity’ HDRP, dynamic resolution can be used to improve framerate without sacrificing too much of the game’s visual qualities. Most of the tweakable parameters are documented, except for “Hardware” and “Software” dynamic resolution modes. OK, then, what are those?
I spent some time poking into the two different modes and it turned out “Hardware” and “Software” aren’t that simple, they have serious impact on the whole render pipeline.
What’s more, in my opinion, dynamic resolution is not a hardware-level thing. They just use the graphics API differently to achieve the downscaling effect.
“Software” dynamic resolution (Viewport)
Before tackling what “viewport implementation” is, let us review how is the viewport data specified:
In VkPipeline
construction, we could specify vkViewport
s in VkPipelineViewportStateCreateInfo
, or when using dynamic viewports, it is set with vkCmdSetViewport
.
-
Non-dynamic viewports are preferable when viewport does not change. If you do change it however, you need to recreate the whole
VkPipeline
which would result in significant stutter. -
Dynamic viewports are preferable when viewport does change. This does induce small runtime performance costs due to the extra command.
Unity uses dynamic viewport by default: (capture taken when dynamic resolution is disabled)
Therefore, dynamic resolution does not induce extra overhead of set viewport commands.
Now, the viewport implementation.
Essentially, viewport implementation creates one single VkImage
with the size of the swapchain extents and draws on a limited area specified by the viewport:
Note the Dimension here: it is exactly the size of the swapchain extents:
Viewport affects clip space coordinates translation, mapping the range of the clip space to the area of the viewport. When the driver knows the viewport beforehand, it doesn’t need to run the fragment program on pixels outside of the viewport, and that’s how we gain the performance boost.
“Hardware” dynamic resolution (Memory Aliasing)
Hardware implementation is only available in DX12 and Vulkan for good reason: Memory Aliasing can only be achieved with lower-level graphics API.
In a nutshell, Memory Aliasing is creating multiple VkImage
but map them to the same chunk of memory (the largest chunk required by all these images).
Here’s a capture taken when memory aliasing implementation is enabled:
Note here the Dimension is no longer the extents of the swapchain:
Unity still issues vkCmdSetViewport
call, but now the viewport covers the entire render target rather than just a portion.
In Unity, render textures that have dynamic scaling enabled (.useDynamicScale = true
) are managed by ScalableBufferManager
. Unity issues a global update call to update the resolution (probably keeping which slice of the render target to use, managed in the C++ side of the engine).
Which one to choose?
The reason Unity used Hardware and Software to label the two implementations is probably, it is intuitive that if dynamic scaling is supported on a “hardware” level, it is better. And that is actually true. But here are the details why memory aliasing is better than viewport when both options are available:
-
When the GPU loads a texture (via OP_LOAD), only the mapped memory of
VkImage
is pulled. The viewport implementation always loads the full resolution texture, but only draws on part of it, resulting in a waste of GPU bandwidth. In contrast, memory aliasing only loads what is necessary. -
The viewport implementation only assures the specific area is written to, but does not prevent reading from areas that are “out of bounds”. This means if you were to sample a texture subject to viewport implementation dynamic resolution before the upscaling pass, not only you don’t save any sampling calls, you must also take precautions that there might be invalid data. Unity hides this fact as usually, you would sample those textures in a post processing pass, while the upscaling pass is placed conveniently before post processing by default.
The conclusion is: prefer Hardware whenever possible, and take precautions when sampling as not all devices support Vulkan/DX12 and will cause a fallback to Software.