This page was machine-translated from Portuguese and may contain errors. The Portuguese version is canonical.
The rendering pipeline
Understanding how drawing becomes pixels explains several of the framework’s performance rules.
The drawing layers
Paintis the facade you draw with inonPaint(...). It thinks in local coordinates, clip, and translation — and knows nothing about shaders or OpenGL. You say “draw this rectangle here”; how that becomes triangles and GPU calls is not your problem.gl/ renderers — there is one specialized renderer per primitive (rectangle, rounded rectangle, line, text, image…), each essentially a shader.Paintdelegates to the right renderer.- OpenGL — the final draw calls.
The central concept: batching
Renderers group drawings of the same type into a batch to reduce GPU calls. The rule that follows from this:
Switching primitive type “closes” the previous batch. Drawing order is always preserved, but alternating types (rectangle → text → rectangle → text) forces multiple flushes; grouping calls of the same type is what gives performance.
In practice, in heavy custom drawing, drawing all rectangles together and then all text yields more than interleaving them.
On-demand render + whole-tree repaint
Two properties of the render model that affect how you write onPaint:
- On demand: the screen only redraws when someone requests it (
repaint()→requestRendering()). Without a request, no new frame is generated — it saves battery. (The threading angle of this is in The paint thread.) - No dirty rectangles: when a frame happens, the entire visible tree is repainted, not just the part that changed. There is no partial repaint.
The practical consequence is a principle:
Keep
onPaintcheap. It runs for the entire tree on every rendered frame — no allocating objects, loading resources, or doing expensive computation inside it.
How the frame is assembled (high-level view)
On each rendered frame, the EventsProcessor paints the window stack (via paintWindows(...)): the
topmost window on top, the ones below behind (popups leave the previous one visible). Each visible component
receives its onPaint(Paint).
// minimal, cheap onPaint: reuse temporaries, draw in local coords (0,0 = top-left)
@Override public void onPaint(Paint paint) throws Exception {
paint.rect(scratch.bounds(0, 0, width, height).fill(bg)); // 'scratch' is a reused GRect
}
See also
- Apply: Custom drawing
- Next: The paint thread