Redesign span layout around retained placement
This commit is contained in:
1 parent
ae0af8f5e3
commit
0aa03cf621
30 files changed
+501
-1321
No files matched your search
+12
-29
@@ -650,8 +650,7 @@ strategy alone. Three things, in the order they had to be fixed:
|
||||
dirty. This alone took the glyph array from 95% re-uploaded to 3%.
|
||||
2. **A redraw freed its primitives and pushed new ones.** Freed slots are
|
||||
not reusable until the end of the frame (a layer's draw order still
|
||||
names them), and `Painter::draw_twice` -- how a container learns a
|
||||
child's size, and containers nest -- meant the arena's high-water was
|
||||
names them), and nested provisional layout meant the arena's high-water was
|
||||
the *transient* push count: 17 million pushes across 401 deltas, and
|
||||
127,443 slots for 11,569 live primitives, growing linearly with the
|
||||
transcript. A redraw now gets its old handles back as a recycle pool
|
||||
@@ -674,36 +673,20 @@ changed. `PrimitiveVec::set` and `Primitives::set_instance` compare before
|
||||
marking, and `arena_churn` prints both numbers so the gap cannot reopen
|
||||
unnoticed.
|
||||
|
||||
**A measurement is a mode, not a discarded draw (added later the same
|
||||
day).** `Painter::draw_twice(child, first, |used| second)` became
|
||||
`Painter::measure` + an ordinary draw, at Iris's request: her objection
|
||||
was the shape it forced on the caller, since the arithmetic that picks
|
||||
the real region had to happen inside a closure and anything it wanted to
|
||||
keep came back out through a captured `&mut`. Two statements now say it
|
||||
in the order it happens.
|
||||
**Layout has no measurement mode.** A widget is drawn provisionally only
|
||||
when its size cannot be known yet, and that retained drawing is moved into
|
||||
place. `Widget::size_hint(axis)` lets context-free wrappers such as `Sized`
|
||||
report an exact `Len`; a debug assertion compares every hint with the real
|
||||
draw result. If final allocation changes a child's size, `Painter::place`
|
||||
redraws it in that box. Otherwise placement is one move-offset write.
|
||||
|
||||
`DrawMode::Measure` is that draw with everything it *writes* switched
|
||||
off -- no arena slot, no mask, no move slot, nothing left in `active`,
|
||||
nothing marked dirty -- so the real draw that follows is an ordinary one
|
||||
and cannot be short-circuited by the measurement having "already drawn"
|
||||
the widget at that region. A `debug_assert` at the end of `draw_inner`
|
||||
catches a `Painter` method that forgets to check the mode, because the
|
||||
failure would otherwise be one leaked primitive per measured widget per
|
||||
frame.
|
||||
|
||||
The amplification this removes, measured: a streamed frame makes **1,083
|
||||
`Widget::draw` calls over 113 distinct widgets**, and the worst widgets
|
||||
are drawn **11 times** at nesting depth 7-8. It is not two draws, it is
|
||||
two to the power of how many measuring ancestors a widget has. Only the
|
||||
*writes* go away, not the traversals -- the walk and the region
|
||||
arithmetic still happen 11 times, and removing those needs a size that
|
||||
can be answered without drawing, which is what LAYOUT.md section 5 rules
|
||||
out. Worth what it cost: the streamed frame went p50 1.39ms -> 1.22ms
|
||||
and p99 4.75ms -> 3.58ms, and the upload numbers did not move, because
|
||||
recycling had already made the discarded writes free in arena terms.
|
||||
Measured over the fixture's 401 streamed events: the busiest frame makes
|
||||
176 `Widget::draw` calls and the worst widget is called four times.
|
||||
Streamed-frame CPU p50 is 0.35ms, from 1.18ms before this layout change.
|
||||
Arena size and upload floors are unchanged.
|
||||
|
||||
**What is left, and it is a layout question rather than an upload one.**
|
||||
Stream instances upload 72.7%, which *is* the floor: the list is pinned to
|
||||
Stream instances upload 71.9%, against a 71.8% floor: the list is pinned to
|
||||
the newest end, so a growing reply moves every row, and a row's instances
|
||||
carry an absolute region. Moving a subtree is supposed to be one
|
||||
`move_offsets` write (LAYOUT.md section 2); something on this path is
|
||||
|
||||
Reference in new issue
Block a user