Asynchronous Shader compilation prevents the Unity Editor from stalling by rendering dummy Shaders while compiling new Shader Variants. Asynchronous Shader compilation is enabled un the Editor settings (menu: Edit > Settings > Editor) by default.
Shaders can consist of hundreds or thousands of variants that cover different usage scenarios with different keyword combinations. If the Editor had to compile all variants when loading a shader, the Shader import process would be very slow. To handle this, Unity uses on-demand Shader compilation by default. This means that the Editor compiles Shader Variants the first time it encounters them in a Scene. This can stall rendering in the Editor, because full Shader compilation can take anywhere from milliseconds to seconds. The time it takes to compile a Shader Variant depends on the selected graphics API and the complexity of the Shader. To overcome these stalls, use Asynchronous Shader Compilation.
Asynchronous shader compilation is enabled by default. You can disable it for Game View and Scene View. This can be useful if you don’t know which parts of your rendering solution are causing issues. However, you might then still experience rendering stalls in the Editor during Shader compilation.
To disable asynchronous Shader compilation: 1) In your Project, go to Edit > Project Settings > Editor. 2) At the bottom of the Editor settings, under Shader Compilation, uncheck the Asynchronous Shader Compilation checkbox.
Note: When you disable asynchronous shader compilation, this only affects the Scene View and Game View. This doesn’t affect systems and custom scripts that explicitly enable asynchronous Shader compilation.
With Asynchronous Shader Compilation, the Editor adds shader variants to a compilation queue and completes them in a job thread; it does not compile them immediately. . To avoid rendering stalls, the Editor continues rendering while it’s also compiling a Shader Variant. The Editor then fills in the Shader Variant’s spot with a dummy Shader in a plain cyan color (you’ll see occasional transient glimpses of the cyan dummy Shader that show what’s going on in the background). This avoids some objects not being rendered in Scenes, because the Editor is still compiling them. When compilation has finished, the Editor swaps-in the real Shader. The progress bar in the bottom right corner of the Editor shows the status of the compilation queue.
The feature does not have any effect on the standalone Player, because the Editor compiles all the Shader Variants needed by the Player during the build process.
Note: Asynchronous Shader compilation works in the Scene and Game views by default. If you want to use it in other scenarios, see [Using asynchronous Shader compilation in custom Editor tools.
Figure 1. Unity renders Shader Variants that are still compiling with a cyan dummy Shader until compilation has finished. The bottom right progress bar indicates Shader compilation queue progress.
Note: If you use DrawProcedural
or CommandBuffer.DrawProcedural
, the Editor doesn’t swap in a dummy Shader. Instead, the Editor just skips rendering this Shader Variant until it has compiled the Shader Variant.
Note: Blit operations do not use asynchronous Shader compilation. This is to guarantee correct output in the most common use cases.
By default, asynchronous Shader compilation works in the Scene and Game views. Advanced rendering solutions rely on generating data once and reusing it in later frames, which might cause the dummy Shader to pollute the generated data. If this happens, you can see the cyan color or other rendering artifacts in your Scene, even after the Shaders have finished compiling. The issue only happens the first time the Editor encounters the data generating Shader Variants. However, to avoid these issues, you can either disable asynchronous Shader compilation for some parts of your rendering, force synchronous Shader compilation for some Shaders, or detect the specific data pollution and re-generate the data when compilation is done.
If you want to use asynchronous Shader compilation, but also don’t want the dummy Shader to affect the rendering result on specific rendering calls, you can disable the feature for those calls in your C# scripts. The following instructions show you how to disable the feature in an immediate scope and a CommandBuffer scope. In both cases, you essentially inject clamps around the render calls that you don’t want Unity to compile asynchronously.
In an immediate scope, you’ll have to use ShaderUtil.allowAsyncCompilation;
.
Save the current state of ShaderUtil.allowAsyncCompilation
to a variable.
Immediately before you call the render commands that you want to disable asynchronous compilation for, set ShaderUtil.allowAsyncCompilation
to false
.
After the rendering calls you want to affect, restore ShaderUtil.allowAsyncCompilation
back to the previous state that you saved under step 1.
Here is a pseudo-code example:
// Store the current state and disable async compilation
bool oldState = ShaderUtil.allowAsyncCompilation;
ShaderUtil.allowAsyncCompilation = false;
// Enter your rendering code that should never use the dummy shader
Graphics.DrawMesh(...);
// Restore the old state
ShaderUtil.allowAsyncCompilation = oldState;
In a CommandBuffer scope, you’ll have to use ShaderUtil.SetAsyncCompilation
and ShaderUtil.RestoreAsyncCompilation
.
Immediately before you call the render commands that you want to disable asynchronous compilation for, call ShaderUtil.SetAsyncCompilation
, and set it to false
. All the immediately following commands in the buffer won’t allow asynchronous compilation.
After the rendering commands you want to affect, use Shader.Util.RestoreAsyncCompilation
.
Here is a pseudo-code example:
// Disable async compilation for commands followed by this
ShaderUtil.SetAsyncCompilation(cmd, false);
/// Enter your rendering commands that should never use the dummy shader
cmd.DrawMesh(...);
// Restore the old state
ShaderUtil.RestoreAsyncCompilation(cmd);
You can force synchronous compilation for specific Shaders. This is a good option for data generating Shaders that are always present at the start of your rendering, and which are relatively quick to compile.
To force synchronous compilation for a specific Shader:
In your Shader code, add this directive:
#pragma editor_sync_compilation
Note: Don’t force synchronous compilation for complex Shaders that encounter new variants in the middle of your rendering. Forced synchronous compilation of complex Shaders can stall rendering in the Editor.
If the dummy Shader pollutes your generated data, you must discard the polluted data and regenerate a new set with the properly-compiled Shaders.
If you already know the Material that Unity is using for data generation:
Use ShaderUtil.IsPassCompiled
to check the compilation status of the Shader Variant specified by the current state of the Material.
When the status has gone from Uncompiled to Compiled, refresh the generated data.
If you do not know which specific Material generates polluted data, or if the data generation is not specific to a single Material:
Use ShaderUtil.anythingCompiling
to detect whether Unity is compiling any shaders asynchronously.
When any asynchronous compilation has finished, refresh the data.
By default, asynchronous Shader compilation works in the Game and Scene views. If you want to use it in custom Editor tools, you can enable it via C# for your custom tool.
In an immediate scope, you’ll have to use ShaderUtil.allowAsyncCompilation;
.
Save the current state of ShaderUtil.allowAsyncCompilation
to a variable.
Immediately before you call the render commands that you want to enableasynchronous compilation for, set ShaderUtil.allowAsyncCompilation
to true
.
After the rendering calls you want to affect, restore ShaderUtil.allowAsyncCompilation
back to the previous state that you saved under step 1.
Here is a pseudo-code example:
// Store the current state and enable async compilation
bool oldState = ShaderUtil.allowAsyncCompilation;
ShaderUtil.allowAsyncCompilation = true;
// Enter your rendering code that you wish to utilize async compilation
Graphics.DrawMesh(...);
// Restore the old state
ShaderUtil.allowAsyncCompilation = oldState;
In a CommandBuffer based scope, you’ll have to use ShaderUtil.SetAsyncCompilation
and ShaderUtil.RestoreAsyncCompilation
.
Immediately before you call the render commands that you want to enable asynchronous compilation for, call ShaderUtil.SetAsyncCompilation
, and set it to true
. All the immediately following commands in the buffer then allow asynchronous compilation.
After the rendering commands you want to affect, use Shader.Util.RestoreAsyncCompilation
.
Here is a pseudo-code example:
// Enable async compilation for commands followed by this
ShaderUtil.SetAsyncCompilation(cmd, true);
/// Enter your rendering commands that you wish to utilize async compilation
cmd.DrawMesh(...);
// Restore the old state
ShaderUtil.RestoreAsyncCompilation(cmd);
Graphics.ExecuteCommandBuffer(cmd);
You can make your custom tools draw something other than the dummy Shader per Material. This way, you can avoid rendering with the Shader Variant that would be cyan, and instead draw something else while the Shader compiles.
To check if a specific Shader Variant has compiled, use ShaderUtil.IsPassCompiled
.
To trigger the compilation manually, use ShaderUtil.CompilePass
. This way, you can avoid rendering with the Shader Variant that would be cyan, and instead draw something else while the Shader compiles.