Greetings from the Shaders team!
We would like to share the news on some immediate improvements coming up, which aim to resolve the current pain points of shader compilation time and memory usage. We also wish to share some best practices regarding shader variant stripping, which you may find useful.
Conditional shader features allow artists and developers to easily control the shader’s functionality at authoring or runtime. Static branching and shader variant compilation is traditionally used, which generally provides improved performance of shader execution compared to dynamic branching. As the feature set of the render pipelines grew, so did the amount of shader variants, often resulting in painfully long build times and high memory usage for shaders.
Improvements to shader compilation time and memory usage
To address these pain points, we are now working on immediate improvements to Unity’s shader variant stripping, as well as shader memory usage:
Variant Keyword Prefiltering is a new optimization to the engine’s built-in stripping, and will significantly reduce build times due to shader variant processing and compilation. Shader variant stripping greatly reduces the amount of compiled shader variants, however stripping is currently performed at the end of the shader processing stage. Processing a huge amount of variants can still take a long time, regardless of compilation.
This optimization introduces early exclusion of ‘multi_compile’’ keywords based on project settings to greatly reduce shader variants processing time. Variant Prefiltering landed in 2023.1.0a14 and was backported all the way back to 2021.3.15. Based on our internal tests, warm build times have been reduced by up to 90%!
Dynamic Shader Loading is an additional optimization which provides control over shader runtime memory usage. Shader variants actively utilized by the GPU in a frame are often a small portion of all variants actually included in the build. Prior to this optimization, all shader variants were front loaded to CPU memory on scene or resource load. As a result, shader memory usage was often much larger than what is actually needed at runtime.
This optimization enables streaming of shader data chunks into memory, and eviction of shader data that is no longer needed at runtime, based on a user controlled memory budget. This allows to reduce shader memory usage on platforms with limited memory budget.
The new Shader Variant Loading Settings are now accessible from the Editor’s Player Settings, and can be used to override the maximum number of shader chunks loaded and per-shader chunk size (MB):
-
PlayerSettings.SetDefaultShaderChunkCount and PlayerSettings.SetDefaultShaderChunkSizeInMB can be used to override the project’s default shader loading settings.
-
You can override these settings on a per platform basis, using PlayerSettings.SetShaderChunkCountForPlatform and PlayerSettings.SetShaderChunkSizeInMBForPlatform.
You can also override the maximum amount of loaded shader chunks at runtime using the C# API, via Shader.maximumChunksOverride. This allows to override the shader memory budget based on factors such as the total available system and graphics memory queried at runtime.
Dynamic Shader Loading landed in 2023.1.0a11 and backported all the way back to 2021.3.12. In the case of URP’s BoatAttack, we observed a 78.8% reduction in runtime memory usage for shaders, from 315 MiB (default) to 66.8 MiB (dynamic loading). You can read more about this optimization in the official announcement .
We hope to share information about backports as soon as possible. In the longer term, we are also planning to improve Shader Variant Management as a whole, from better tools and workflows for tracking and stripping shader variants, to improved logging and control of build and runtime shader compilation, as well as documentation updates.
Build-time shader variant stripping
The engine’s build-time shader variant stripping aims to reduce the amount of compiled variant, the resulting build times and runtime memory usage for shaders. To maximize the benefits of Unity’s built-in variant stripping, it is recommended to follow the best practices outlined in the manual for Shader Variant Stripping.
Based on the render pipeline, you can also enable shader variant stripping settings in the URP Global Settings & HDRP Global Settings, and disable any unused features in the URP Assets & HDRP Assets used by the player quality settings.
When authoring your own conditional shader features using ‘multi_compile’ keywords, consider implementing editor scripts that perform custom build-time stripping via the OnProcessShaders callback. This way, you can explicitly remove variants that are not needed at runtime, based on your target platform or runtime settings.
Shader variant logging and runtime profiling
In 2020.2, the Editor.log was extended to include information (per shader/pass/stage) on the amount of shader variants stripped and compiled, as well as variants processing and compilation time. Before 2020.2, the same information can be logged by setting the “Shader Variant Log Level” in the Universal Render Pipeline Asset & HDRP Global Settings.
Player logging can be enabled via “Log Shader Compilation” in the Graphics Settings, and is useful for tracking shader variants that are requested by the GPU and compiled at runtime. In the Graphics Settings, it is also possible to track the runtime compiled shaders used by the Editor’s viewport, and save them to a Shader Variant Collection. (“save to asset” at the bottom of the menu)
Runtime memory usage of shaders can be profiled using the Memory Profiler package. Shaders which use up the most runtime memory are a good candidate for shader variant stripping.
When a requested shader variant is missing at runtime (due to stripping), the engine will fallback on the closest matching variant by default. in 2022.1.0a7*, Strict Shader Variant Matching was introduced and can be used to fallback on a pink debug shader instead, logging an error in the console detailing the missing variant and its keywords. This can be useful when performing shader variant stripping, in order to identify variants that should not be stripped.
We know the build time and memory situation has been a huge source of difficulty, and we appreciate all your feedback. You can now also submit requests directly to the Shader System Portal. Please let us know what you think, and share any improvements you would like to see in the future!