Draw Calls na Unity: SRP Batcher, Static e GPU Instancing

Unity draw calls no URP pelo Frame Debugger: SRP Batcher, static batching, GPU instancing e GPU Resident Drawer, o que se anula e um teste com 500 objetos.
Draw Calls na Unity: SRP Batcher, Static e GPU Instancing
Unity draw calls são os pedidos que a CPU faz à GPU para desenhar algo, e o custo real está menos no desenho e mais na preparação: trocar shader, material e dados antes de cada pedido. No URP do Unity 6.3 LTS, quatro mecanismos atacam isso: SRP Batcher (ligado por padrão), static batching, GPU instancing e GPU Resident Drawer. Eles não somam: a Unity escolhe um por objeto, numa ordem fixa, e alguns se anulam.
Este post explica cada um, mostra como ler o resultado no Frame Debugger e no painel Stats, e propõe um teste com 500 objetos que você roda no seu projeto para ver com os próprios olhos o que cada configuração muda.
O que é draw call e SetPass call
Para desenhar um objeto, a CPU precisa dizer à GPU: use este shader, com estas texturas e valores, nesta malha, nesta posição. Isso é um draw call. Antes dele, se o shader ou o passe mudou desde o último desenho, há uma troca de estado chamada SetPass call, que é mais cara.
No painel Stats da Game View (botão Stats no canto superior direito), você vê:
- Batches: quantos lotes de desenho o frame teve.
- SetPass calls: quantas trocas de estado de shader.
- Saved by batching: quantos desenhos foram agrupados.
Mil objetos não significam mil problemas. Significam mil preparações de CPU se nada estiver agrupando. Em PC isso raramente pesa; em celular, é um dos gargalos de CPU mais comuns.
Unity draw calls: ler no Frame Debugger e no Stats
O Frame Debugger (Window > Analysis > Frame Debugger) congela um frame e lista cada evento de renderização em ordem.
- Dê Play e clique em Enable no Frame Debugger.
- À esquerda, a árvore de eventos. Expanda os passes do URP (como
DrawOpaqueObjects). - Eventos com o nome SRP Batch são lotes do SRP Batcher. Clique em um: à direita aparece quantos draw calls ele juntou.
- Quando dois eventos seguidos não foram agrupados, o painel direito mostra o motivo (por exemplo, shader diferente, variante de keyword diferente, objeto com MaterialPropertyBlock).
- Arraste o seletor de evento para ver a tela sendo desenhada passo a passo.
Esse "motivo" é a informação que você não acha no Stats e que diz exatamente o que corrigir.
SRP Batcher: como funciona e o que quebra
O SRP Batcher não junta malhas. Ele guarda os dados dos materiais na GPU de forma persistente e, enquanto o shader variant for o mesmo, faz os draw calls seguidos sem refazer a preparação. Materiais diferentes com o mesmo shader (o URP Lit, por exemplo) entram no mesmo lote.
Segundo o manual do URP, ele fica no URP Asset em Rendering > SRP Batcher (visível com Show All Advanced Properties no menu de três pontos) e vem ligado. Se SRP Batcher e Dynamic Batching estão ligados, o SRP Batcher tem precedência quando o shader é compatível.
O que quebra:
- Shader customizado sem
CBUFFER_START(UnityPerMaterial)envolvendo as propriedades do material. Selecione o shader no Project e veja no Inspector se aparece "SRP Batcher: compatible". - MaterialPropertyBlock: o manual avisa que usá-lo remove a compatibilidade com o SRP Batcher. No URP, para mudar cor por objeto, prefira materiais diferentes.
- Variantes diferentes: o mesmo shader com keywords diferentes (normal map ligado num material e desligado em outro) vira variantes diferentes e quebra o lote.
Shaders do próprio URP (Lit, Simple Lit, Unlit) e os gerados pelo Shader Graph já saem compatíveis. O problema costuma aparecer com shader escrito à mão ou importado de asset antigo feito para a Built-In Render Pipeline, que a Unity marcou como descontinuada no Unity 6.5. Antes de comprar um pacote de shaders na Asset Store, confira na página se ele declara suporte a URP e SRP Batcher.
Static batching
Para objetos que nunca se movem (cenário, prédios, pedras), marque Static (ou só Batching Static no menu da caixa Static) no Inspector. Na build, a Unity combina as malhas que compartilham material em malhas grandes e desenha em poucos lotes.
Custo: memória extra, porque as malhas combinadas são guardadas. Objeto estático que se move depois deixa de ser desenhado no lugar certo. Funciona bem com SRP Batcher: na ordem de prioridade do manual, malhas estáticas usam static batching primeiro.
GPU instancing e por que não soma com SRP Batcher
GPU instancing desenha muitas cópias da mesma malha com o mesmo material num único draw call, passando posições e dados por instância. Ideal para grama, árvores, projéteis, multidões. Ative em Enable GPU Instancing no material.
A pegadinha: o manual do Unity 6.3 descreve a ordem em que os métodos são aplicados quando vários estão disponíveis:
- Malhas estáticas usam static batching.
- Malhas dinâmicas com shader compatível usam SRP Batcher (com o GPU Resident Drawer ou a API BatchRendererGroup, quando ligados).
- As restantes com shader compatível usam GPU instancing.
- O resto usa dynamic batching, se estiver ligado.
Como o URP Lit é compatível com SRP Batcher, marcar Enable GPU Instancing nele não muda nada: o objeto já foi pego no passo 2. A página de GPU instancing do manual confirma que, com shader customizado no URP, instancing só funciona com o SRP Batcher desligado. Na prática, no URP do Unity 6 o caminho para instanciar automaticamente é o GPU Resident Drawer.
GPU Resident Drawer no Unity 6
O GPU Resident Drawer usa a API BatchRendererGroup para desenhar objetos com MeshRenderer por instancing, automaticamente, sem você mudar material. Requisitos segundo o manual do URP no Unity 6.3:
- Caminho de renderização Forward+ no Universal Renderer.
- API gráfica com compute shader, exceto OpenGL ES.
- Objeto com Mesh Renderer, sem script de callback por instância (como
OnRenderObject) e semMaterialPropertyBlock. - Em Project Settings > Graphics > Shader Stripping, BatchRendererGroup Variants: Keep All (a build fica mais demorada).
- No URP Asset, SRP Batcher ligado e GPU Resident Drawer: Instanced Drawing.
O mesmo manual sugere desligar Static Batching em Project Settings > Player > Other Settings quando o GPU Resident Drawer está ativo, porque isso pode acelerar o drawer. Para excluir um objeto, adicione o componente Disallow GPU Driven Rendering. Ele brilha em cenas com muitas cópias da mesma malha. Em celular antigo com OpenGL ES, não funciona.
Entender as quatro técnicas é a parte didática. Aplicar num jogo inteiro é outra coisa: decidir atlas de textura, organizar prefabs, combinar arte e código para não precisar desmontar tudo no fim do projeto. Essa visão de produção, juntando arte, cena e script, é onde quem aprende sozinho mais tropeça.
Teste prático: 500 objetos
Rode este experimento numa cena vazia do URP. Arquivo BatchingTestSpawner.cs:
using UnityEngine;
public class BatchingTestSpawner : MonoBehaviour
{
[SerializeField] private GameObject prefab;
[SerializeField] private Material[] materials;
[SerializeField] private int count = 500;
[SerializeField] private float spacing = 1.5f;
[SerializeField] private bool useInstancedMaterials;
private void Start()
{
int side = Mathf.CeilToInt(Mathf.Sqrt(count));
for (int i = 0; i < count; i++)
{
Vector3 position = new Vector3((i % side) * spacing, 0f, (i / side) * spacing);
GameObject go = Instantiate(prefab, position, Quaternion.identity, transform);
MeshRenderer meshRenderer = go.GetComponent<MeshRenderer>();
Material chosen = materials[i % materials.Length];
if (useInstancedMaterials)
{
meshRenderer.material = chosen;
meshRenderer.material.color = Random.ColorHSV();
}
else
{
meshRenderer.sharedMaterial = chosen;
}
}
}
}
O prefab é um cubo com MeshRenderer. Crie 4 materiais com o shader URP Lit em cores diferentes e arraste para o array. Rode cada configuração e anote Batches, SetPass calls e o tempo de renderização no Profiler:
- SRP Batcher ligado,
useInstancedMaterialsdesligado: o Frame Debugger mostra poucos eventos SRP Batch, mesmo com 4 materiais, porque o shader é o mesmo. - SRP Batcher desligado (no URP Asset): compare o número de Batches e SetPass calls com o caso 1.
useInstancedMaterialsligado: cada cubo ganha seu próprio material. Veja o que acontece com o SRP Batcher (continua agrupando) e com a memória.- GPU Resident Drawer ligado (com Forward+, os requisitos acima e
useInstancedMaterialsdesligado): os cubos que compartilham cada um dos 4 materiais passam a ser desenhados por instancing. - Cubos marcados como Static em vez de instanciados por script, com o GPU Resident Drawer desligado: veja o static batching assumir.
O ponto do teste não é um número mágico, que muda de máquina para máquina, mas ver no Frame Debugger qual mecanismo pegou cada objeto e por quê.
Erros comuns: material instanciado por script
renderer.materialem vez derenderer.sharedMaterial: acessar.materialcria uma cópia só para aquele objeto. Quebra static batching e GPU instancing, gasta memória e a cópia não é destruída sozinha quando o objeto some. Use.sharedMaterialquando não quer cópia.- Trocar por MaterialPropertyBlock "para otimizar": no URP, isso tira o objeto do SRP Batcher. Prefira um material por variação.
- Ligar Enable GPU Instancing no URP Lit e esperar ganho: o SRP Batcher tem prioridade.
- Marcar como Static um objeto que se move: ele fica preso na posição combinada.
- Keywords diferentes por material: dois materiais Lit, um com normal map e outro sem, são variantes diferentes. Padronize.
- Contar Batches e esquecer SetPass calls: no URP, SetPass calls costuma ser o indicador mais útil.
Próximo passo
Abra o Frame Debugger na cena mais pesada do seu jogo e anote os três motivos mais frequentes de "não agrupado". Corrija o primeiro, meça no Profiler e repita. Se você ainda não sabe se o gargalo é CPU ou GPU, comece pelo post sobre o Profiler da Unity. Para a teoria geral de performance, leia otimização para 60 FPS, e se você também mexe com Godot, o conceito equivalente ao instancing está em MultiMesh no Godot.
Perguntas frequentes
O que é SetPass call na Unity?
É uma troca de estado de renderização, normalmente de shader ou de passe de shader. O painel Stats da Game View mostra Batches e SetPass calls separados. No URP com SRP Batcher, os SetPass calls costumam ser o número que mais pesa na CPU, porque o batcher já barateia os draw calls de mesmo shader.
GPU instancing funciona junto com SRP Batcher?
Não no mesmo objeto. Segundo o manual do Unity 6.3, quando um objeto é compatível com os dois, a Unity usa o SRP Batcher, e o GPU instancing com shader customizado só funciona com o SRP Batcher desligado ou com o objeto tornado incompatível. O GPU Resident Drawer é o caminho do Unity 6 para instanciar automaticamente no URP.
Como ver os draw calls na Unity?
Abra o painel Stats no canto da Game View para ver Batches e SetPass calls, e use Window > Analysis > Frame Debugger para ver cada evento de desenho do frame. O Frame Debugger também diz por que dois objetos não foram agrupados.
Usar renderer.material num script quebra o batching?
Cria uma cópia do material para aquele objeto. Isso quebra static batching e GPU instancing e gasta memória, e no URP o SRP Batcher ainda agrupa porque o shader é o mesmo. O pior caso é trocar por MaterialPropertyBlock, que remove a compatibilidade com o SRP Batcher.

