Document per-axis retained layout
This commit is contained in:
1 parent
974d6c7a52
commit
ecce4448f0
2 files changed
+43
-14
No files matched your search
@@ -9,7 +9,7 @@ Canonical `main` is **`ca2b4b2`** (#17, the headless rig). Sixteen slices are
|
|||||||
in.
|
in.
|
||||||
|
|
||||||
**#18 `split/18-position-chain`** is open and finished apart from one decision:
|
**#18 `split/18-position-chain`** is open and finished apart from one decision:
|
||||||
worktree `/home/bob/repos/iris-pr18`, head `82fa6c1`, seventeen commits,
|
worktree `/home/bob/repos/iris-pr18`, head `b1b3eca`, eighteen commits,
|
||||||
workspace tests passing, fmt and clippy clean. It is LAYOUT.md §2's position chain, generalised
|
workspace tests passing, fmt and clippy clean. It is LAYOUT.md §2's position chain, generalised
|
||||||
to boxes. `/home/bob/repos/ai-app-2` is on `rustify`, worktree clean.
|
to boxes. `/home/bob/repos/ai-app-2` is on `rustify`, worktree clean.
|
||||||
|
|
||||||
@@ -217,9 +217,24 @@ hottest texts draw 32 times. Instrumented layout is about 5.5 ms instead of
|
|||||||
60.79B instructions total (60.8M/frame), and 23.85B cycles. This is about 58%
|
60.79B instructions total (60.8M/frame), and 23.85B cycles. This is about 58%
|
||||||
fewer instructions than the roughly 138M/frame #18 path before coalescing,
|
fewer instructions than the roughly 138M/frame #18 path before coalescing,
|
||||||
but still about 1.8x the old 3.14 ms resize median. The remaining multiplier
|
but still about 1.8x the old 3.14 ms resize median. The remaining multiplier
|
||||||
is within one constraint traversal, so per-axis retained size validity is now
|
is within one constraint traversal. Re-sending the existing output size also
|
||||||
the useful next question. Re-sending the existing output size also no longer
|
no longer starts a resize.
|
||||||
starts a resize.
|
|
||||||
|
`b1b3eca` records pixel reads and retained size inputs per axis. `Text` says it
|
||||||
|
reads only its offered width, while `Scroll` says it reads only its scrolling
|
||||||
|
axis. `Span`, `Aligned`, and `Scroll` ask for an exact hint or a retained child
|
||||||
|
length valid under the box they are about to offer, and draw to measure only
|
||||||
|
when neither exists. On the same depth-8 load, resize now averages 449 widget
|
||||||
|
draws, 296 placement calls, 485 drawn-size reads, 12,164 primitive writes, and
|
||||||
|
107 text shapes. Cached uninstrumented 1,000-frame runs measured 4.95–5.24 ms
|
||||||
|
medians, 55.4B instructions total (55.4M/frame), and 21.5–21.6B cycles: about
|
||||||
|
9% fewer instructions than `82fa6c1`, but still about 1.6x the old 3.14 ms
|
||||||
|
median.
|
||||||
|
|
||||||
|
Pixel comparisons now use a 0.05 physical-pixel tolerance. The comparison is
|
||||||
|
against the last actual layout, not the preceding resize event or retained
|
||||||
|
move, so repeated subpixel changes accumulate and eventually redraw. The
|
||||||
|
generated cold-layout oracle uses the same visual tolerance per coordinate.
|
||||||
|
|
||||||
The generated tree now includes `Aligned` with every meaningful per-axis
|
The generated tree now includes `Aligned` with every meaningful per-axis
|
||||||
alignment. That exposed two retained-layout ordering bugs which `84f589e`
|
alignment. That exposed two retained-layout ordering bugs which `84f589e`
|
||||||
@@ -227,7 +242,9 @@ fixes. The regular cold-layout equivalence suite and the ignored 100-seed
|
|||||||
sweep pass. The latter previously stopped at seed 60 on `140.0` versus
|
sweep pass. The latter previously stopped at seed 60 on `140.0` versus
|
||||||
`139.99996948242188`: exactly two `f32` ULPs from an equivalent composition
|
`139.99996948242188`: exactly two `f32` ULPs from an equivalent composition
|
||||||
order, not a visible layout difference. The oracle now keeps draw presence
|
order, not a visible layout difference. The oracle now keeps draw presence
|
||||||
exact and allows at most four ULPs per pixel coordinate.
|
exact and allows at most 0.05 physical pixels per coordinate. Seed 98 is also
|
||||||
|
part of the ordinary suite because it catches stale retained size beneath an
|
||||||
|
aligned size-changing chain.
|
||||||
|
|
||||||
The branches are invariants rather than widget exceptions:
|
The branches are invariants rather than widget exceptions:
|
||||||
|
|
||||||
@@ -255,6 +272,14 @@ stale-size failure. Re-measuring the scroll subtree costs 11 draws rather than
|
|||||||
1, but remains two orders of magnitude below the old 1,313 and follows the
|
1, but remains two orders of magnitude below the old 1,313 and follows the
|
||||||
actual dependency invariant.
|
actual dependency invariant.
|
||||||
|
|
||||||
|
A frame-local cache of several size answers under different constraint boxes
|
||||||
|
was also discarded. It reached about 3.5 ms in the instrumented resize rig,
|
||||||
|
but seed 98 showed that a valid answer is not enough: the child's one active
|
||||||
|
drawing may still realize another constraint, and a parent can then lay out
|
||||||
|
from an answer its final child placement does not realize. A correct version
|
||||||
|
needs an answer-plus-realization or verification protocol; adding dirtiness
|
||||||
|
conditions to the cache does not fix that invariant.
|
||||||
|
|
||||||
Do not restore the archive's old `DrawMode::Measure`. It skipped primitive and
|
Do not restore the archive's old `DrawMode::Measure`. It skipped primitive and
|
||||||
retained-state writes while still walking widgets and shaping text, and once
|
retained-state writes while still walking widgets and shaping text, and once
|
||||||
improved a streamed-frame benchmark from 1.39 to 1.22 ms p50. Retained
|
improved a streamed-frame benchmark from 1.39 to 1.22 ms p50. Retained
|
||||||
|
|||||||
+13
-9
@@ -106,8 +106,11 @@ stands rather than new machinery:
|
|||||||
and the primitive's stored `rel`/`abs` pair every frame, already, on the GPU.
|
and the primitive's stored `rel`/`abs` pair every frame, already, on the GPU.
|
||||||
A widget laid out purely in `rel`/`abs` terms is therefore already correct
|
A widget laid out purely in `rel`/`abs` terms is therefore already correct
|
||||||
after a resize with zero CPU work. Calls to `Painter::px_size` and
|
after a resize with zero CPU work. Calls to `Painter::px_size` and
|
||||||
`Painter::output_size` mark the active widget as reading concrete pixels;
|
`Painter::output_size` mark both concrete-pixel axes; `px_len(axis)` and
|
||||||
only those widgets become dirty when the output actually changes.
|
`output_len(axis)` mark only the axis actually read. Only widgets whose read
|
||||||
|
axes changed by more than 0.05 physical pixels become dirty. The comparison
|
||||||
|
is against each widget's last actual draw, so smaller changes accumulate
|
||||||
|
rather than disappearing event by event.
|
||||||
|
|
||||||
All pixel-dependent leaves are marked before layout begins, along with every
|
All pixel-dependent leaves are marked before layout begins, along with every
|
||||||
chain of parents that read their sizes. Resize then settles the shallowest
|
chain of parents that read their sizes. Resize then settles the shallowest
|
||||||
@@ -145,18 +148,19 @@ An exact `size_hint` stops propagation when both axes still equal the retained
|
|||||||
size. Otherwise propagation is deliberately conservative: the child may have
|
size. Otherwise propagation is deliberately conservative: the child may have
|
||||||
changed size, and only its dependent ancestors can assign the final boxes.
|
changed size, and only its dependent ancestors can assign the final boxes.
|
||||||
Unchanged descendants still take `draw_inner`'s retained skip-or-move path.
|
Unchanged descendants still take `draw_inner`'s retained skip-or-move path.
|
||||||
For a stacking container, retained child lengths are cached per axis: a child's
|
An active widget also retains which offered-box and output axes flowed into
|
||||||
width remains reusable while the parent changes width, and its height remains
|
the size it reported, directly or through a child size it read. A container
|
||||||
reusable while the parent changes height. A change on the orthogonal axis does
|
may use that answer for the same prospective box when every observed input is
|
||||||
invalidate it in both directions. This is a generic constraint rule, not a
|
still within 0.05 physical pixels; content dirtiness anywhere in its size
|
||||||
text exception; wrapped text is merely the common example of height depending
|
dependency subtree rejects the answer. This is a generic constraint rule, not
|
||||||
on width.
|
a text exception. Wrapped text is merely the common example: it reads width,
|
||||||
|
so changing only height leaves its answer valid.
|
||||||
|
|
||||||
### 4. Wrapped text, and "needs child height before choosing width"
|
### 4. Wrapped text, and "needs child height before choosing width"
|
||||||
|
|
||||||
**Wrapped text is not a special case any more; it already reads as one
|
**Wrapped text is not a special case any more; it already reads as one
|
||||||
draw.** `TextView::render` (`iris/src/widget/text/mod.rs:57-76`) already
|
draw.** `TextView::render` (`iris/src/widget/text/mod.rs:57-76`) already
|
||||||
does exactly what single-draw asks for: it reads `ctx.px_size().x` as the
|
does exactly what single-draw asks for: it reads `ctx.px_len(Axis::X)` as the
|
||||||
wrap width, shapes once, and memoizes the shaped layout keyed on that width
|
wrap width, shapes once, and memoizes the shaped layout keyed on that width
|
||||||
plus a changed-flag on the buffer and attrs (`:63-69`) — a second call with
|
plus a changed-flag on the buffer and attrs (`:63-69`) — a second call with
|
||||||
the same width is a hash-map-style cache hit, not a re-shape. Under the new
|
the same width is a hash-map-style cache hit, not a re-shape. Under the new
|
||||||
|
|||||||
Reference in new issue
Block a user