render: walk only the marked rows to prime and shape glyphs #431
No reviewers
Labels
No labels
priority/P0
priority/P1
priority/P2
release/v0.1.0
status/blocked
status/planned
type/bug
type/design
type/test-gap
type/tracker
No milestone
No project
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
natsukium/felis!431
Loading…
Reference in a new issue
No description provided.
Delete branch "render/incremental-populate"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #422
The glyph populate walk now visits only the rows the shadow marked, and keeps the shape results (
ShapeFrame) of the other rows across frames. Row rotation for scrolls, the issue's second part, does not pay with the traffic the client receives today; the evidence is in a comment on #422.What changed
GridWalker::walk(crates/felis-render-wgpu/src/glyphs.rs) walksscreen.damage().dirty_rows()while the index's key from its last complete walk (rows, cols, whether the shaper runs) still holds, and every row otherwise. Every atlas recycle drops the key, including one caused by overlay priming between frames, and so does the retry after a mid-walk recycle. A font, size or feature reload rebuilds the index, which starts with no key.RowDeltas, which mark their rows.GlyphCache, with no GPU dependency, so tests can drive it against a bareGlyphIndex. The property testwalking_the_marked_rows_matches_a_full_walk(glyphs/walk_tests.rs) applies random writes, clusters, sized cells, scroll directives, resizes, style sweeps and overlay priming. It runs with and without features, and under atlases small enough to recycle. After each frame, the kept frame must equal a from-scratch walk, and the atlas must already hold every glyph a full walk primes. Removing the recycle's key reset, the row clear, the compaction or the key check each makes it fail.TableGc::sweep(#432).Measurements
Linux, NVIDIA, release builds, 212x93, interleaved with origin/main (
43ac9b14), three runs each, load 6 to 19 on a shared host. Frame build+upload was timed as in #424. Populate is timed separately and covers the grid walk and overlay priming.seqscroll floodA keystroke frame's populate plus build+upload goes from about 150 us to about 75 us. The flood does not change, because every frame marks every row.
just checkpasses locally. pi review (sol): PASS on the first round.With the row cache in place, the glyph populate walk was the one whole-grid cost left on a keystroke: it read, and with features or clusters shaped, every cell to prime atlas slots and rebuild the shape frame, although only the echoed row changed. At 212x93 it took more time than building and uploading the frame's instances. The walk now visits the rows the shadow marked and keeps the shape frame's entries for the rest. That holds only while nothing moved the slots or the frame's layout under them, so the index keeps the key of its last complete walk (rows, cols, whether the shaper runs) and drops it on every atlas recycle, including one an overlay's priming causes between frames; a missing or different key walks every row, as does the retry after a mid-walk recycle. A font, size or feature change rebuilds the index and so starts from no key. The frame-wide paint inputs the row cache also keys on (viewport, selection, pre-edit, chrome rows, reverse video) change pixels, not glyphs, so they leave the walk incremental. Clusters re-walked in place leave stale glyphs in the frame's shared pool; the pool is rewritten once they outnumber the live ones two to one (floor 4096), so it stays bounded without per-row pools, which would have changed the offsets the painter and its tests use. The walk moves into a GPU-free GridWalker so the property test can drive it against a bare GlyphIndex: after random writes, clusters, sized cells, scrolls, resizes, style sweeps and overlay priming, with and without features and under atlases small enough to recycle, the kept frame must equal a from-scratch walk and the atlas must already hold every glyph a full walk primes. Linux, NVIDIA, release, 212x93, interleaved with origin/main, three runs each, load 6 to 19 (a shared host): one key every 50 ms populate median 63/80/101 us -> 3.8/4.1/5.0 us build+upload median 66-75 us on both seq scroll flood every frame marks all 93 rows; populate 94-116 us on both, unchanged so a keystroke frame's populate plus build+upload goes from about 150 to about 75 us. Assisted-by: Claude Code