From a428cba41aeab8934f1799e7788824ca1e3276f9 Mon Sep 17 00:00:00 2001 From: iris <2+iris@noreply.localhost> Date: Wed, 9 Sep 2026 11:34:30 -0400 Subject: [PATCH] iris: record the streamed-row redraw as an open item arena_churn says a streamed frame uploads 72.7% of the instance arena and that this is the floor, against 3.3% for a fling over the same content -- so the rows are being redrawn where a scroll would write one move_offsets delta. The upload half landed in 3c7d3db; this is the layout half, with the measurement, the control that makes it convincing, and where to look first. --- docs/IRIS_TODO.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs/IRIS_TODO.md b/docs/IRIS_TODO.md index 41575f6..f087aa8 100644 --- a/docs/IRIS_TODO.md +++ b/docs/IRIS_TODO.md @@ -12,6 +12,41 @@ and six phone-report sections went on 2026-09-08 for that reason. ## Fix +- [ ] **A row moving because the list grew should be one `move_offsets` + write, and today it is a redraw.** Found 2026-09-09 by + `scripts/rigs/ui-profile`'s `arena_churn` and left for whoever picks + this up next; the upload half of it is done and this is the layout + half. + + The measurement. Over the bench fixture's 401 streamed deltas, the + instance arena uploads **72.7%** of itself per frame, and that number + *is* the floor -- those entries genuinely differ, so no amount of + better dirty-tracking touches it. The control that says it is wrong is + the fling phase on the same screen and the same content: it moves the + same primitives every frame and uploads **3.3%**, because a scroll + reaches `UiRenderState::mov` and writes one `move_offsets` delta for + the subtree (LAYOUT.md section 2) instead of rewriting every + primitive's absolute region. + + What is different about the streaming path. The list is pinned to the + newest end, so a growing reply pushes every row above it up by the + amount the last row grew. That is a translation of an already-drawn + subtree -- exactly what `move_offsets` is for -- but it arrives as a + new offered region per row, and `draw_inner`'s fast path only takes + `mov` when `active.region.size() == region.size()`. Worth checking + first: whether `LazySpan::place` is offering each row a region whose + *size* differs (it computes `edges(height)` fresh each frame, so an + identical height should compare equal -- unless a float differs in the + last bit, which the `// TODO: epsilon?` beside that comparison already + suspects), or whether something upstream marks the rows dirty so the + fast path is skipped entirely. + + Done looks like: `arena_churn`'s `what_a_streamed_reply_uploads` shows + stream instances in the same range as the fling's, and its `whole` + column stops being the interesting one. The rig prints floor, + uploaded and whole per array precisely so this is checkable rather + than argued. + - [ ] **Where the scroll *pin* lives.** The rest of "scrolling moves out of the list" landed on 2026-09-08 -- `List` is `LazySpan`, the physics and the gesture live in one `ScrollController`, `.scrollable()` is the