[[Графика на Unity|Назад]]
Релевантные источники:
[Unity Doc -> Scriptable Render Pipeline Batcher](https://docs.unity3d.com/2023.2/Documentation/Manual/SRPBatcher.html)
- [Перевод на русский язык](https://unityhub.ru/manual/SRPBatcher)
[Unity Doc -> Устранение неполадок SRP Batcher в URP](https://docs.unity3d.com/6000.2/Documentation/Manual/SRPBatcher-Profile.html)
Релевантные страницы:
- [[Как выглядит SRP-Batch в Frame Debugger?]]
- Как узнать причину, по которой объект не попал в SRP Batch?
- [[Batch cause в Frame Debugger]]
- [[Поле SRP Batcher в инспекторе шейдера]]
- [[Разбор схемы работы SRP Batcher и Standard SRP]]
- [[Куда попадают параметры материалов в SRP Batcher и разрывает ли батч, если некоторые параметры материала разные?]]
- [[Уменьшается ли количество SetPass Calls при использовании SRP Batcher? ]]
- [[Как включается SRP Batcher]]
### Что такое SRP Batcher
**SRP Batcher** (Scriptable Render Pipeline Batcher) — это низкоуровневый путь рендеринга, который не уменьшает число draw calls, а резко сокращает количество CPU-затрат на их подготовку.
SRP Batcher устраняет часть работы CPU между вызовами отрисовки, минимизируя изменения состояний и повторную загрузку одних и тех же данных.
GPU Instancing конфликтует с SRP Batcher (не работает одновременно).
- если объект может быть отрисован через SRP Batcher, то он **будет** им отрисован и **не** станет инстанцироваться
SRP Batcher — это чисто CPU-процедура, которая выполняется в нативном [[CPU main thread и CPU render thread|Render Thread]] (или в его worker-потоках, когда включены Graphics Jobs).
Стандартные шейдеры URP (Lit, Unlit), а также шейдеры, созданные через Shader Graph - [[Стандартные шейдеры URP (Lit, Unlit), а также шейдеры, созданные через Shader Graph - совместимы с SRP Batcher.|совместимы]] с SRP Batcher.
### Как работает механизм
| Шаг | **[[Standard SRP]] (обычный путь)** | **SRP Batcher (оптимизированный путь)** |
| -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **1. Сортировка объектов** | Частичная — по материалам и [[Render State\|render-state]], но не по [[Shader Variant\|shader variant]]. Для объединения объектов необходим [[тот же самый экземпляр материала\|тот же самый экземпляр материала]], иначе батчинг не происходит. | Полная сортировка по [[Shader Variant\|shader variant]] + [[Render State\|render-state]] для объединения в группы (батч), игнорируя различия между разными экземплярами материалов на этом шейдере. При этом материалы, могут иметь [[Параметры или свойства материала\|разные параметры]] |
| **2. Обработка материала** | CPU при встрече каждого нового экземпляра материала выполняет трудоёмкую работу: собирает все [[Параметры или свойства материала\|свойства материала]] и подготавливает их для отправки на GPU. Это включает настройку/создание постоянных буферов (constant buffers) под данные материала и привязку их к графическому конвейеру. Проще говоря, для каждого инстанса материала происходит вызов SetPass: загружается шейдерный программ, устанавливаются все униформы и ресурсы. Если один и [[тот же самый экземпляр материала]] используется подряд для нескольких объектов, движок может повторно использовать уже настроенный шейдер, но как только материал меняется, CPU снова проделывает всю подготовку. При большом количестве материалов в сцене затраты CPU резко возрастают, т.к. каждый новый материал требует новой настройки констант и состояний. | Минимизирует работу CPU при обработке материалов. При первом использовании материала SRP Batcher один раз собирает [[Параметры или свойства материала\|свойства этого материала]] и размещает их в константном буфере на GPU, сохраняя эти данные там на будущее. Все материалы получают постоянные буферы (Constant Buffers), находящиеся в памяти GPU, которые не пересоздаются каждый кадр. Если содержимое материала не менялось, при последующей отрисовке CPU вообще не занимается переустановкой [[Параметры или свойства материала\|свойств материала]] – они уже “лежат” в GPU и готовы к использованию. CPU фокусируется только на обновлении данных, зависящих от объекта (например, трансформы). Таким образом, затраты на SetPass существенно сокращаются: даже если в сцене множество разных материалов, но по небольшому числу шейдеров, CPU не повторяет одну и ту же работу для каждого экземпляра материала, как в обычном режиме. |
| **3. Отправка данных на GPU | Основная нагрузка при рендеринге связана с передачей данных на видеокарту для каждого draw call. Для каждого объекта/материала CPU должен отправить в GPU все необходимые константы и параметры (через записи в uniform-переменные или небольшие буферы). На самом деле, основной CPU-накладной часть рендеринга – это не сам вызов отрисовки, а подготовка данных для него (заполнение и отправка буферов). При большом количестве объектов шина CPU–GPU может загружаться пересылкой множества одинаковых по структуре данных (например, цветов материалов, коэффициентов и т.п.), повторяемых для каждого объекта. В итоге без батчера мы тратим много времени на передачу избыточных данных, особенно если объекты используют один шейдер с разными материалами. | Радикально сокращает объём данных, пересылаемых на GPU для каждого объекта. Поскольку [[Параметры или свойства материала\|свойства материалов]] уже хранятся в памяти GPU, каждый draw call не дублирует их отправку, а использует сохранённые значения. По сути, для рисования очередного объекта с тем же шейдером CPU достаточно указать GPU, какой материал (какой участок буфера) использовать, и обновить лишь небольшое количество переменных, специфичных для этого объекта (например, матрицу модели в крупном общем буфере). Это существенно уменьшает трафик по шине и время, затрачиваемое CPU на каждый вызов отрисовки. Иными словами, SRP Batcher кэширует материал на стороне GPU, избавляя от повторной передачи его [[Параметры или свойства материала\|параметров]], что экономит и CPU, и пропускную способность памяти. |
| **4. Вызовы Bind + Draw | Для каждого объекта выполняется, как правило, отдельная последовательность команд: установить (bind) нужный шейдер и ресурсы, затем выполнить команду отрисовки (draw). Даже при сортировке по материалам каждая смена материала приводит к новому набору команд Bind. Таким образом, если рисуется N объектов, обычно совершается ~N отдельных draw-вызовов, каждый со своей затратной настройкой состояния (если повезёт и несколько объектов подряд имеют [[тот же самый экземпляр материала]], они могут разделить настройку шейдера, но [[изменение любого параметра]] всё равно требует команд на переключение). Исторически оптимизация рендеринга сводилась к снижению числа draw call’ов, так как каждая содержит дорогостоящую фазу Bind (Setup) перед собственно командой рисования | “Склеивает” последовательности Bind+Draw в большие пачки. Для группы объектов с одним шейдером выполняется одна общая настройка (bind) шейдера и материалов, после чего подряд вызываются несколько команд Draw без полного сброса/настройки между ними. Такое объединение называется _SRP-батч_ – он представляет собой серию из множества Draw, выполненных под одним контекстом привязанных ресурсов. В результате уменьшается количество переключений состояний: многие объекты отрисовываются как бы “за один заход”. Важно понимать: SRP Batcher _не_ объединяет геометрию разных объектов в один и тот же draw call (как это делает статический или динамический батчинг) – каждый объект всё ещё рендерится отдельной командой Draw, просто эти команды идут последовательно в одной батче с минимальными изменениями состояния. Это снижает накладные расходы, связанные с повторяющимися Bind, и приближает по эффективности рендеринг большого числа объектов к единому пакету. |
| **5. Работа [[CPU main thread и CPU render thread\|Render Thread]]** | Поток обрабатывает длинную последовательность команд для каждого объекта: настройка констант, привязка разных ресурсов, запуск отрисовки, затем снова настройка для следующего объекта и т.д. Большое число draw call’ов напрямую нагружает поток рендеринга, так как каждая пачка настроек и команд требует CPU-времени в драйвере и двигателе. При сценах с тысячами объектов Render Thread без батчера часто становится узким местом ([[CPU-bound]]), даже если сами GPU-операции (растеризация и др.) относительно быстрые. | Нагрузка на [[CPU main thread и CPU render thread\|Render Thread]] значительно снижается. Поскольку команды сгруппированы в большие батчи, поток рендеринга выполняет гораздо меньше переключений состояния и вызовов драйвера. Он может отправлять на GPU сразу серию отрисовок, используя единожды установленный шейдер/материал, вместо того чтобы повторять настройку для каждого объекта. Каждый draw call “худеет” по затратам CPU, что в сумме сильно ускоряет прохождение командного буфера. В реальных сценах включение SRP Batcher даёт заметный рост производительности на стороне CPU (по данным Unity, ускорение работы процессора при рендеринге может составлять ~1.2–4× в зависимости от сцены. Иными словами, SRP Batcher сокращает время, затрачиваемое CPU на отправку команд и данных на видеокарту, освобождая ресурсы CPU для других задач или повыша |
| **6. Использование кэша** | Материал не имеет постоянного GPU-кэша своих параметров – все свойства хранятся в CPU-памяти (в объекте Material) и при рендеринге заново передаются или устанавливаются в драйвере. Unity не сохраняет автоматом уникальные буферы под каждый материал между вызовами отрисовки – вместо этого каждый кадр (или при смене материала) значения снова загружаются. Некоторое кеширование может происходить на уровне драйвера (например, уже загруженные ранее константы могут оставаться в регистрах до изменения), но с точки зрения Unity каждый новый материал считается новым набором данных для GPU. Также, если для уникализации материала используется MaterialPropertyBlock, в стандартном рендерере это просто добавляет ещё один уровень переустановки данных перед draw call. | Внедряет кэш на уровне GPU для материалов. Для каждого совместимого материала Unity заранее (при первом использовании) выделяет на GPU область в буфере UnityPerMaterial, куда записываются все постоянные свойства этого материала. Эти данные хранятся постоянно в видеопамяти и повторно используются при каждом рендере, пока материал не изменится. Таким образом, материал как бы имеет собственный GPU-кэш своего состояния. Кроме того, SRP Batcher использует один большой буфер для всех пер-объектных данных (UnityPerDraw) и обновляет в нём только соответствующий раздел для текущего объекта очень быстрым путём. В результате кэшируются все неизменные между объектами данные ([[Параметры или свойства материала\|свойства материалов]], константы шейдера), а изменяется и пересылается лишь минимальный набор данных на объект (матрицы, уникальные параметры). |
---
### Требования к совместимости
1. **Pipeline** — URP, HDRP или собственная SRP; в Built-in RP не работает.
2. **Шейдер** должен держать _все_ свойства движка в `CBUFFER UnityPerDraw`, а _все_ [[Параметры или свойства материала|свойства материала]] — в `CBUFFER UnityPerMaterial`
3. **Материал** не должен использовать [[MaterialPropertyBlock]] (он разрушает батч).
4. **Рендерер** без GPU Instancing; если инстансинг выгоднее (много _идеально_ одинаковых мешей), можно отключить SRP Batcher для конкретного материала.
---
### Ограничения и подводные камни
| Сценарий | Поведение |
| --------------------------------------------------------------------------------- | ------------------------------------------------------ |
| `MaterialPropertyBlock` меняет свойство из `UnityPerMaterial` | Объект выводится из SRP Batcher |
| Multi-Pass шейдеры (доп. Shadow Caster pass и т. д.) | Каждый pass считается отдельным, бэтчи могут дробиться |
| Слишком много shader [[Shader Variant\|variants]] / [[Shader Keywords\|keywords]] | Бэтчи короткие → эффект минимальный |
| WebGL | SRP Batcher недоступен (Нет CBuffer API ) |