Carry the composed box down the draw, rather than walking back up for it
Every widget that reads its box in pixels was making `Moves` compose its slot's chain again, a mean of 2.8 levels, about eight hundred times a frame. A draw already descends past every one of those entries on its way in, so `DrawInfo` carries what the slot composes to and `draw_at` steps it one box further -- which is a select where it was a walk. `Moves::size_of` and `compose` are left for `redraw`, which starts mid-tree with nothing above it in flight. Measured on the fixed-shape fixture, seed 1 depth 8, 500 frames of `many`, medians of 25 runs, twenty-five work counters identical throughout: | | instructions | cycles | | --- | ---: | ---: | | `d21a215`, before exact composition | 1,908M | 760M | | `45a7176`, composing on the fine grid | 1,880M | 755M | | this | **1,840M** | **735M** | So exact composition ends up 3.6% fewer instructions and 3.3% fewer cycles than the rounding-per-level walk it replaced, and the widening it needed was paid for twice over by not doing the walk. `Holds::through`'s allowance does not move: two half steps is where shrinker seed 220 pins it, not where the arithmetic does. `Painter` still composes a child's region into its own on the grid before asking for it in pixels, which is the last narrow step in that path; taking it out needs the child's region as its parent stated it, which `draw_inner` is not handed. Checked: fmt, clippy, 83 suite tests, 17 core unit tests, the release oracle at 100 seeds and at 1000 seeds of depth 6, all fifteen shrinker cases at 400 seeds of depth 5, and `tabs`, `view`, `minimal`, `text`, `random` and the tab replay byte-identical at 1920x1200 against `45a7176`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
45a717695b
commit
5f16617511
3 files changed
+92
-12
No files matched your search
@@ -109,6 +109,44 @@ impl WideSpan {
|
||||
}
|
||||
}
|
||||
|
||||
impl WideSpan {
|
||||
/// A box given as a part of this one: the same composition carried one
|
||||
/// level further, with the part on the ordinary grid and the frame it
|
||||
/// lands in already on the fine one. That is the way round a draw
|
||||
/// descends -- a widget states its child's box as a part of its own --
|
||||
/// so composing this way never puts an intermediate back on the grid.
|
||||
pub const fn select(self, part: &UiSpan) -> Self {
|
||||
Self {
|
||||
start: self.end_at(part.start),
|
||||
end: self.end_at(part.end),
|
||||
}
|
||||
}
|
||||
|
||||
/// How long such a part is, in half the multiplies its two ends cost:
|
||||
/// where this box sits falls out of the difference.
|
||||
pub const fn select_len(self, part: &UiSpan) -> WideLen {
|
||||
let len = part.len();
|
||||
let rel_span = (self.end.rel - self.start.rel) as i128;
|
||||
let px_span = (self.end.px - self.start.px) >> PX_GAIN;
|
||||
WideLen {
|
||||
rel: ((rel_span * len.rel.raw() as i128) >> REL_SHIFT) as i64,
|
||||
px: ((len.px.raw() as i64) << PX_GAIN)
|
||||
+ ((px_span * len.rel.raw() as i64) >> (REL_SHIFT - PX_GAIN)),
|
||||
}
|
||||
}
|
||||
|
||||
const fn end_at(self, at: Len) -> WideLen {
|
||||
let rel_span = (self.end.rel - self.start.rel) as i128;
|
||||
let px_span = (self.end.px - self.start.px) >> PX_GAIN;
|
||||
WideLen {
|
||||
rel: self.start.rel + ((rel_span * at.rel.raw() as i128) >> REL_SHIFT) as i64,
|
||||
px: self.start.px
|
||||
+ ((at.px.raw() as i64) << PX_GAIN)
|
||||
+ ((px_span * at.rel.raw() as i64) >> (REL_SHIFT - PX_GAIN)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// How long a box is on each axis, part-way through a composition. What
|
||||
/// reads a box in pixels almost always wants this and not where it sits.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
@@ -144,6 +182,22 @@ pub struct WideRegion {
|
||||
}
|
||||
|
||||
impl WideRegion {
|
||||
/// A box given as a part of this one, on both axes.
|
||||
pub const fn select(self, part: &UiRegion) -> Self {
|
||||
Self {
|
||||
x: self.x.select(&part.x),
|
||||
y: self.y.select(&part.y),
|
||||
}
|
||||
}
|
||||
|
||||
/// How big such a part is, which is what reads a box in pixels.
|
||||
pub const fn select_size(self, part: &UiRegion) -> WideSize {
|
||||
WideSize {
|
||||
x: self.x.select_len(&part.x),
|
||||
y: self.y.select_len(&part.y),
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn of(region: UiRegion) -> Self {
|
||||
Self {
|
||||
x: WideSpan::of(region.x),
|
||||
|
||||
Reference in new issue
Block a user