The layer tree
what can move alone
Blink does not hand the compositor pixels or paint commands — it hands it a tree of layers. A layer is a thing that can be moved, scaled or faded independently of everything around it. Which elements get their own layer is the decision that determines what can be animated without waking the main thread.
will-change: transform // promote to a layer
Main thread & compositor thread
the split
The main thread runs script, style, layout and paint. The compositor thread holds a committed copy of the layer tree and can keep producing frames from it on its own. That copy is the entire reason a page stuck in a long task still scrolls smoothly under your finger.
LayerTreeHost (main) ⇄ LayerTreeHostImpl (impl)
Tiling & raster
paint ops → pixels
A layer larger than the screen is cut into tiles, and only the tiles near the viewport are rastered, on worker threads or on the GPU. Priorities come from how close a tile is to being visible and how fast you are moving towards it. A checkerboard is a tile that missed its deadline.
visible → soon-visible → eventually → skip
Compositor frames
quads, not pixels
The compositor does not draw to the screen. It submits a CompositorFrame: a list of quads, each a transform plus a reference to an already-rastered texture. Producing one is cheap, and re-submitting the same one with a different transform is cheaper still — which is what a scroll actually is.
CompositorFrame { render_passes, quads }Viz, the display compositor
in the GPU process
Every client — each renderer, the browser’s own UI — submits its frame to Viz, which aggregates them into one frame for the screen and draws it through Skia. It owns the vsync deadline, decides how long to wait for a late client, and is the last place anything can still be dropped.
components/viz/service/display/
Scroll & animation off-thread
why transform is cheap
Scroll offsets and animations of transform and opacity are handled entirely on the compositor thread, because neither changes any pixel that was already rastered — only the matrix a quad is drawn with. Animate top or width instead and you have asked for layout, on the main thread, every frame.
transform / opacity → compositor
top / width / color → main thread