iris: count text layouts, so "a delta shapes one block" is measured rather than argued
take_counters gains a fourth counter, text shapes, bumped in Painter::render_text -- which TextView::render only reaches on a cache miss, so it counts shapes and not requests. A draw counter cannot stand in for it in either direction: a widget can be redrawn without re-shaping (the layout is memoized by width) and re-shaped without any extra draw, and re-shaping is the whole thing the per-block transcript row exists to avoid. With it, a_delta_into_a_long_reply_redraws_the_same_widgets_as_a_short_one asserts the number docs/DECISIONS.md's 2026-09-06 entry actually claims: one delta into a 100-paragraph reply shapes exactly one text layout, the same as into a one-paragraph one. Before the split that was necessarily O(message), since the reply was one buffer. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
155d899e55
commit
c3cfc67bb3
6 files changed
+43
-15
No files matched your search
@@ -191,6 +191,10 @@ impl<'a> Painter<'a> {
|
||||
width: Option<f32>,
|
||||
) -> RenderedText {
|
||||
let density = self.state.density;
|
||||
// Counted here rather than in `TextView::render`, which returns
|
||||
// its memoized layout without reaching this -- so this counts
|
||||
// shapes, not requests. `UiRenderState::take_counters`.
|
||||
self.state.shape_count += 1;
|
||||
let ui = self.rsc.ui_mut();
|
||||
ui.text
|
||||
.render(buffer, attrs, width, &mut ui.textures, density)
|
||||
|
||||
@@ -55,6 +55,9 @@ pub struct UiRenderState {
|
||||
draw_count: u64,
|
||||
region_mut_count: u64,
|
||||
mov_count: u64,
|
||||
/// Text layouts actually computed -- bumped by `Painter::render_text`,
|
||||
/// which `TextView::render` only reaches on a cache miss.
|
||||
pub(super) shape_count: u64,
|
||||
}
|
||||
|
||||
/// A move chain more than this deep would mean something else is wrong
|
||||
@@ -76,17 +79,25 @@ impl UiRenderState {
|
||||
draw_count: 0,
|
||||
region_mut_count: 0,
|
||||
mov_count: 0,
|
||||
shape_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads and zeroes the (draws, region_mut rewrites, move_offsets
|
||||
/// writes) counters -- call once per frame before `update()` to
|
||||
/// measure exactly that frame, per LAYOUT.md section 8.
|
||||
pub fn take_counters(&mut self) -> (u64, u64, u64) {
|
||||
/// writes, text shapes) counters -- call once per frame before
|
||||
/// `update()` to measure exactly that frame, per LAYOUT.md section 8.
|
||||
///
|
||||
/// The fourth is the one a draw count cannot stand in for: a widget
|
||||
/// can be redrawn without re-shaping (`TextView::render` memoizes by
|
||||
/// width) and re-shaped without any extra draw, and it is re-shaping
|
||||
/// that the per-block transcript row exists to avoid -- see
|
||||
/// `transcript_ui`'s `a_delta_into_a_long_reply_shapes_one_block`.
|
||||
pub fn take_counters(&mut self) -> (u64, u64, u64, u64) {
|
||||
(
|
||||
std::mem::take(&mut self.draw_count),
|
||||
std::mem::take(&mut self.region_mut_count),
|
||||
std::mem::take(&mut self.mov_count),
|
||||
std::mem::take(&mut self.shape_count),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user