AwtCanvasVideoRenderer
Draws frames onto an AWT canvas, on a thread of its own.
Why this exists next to the Compose renderer
Compose draws the whole window as one scene on one clock, so heavy UI work delays the picture. This renderer paints a heavyweight AWT canvas from its own thread through a BufferStrategy, which the window server presents independently. Measured 2026-08-30: with the Compose frame clock choked to 8 percent of its rate, a canvas painted this way kept 100 percent of its own.
The ownership rule that matters most
Every frame handed to present is closed exactly once, on every path including refusal. A leak here is 3.11 MB per 1080p frame, so the paths that refuse are the ones worth reading: no canvas, no peer yet, a zero-sized canvas, a painter that declines the frame, a closed renderer, and a frame superseded by a newer one while the painter was busy. Each closes and counts.
Where the painting happens, said plainly because it is easy to assume otherwise
present converts and paints on the thread that calls it, which is the engine's video scheduler, exactly as the Android surface renderer does. That is already independent of Compose, which is the decoupling this path exists for; it is NOT independent of the engine, and a slow present slows the schedule that called it. There is no queue and no painter thread here, so nothing is ever superseded inside this renderer and supersededFrames stays zero: the counter exists because the view's ledger sums one number across every renderer it builds, and a renderer with nothing to report reports nothing rather than being absent from the sum.
Every member may be called from any thread, and the engine does so: present on its video scheduler, setOverlay on the subtitle raster lane and the actor, the picture controls on the actor, and a resize on the AWT event thread. One paint lock serialises every draw, and setCanvas and close take it too, so a canvas handed back is fenced from the paint in flight.
Properties
The canvas in device pixels: its size times the scale of the screen it is on. The engine lays subtitles out for this size, rule 2 of docs/subtitle-placement.md, and the presenter draws them back at one overlay pixel to one device pixel. Null before a canvas with a size exists.
Functions
Forgets the retained picture and paints the background with the cues over it (#530). There is no queue here, so the retained picture is the only frame there is to forget.
No hardware surface: the painter converts every frame on the CPU, a hardware frame through its downloaded copy.