Short answer
RenderObjects record drawing commands into geometric layers (ContainerLayer, PictureLayer), then the SceneBuilder merges them into a unified Scene that is sent through RenderView to the rasterizer thread to be processed on the GPU.
Explanation
RenderObjects are not drawn directly on the screen; instead, their output is deposited in a layer tree. This tree contains PictureLayers that record drawing commands as a display list, and ContainerLayers for clipping (ClipLayer), opacity (OpacityLayer), and geometric transformation (TransformLayer). At the end of the paint stage, RenderView calls compositeFrame(), which uses SceneBuilder to assemble these layers into a single Scene object. This scene is handed to the rendering engine on the rasterizer thread, where the GPU colors the pixels and displays them on screen.
Code example
import 'dart:ui' as ui;
import 'package:flutter/rendering.dart';
// What RenderView does after paint (simplified): flatten the layer tree into a Scene
ui.Scene buildScene(ContainerLayer rootLayer) {
final builder = ui.SceneBuilder();
rootLayer.addToScene(builder); // PictureLayer, OpacityLayer, TransformLayer… append themselves
return builder.build(); // the engine then hands the Scene to the rasterizer
}
// RepaintBoundary gives a subtree its own layer, so it can be repainted/cached independently
class Cached extends StatelessWidget {
const Cached({super.key, required this.child});
final Widget child;
@override
Widget build(BuildContext context) => RepaintBoundary(child: child);
}Common mistakes
- Confusing the UI thread, which executes Dart code and creates the layer tree, with the raster thread, which directs commands to the GPU.