Greetings from the Shaders team!
Unity 2023.1.0a11 brings dynamic shader variant loading. This feature allows you to manage the runtime memory usage of shaders.
The bulk of shader memory consumption in the player runtime comes from two areas: variant parameters and variants themselves. When we do a build, we compile individual variants for each shader, pack their parameters and the code together into chunks and compress each chunk individually. When a shader gets loaded, we decompress all chunks, load all variant parameters and prepare all variants for compilation by the GPU driver when rendering requests them.
Dynamic shader variant loading enables dynamic decompression of the chunks mentioned above and exposes control over two settings: the size of chunks during the build in megabytes and the maximum number of chunks that are kept decompressed simultaneously for each shader at runtime. Both settings can be configured globally and overridden for each platform. The default values are 16 megabytes per chunk, unlimited chunks. We treat 0 chunks as “no limit”.
Additionally, you can use Shader.maximumChunksOverride to override the chunk limit at player runtime for any shaders loaded after changing this value. The default value is -1, which means “do not override”. Setting this property to a positive values will set a fixed limit on the number of loaded chunks, 0 is treated as “no limit”, similar to the build time setting.
When all variants of a shader fall within the chunk limits, we preload all variants, as in the default case.
Please note that these limits only affect variants themselves, and have no effect on variant parameters.
We measured the memory savings and performance implications on two projects, Boat Attack and an artificial scene with one shader that has 30 000 variants. Measurements were taken with two sets of settings: default (up to 16 MiB chunk size, unlimited chunks) and with dynamic variant loading enabled (up to 1 MiB chunk size, up to 1 chunk loaded per shader). All measurements were performed on a MacBook Pro M1.
Memory usage in the artificial scene was reduced from 122.9 MiB (default) to 47 MiB (dynamic loading), or 61.8% reduction; in Boat attack - from 315 MiB (default) to 66.8 MiB (dynamic loading), or 78.8% reduction.
Initial loading is faster with dynamic variant loading as well - artificial scene loaded the heavy shader in 41.58 ms (dynamic loading) instead of 64.68 ms (default), or 35.7% faster; Boat attack loaded the shaders in 46.89 ms (dynamic loading) instead of 114.4 ms (default), or 59% faster.
Of course, this is not entirely free. Loading individual variants when they are required takes roughly 10% more time: 0.25 ms per variant with dynamic loading and 0.23 ms per variant with default settings.
We plan to backport this to 2022 and 2021.3 LTS.
Stay tuned for more!