What a frame costs
A native window is up in a tenth of a second, a settled frame costs microseconds, and this page says where the rest of the time goes.
Read this page to know which numbers to expect from a Goldberry window and where each one was measured. The three chapters after it say how to start fast, how to keep a frame cheap, and how to measure your own application rather than trust these figures.
Every number above comes from a record in the decision log, and the table below says which.
| Number | What it measures | Record |
|---|---|---|
| 519 ms, 116 ms | The showcase’s native image, median of 7 runs, timed from exec. The window is open at 116.2 ms in the run the record prints | ADR-0506 |
| 1980 ms, 1340 ms | The showcase on the JVM, cold and with an AOT cache, median of 5 runs | ADR-0506 |
| 3.13 ms, 4.28 ms | Median and 95th percentile of a 960×640 frame with text, paced to the display | Status, M1, from the pacing in ADR-0047 |
| 2.3 ms | A 3840×2160 paint in PaintBenchmark, down from 6.0 ms on one thread | ADR-0042 |
| 117 µs | One small box changed at 960×640, repainted inside its damage, down from 367 µs | ADR-0072 |
| 9.1 µs | Layout and the walk on a showcase-shaped tree when nothing changed, down from 190 µs | ADR-0069 |
The frame loop
One UI thread runs the loop. Blend2D’s workers rasterize the bands. This is
the pipeline from docs/ARCHITECTURE.md §5, in the order a frame runs it:
input events → dispatch (hit-test on render tree)
→ rebuild dirty widgets → diff → update elements/render objects
→ style resolution (invalidated nodes) → Yoga layout (incremental)
→ paint recording (dirty layers only) → Blend2D raster (banded)
→ present(buffer, damage) / GPU composite
Three trees take part. Widgets are immutable records that describe. Elements persist and hold state. Render objects own the Yoga nodes and are kept between frames, so a frame diffs a new description against a retained tree rather than building one. The architecture overview has the full picture.
Where the time goes at 960×640
Everything before rasterization is now a rounding error. Rasterization and present are the frame.
| Stage | Cost | Record |
|---|---|---|
| Everything but rasterization, nothing changed | 3.5 µs, down from 354 µs | ADR-0070 |
| Rasterization on one thread | about 320 µs | ADR-0070 |
| Paint in a live window, four workers | 2.146 ms, from 2.856 ms synchronous | ADR-0042 |
| Present, unpaced | about 6.4 ms, of which 4.8 ms is blocking on the swapchain and 43 µs is this repository’s code | ADR-0046 |
| Present, paced to the display | 1.20 ms, with paint falling to 1.61 ms beside it | ADR-0047 |
Read the paint row with care. The same scene paints in 0.34 ms in a benchmark
loop and in 2.15 ms in a running window, because present leaves the next
paint’s caches cold. Only a figure from a live window says what a frame costs.
Measuring explains the gap.
Note
Every number on this page was measured on one Linux machine. The run that would repeat the frame benchmarks on Linux, macOS and Windows is open, and the status page says what each platform’s CI leg has reported so far. See the frame evidence.