The SRP Batcher is a rendering loop that speeds up your CPU rendering in Scenes with many Materials that use the same Shader Variant.
To use the SRP Batcher, your Project must use a Scriptable Render Pipeline. This can either be:
To activate the SRP Batcher in URP:
In HDRP, the SRP Batcher is enabled by default and you should not disable it. However, if you want to temporarily disable the SRP Batcher for debugging purposes:
You can also enable or disable the SRP Batcher at run time. To do this, toggle the following global variable in your C# code:
GraphicsSettings.useScriptableRenderPipelineBatching = true;
The SRP Batcher works on almost all platforms. This table shows supported platforms and the minimal Unity version required.
Platform | Minimum Unity version required |
Windows DirectX 11 | 2018.2 |
PlayStation 4 | 2018.2 |
Vulkan | 2018.3 |
OSX Metal | 2018.3 |
iOS Metal | 2018.3 |
Nintendo Switch | 2018.3 |
Xbox One DirectX 11 | 2019.2 |
OpenGL 4.2 and higher | 2019.1 |
OpenGL ES 3.1 and higher | 2019.1 |
Xbox One DirectX 12 | 2019.1 |
Windows DirectX 12 | 2019.1 |
Note: For XR, you can only use the SRP Batcher with the SinglePassInstanced
mode.
In Unity, you can modify the properties of any Material at any time during a frame. However, this has some drawbacks. For example, there is a lot of work to do when a DrawCall is using a new Material. So the more Materials you have in a Scene, the more CPU Unity has to use to set up GPU data. The traditional way to deal with this is to reduce the number of DrawCalls to optimize the CPU rendering cost, because Unity has to set up a lot of things before issuing the DrawCall. And the real CPU cost comes from that setup, not from the GPU DrawCall itself, which is just some bytes that Unity needs to push to the GPU command buffer.
The SRP Batcher reduces the GPU setup between DrawCalls by batching a sequence of Bind
and Draw
GPU commands.
To get the maximum performance for your rendering, these batches must be as large as possible. To achieve this, you can use as many different Materials with the same Shader as you want, but you must use as few Shader Variants as possible.
During the inner render loop, when Unity detects a new Material, the CPU collects all properties and sets up different constant buffers in GPU memory. The number of GPU buffers depends on how the Shader declares its CBUFFERs.
To speed up the general case where a Scene uses a lot of different Materials, but very few Shader variants, the SRP natively integrates paradigms such as GPU data persistency.
The SRP Batcher is a low-level render loop that makes Material data persist in GPU memory. If the Material content does not change, the SRP Batcher does not need to set up and upload the buffer to the GPU. Instead, the SRP Batcher uses a dedicated code path to quickly update the Unity Engine properties in a large GPU buffer, like this:
Here, the CPU only handles the Unity Engine properties, labelled Per Object large buffer in the above diagram. All Materials have persistent CBUFFERs located in GPU memory, which are ready to use. This speeds up rendering because: All Material content now persists in GPU memory. Dedicated code manages a large per-object GPU CBUFFER for all per-object properties.
In any given Scene, some objects compatible with the SRP Batcher, and some are not. Even when using non-compatible objects, Unity renders the Scene properly. This is because compatible objects use the SRP Batcher code path, and others use the standard SRP code path.
For the SRP Batcher code path to render an object:
For a Shader to be compatible with the SRP Batcher:
unity_ObjectToWorld
, or unity_SHAr
.UnityPerMaterial
.You can see the compatibility status of a Shader in the Inspector panel.
To measure the speed increase in your Scene when using the SRP Batcher, add the SRPBatcherProfiler.cs
C# script from the SRP Batcher template to your Scene. When this script is running:
Toggle the overlay display using the F8 key.
You can also turn SRP Batcher on and off during play using the F9 key.
The overlay looks like this:
The time measurements are in milliseconds (ms), and show how much time the CPU spent in Unity SRP rendering loops.
Note: Time here equals cumulated time of all RenderLoop.Draw
and Shadows.Draw
markers that are called during a frame, regardless of the thread owner. For example, if you see 1.31ms SRP Batcher code path, maybe the draw calls have spent 0.31ms on the main thread, and 1ms is spread over all graphic jobs.
This table describes each setting in the SRP Batcher overlay that is visible in Play mode:
Name in overlay | Descripción | |
---|---|---|
(SRP batcher ON) / (SRP batcher OFF) | Indicates whether the current SRP Batcher is enabled or not. To toggle the SRP Batcher on or off, press F9. | |
CPU Rendering time | Indicates the total, cumulative amount of time that SRP loops have spent in the CPU, regardless of which multi-thread mode is being used, for example single, client/worker or graphics jobs. This is where you can see the effects of the SRP Batcher the most. To see the optimization of the batcher, try toggling it on and off to see the difference in CPU usage. In this example, the total is 2.11 milliseconds. (incl RT idle): Indicates the idle time that the SRP has spent in the render thread. This could mean that the app was in a client/worker mode with no graphics jobs, which happens when the render thread has to wait for the graphics commands on the main thread. In this example, the render thread was idle for 0.36 milliseconds. |
|
SRP Batcher code path (flushes) | Indicates the time your game or app spent in the SRP Batcher code path. This is broken down into the amount of time that your game spent rendering All objects (except for shadow passes) (1.18ms), and Shadows (1.13ms). If the Shadows number is high, try reducing the number of shadow casting lights in your Scene, or choose a lower number of Cascades in your Render Pipeline Asset. In this example, it was 1.31ms. The (flush(s)) number indicates how many times Unity flushed the Scene because it encountered a new Shader Variant (in this example: 89). A lower number of flushes is always better, because that means there was a low number of Shader Variants in the frame. |
|
Standard code path (flushes) | Indicates the time Unity spent rendering objects that are not compatible with the SRP Batcher, such as particles. In this example, the SRP Batcher flushed 81 objects in 0.80ms: 0.09ms for shadow passes and 0.71ms for all other passes. |
|
Global Main Loop: (FPS) | Indicates the global main loop time in milliseconds, and the equivalent in frames per second (FPS). Note. FPS is not linear, so if you see FPS increase by 20, this doesn’t necessarily mean you’ve optimized the Scene. To see whether the SRP Batcher optimizes your Scene rendering, toggle it ON and OFF, and compare the numbers under CPU Rendering time. |
You can check the status on SRP Batcher “batches” in the Frame Debugger window.
To check the status of SRP Batcher batches:
The SRP Batch details show you how many draw calls were used, which keywords were attached to the Shader, and the reason why that specific draw call wasn’t batched with the previous one. In the example below, the stated reason is: Node use different shader keywords. This means that the Shader keywords for that batch are different than the keywords in the previous batch. Because the SRP Batcher used a different Shader Variant, the batch was broken. If an SRP batch has a low number of draw calls, you’re most likely using too many Shader Variants.
If you’re writing your own SRP instead of using URP or HDRP, try to write a generic “uber” Shader with a minimal amount of keywords (but you can use as many Material parameters and Material Properties inside each Material as you want).