Describe Flutter's rendering pipeline from frame start to pixel output.
TL;DR: Flutter's rendering pipeline: vsync signal → build (widget tree diff) → layout (constraints/sizes) → paint (canvas commands) → composite (layers) → rasterize (GPU) → display.
Full Answer
Every frame begins with a vsync signal from the device display (typically 60/90/120Hz). Flutter's SchedulerBinding processes this signal and drives the rendering pipeline.
- ▸1. Build phase: Dirty elements rebuild their widget trees (setState, provider changes)
- ▸2. Layout phase: RenderObjects receive constraints and compute sizes (performLayout)
- ▸3. Compositing bits phase: marks which layers need compositing
- ▸4. Paint phase: RenderObjects emit canvas draw calls into a PictureLayer
- ▸5. Composite phase: SceneBuilder assembles layers into a Scene
- ▸6. Rasterize phase: Scene sent to GPU (Skia or Impeller) via dart:ui
- ▸7. Display: GPU renders pixels to the screen
Impeller (Flutter's new rendering backend, default on iOS since Flutter 3.10, Android preview) pre-compiles shaders at startup, eliminating the shader compilation jank that plagued Skia.
The Flutter DevTools Timeline view shows each phase. Look for 'Build', 'Layout', 'Paint', and 'Raster' spans. Long raster spans indicate GPU bottlenecks; long build spans indicate widget rebuild issues.
Code Examples
Frame rendered! Widget size: Size(375.0, 56.0)
Common Mistakes
- ✗Performing heavy computation during the build phase — use compute() or isolates
- ✗Trying to access RenderBox size in build() — layout hasn't run yet; use addPostFrameCallback
Interview Tip
Mentioning Impeller and the shader precompilation problem it solves shows you follow Flutter's development roadmap closely.