O pipeline de renderização
Entender como o desenho vira pixels explica várias regras de performance do framework.
As camadas do desenho
Painté a fachada com que você desenha emonPaint(...). Ela pensa em coordenadas locais, clip e translação — e nada sabe de shaders ou OpenGL. Você diz “desenhe este retângulo aqui”; como isso vira triângulos e chamadas de GPU não é problema seu.gl/ renderizadores — há um renderizador especializado por primitiva (retângulo, retângulo arredondado, linha, texto, imagem…), cada um essencialmente um shader. OPaintdelega para o renderizador certo.- OpenGL — as draw calls finais.
O conceito central: batching
Renderizadores agrupam desenhos do mesmo tipo em lote (batch) para reduzir chamadas de GPU. A regra que decorre disso:
Trocar de tipo de primitiva “fecha” o batch anterior. A ordem de desenho é sempre preservada, mas alternar tipos (retângulo → texto → retângulo → texto) força vários flushes; agrupar chamadas do mesmo tipo é o que dá desempenho.
Na prática, em desenho custom pesado, desenhar todos os retângulos juntos e depois todos os textos rende mais que intercalar.
Render sob demanda + repintura de árvore inteira
Duas propriedades do modelo de render que afetam como você escreve onPaint:
- Sob demanda: a tela só redesenha quando alguém pede (
repaint()→requestRendering()). Sem pedido, nenhum frame novo é gerado — economiza bateria. (O ângulo de threading disso está em A paint thread.) - Sem dirty rectangles: quando um frame acontece, toda a árvore visível é repintada, não só a parte que mudou. Não há repintura parcial.
A consequência prática é um princípio:
Mantenha
onPaintbarato. Ele roda para a árvore inteira a cada frame renderizado — nada de alocar objetos, carregar recursos ou fazer cálculo caro dentro dele.
Como o frame é montado (visão de alto nível)
A cada frame renderizado, o EventsProcessor pinta a pilha de janelas (via paintWindows(...)): a
janela do topo por cima, as de baixo atrás (popups deixam a anterior visível). Cada componente visível
recebe seu onPaint(Paint).
// onPaint mínimo e barato: reaproveite temporários, desenhe em coords locais (0,0 = topo-esquerda)
@Override public void onPaint(Paint paint) throws Exception {
paint.rect(scratch.bounds(0, 0, width, height).fill(bg)); // 'scratch' é um GRect reutilizado
}
Veja também
- Aplicar: Desenho customizado
- Próximo: A paint thread