Hello Unity users!
TL;DR:
Unity 2021.2.0a16 changes the way shader keywords work and removes fixed limits on the number of keywords used both per shader and globally.
First, the long-awaited part: fixed keyword limits are gone. There can now be up to 4.294.967.294 (2^32 - 2) global keywords per project. Local keywords are limited to 65534 (2^16 - 2) per shader or compute shader.
Next, we introduce a concept of keyword spaces.
Each shader has its own local keyword space, with no distinction between local or global keywords that existed before. All keywords declared in a shader are local. [EDITED on 08.06.2021] This, in turn, means that #pragma multi_compile and #pragma multi_compile_local do the same thing; the same is true for #pragma shader_feature and #pragma shader_feature_local. We will deprecate the pragmas with “_local” suffix in the future. The “_local” suffix in #pragma multi_compile and #pragma shader_feature directives determines whether the global keyword state can override the local shader keyword. The first appearance of a shader keyword wins in case of a conflict. [END OF EDIT]
Local keyword space is formed from all keywords declared in the shader, all keywords declared in passes that are added with UsePass functionality and all keywords from the shaders in the fallback chain. If a keyword in a fallback or in UsePass has the same name as a keyword in the main shader, it’s treated as the same keyword and counts only once. Unity automatically adds several builtin keywords to each local keyword space (UNITY_SINGLE_PASS_STEREO, STEREO_CUBEMAP_RENDER_ON, STEREO_MULTIVIEW_ON and STEREO_INSTANCING_ON). Any keywords added by shader compiler access plugins are also automatically added to each local keyword space.
For compute shaders the local keyword space is formed from all keywords declared in the compute shader.
The local keyword limit mentioned above applies to keywords in a single local keyword space.
Global keyword space is completely separate. Prior to rendering keywords from the global keyword space are converted to local keyword space. The conversion is based on keyword names. Enabling a global keyword FOO means that any shader or compute shader that has FOO in its local keyword space will have this keyword enabled.
A note on performance: local keyword spaces maintain a mapping from the global keyword space. When a keyword is added to the global space, the mapping gets updated on the first conversion from the global space to the local space. For best performance, add all global keywords as early as possible.
C# API changes.
We keep the current string-based C# API intact with some minor improvements: Shader.DisableKeyword and Shader.IsKeywordEnabled no longer create a global keyword if it doesn’t exist.
We also added a new API that is faster and has a clear separation between local and global keywords. Material, ComputeShader, Shader, CommandBuffer and ShaderKeywordSet classes have been extended to work with the new API - methods that accept instances of LocalKeyword and GlobalKeyword structs. Shader and ComputeShader also got a new member keywordSpace that can be used to query the local keyword space of a particular Shader or ComputeShader.
GlobalKeyword also has an explicit static method to create a new GlobalKeyword. The constructor does not create a new keyword if it doesn’t exist.
Shader.EnableKeyword and CommandBuffer.EnableShaderKeyword create a new global keyword if it doesn’t exist.
Shader.DisableKeyword, CommandBuffer.DisableKeyword, Material.DisableKeyword, Material.EnableKeyword and ComputeShader counterparts have no effect if a keyword doesn’t exist. Shader, Material and ComputeBuffer IsKeywordEnabled methods return false for keywords that do not exist.
We also added Shader.enabledGlobalKeywords and Shader.globalKeywords to query the enabled global keywords and all existing global keywords, respectively.
Stay tuned for more updates!
(EDITED on 04.06.2021)
We added new API to set shader keyword state directly. Material.SetKeyword, Shader.SetKeyword, ComputeShader.SetKeyword and CommandBuffer.SetKeyword are available from 2021.2.0a19 onward.