Carry a box in a move slot, not a translation
A slot now holds the box its contents are placed within, in the coordinates of the slot it names, and `prelude.wgsl` composes the chain with `within` instead of adding a delta. A translation is the special case where the box has its parent's relative extent, so every caller passes `UiRegion::FULL.offset(delta)` and nothing changes on screen yet: 42 tests pass and `tabs` at 1920x1200 is byte-identical. `Moves::resolve` takes the region to compose rather than returning a sum, so the CPU walk is the same operation the shader performs. Measured against the translate slot on the same binary with `tests/chain_cost.rs`, 200k instances: +0.6% at depth 1, +0.5% at 2, +0.8% at 4, then +9.6% at 8 and +32.2% at 64. Free at the depth opt-in slots produce, which is the next commit; the per-level cost was always the dependent load rather than the arithmetic. The identity is `UiRegion::FULL` rather than zero, which `MoveOffset`'s comment says beside the `Zeroable` that `Pod` requires: a zeroed entry is a box of no extent and collapses its subtree to a point. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
db1751fdfd
commit
1f9dc48b80
4 files changed
+69
-48
No files matched your search
@@ -110,7 +110,7 @@ impl UiRenderState {
|
||||
|
||||
// draw widget
|
||||
let move_idx = self.move_slot(id, parent);
|
||||
self.moves.set(move_idx, Vec2::ZERO);
|
||||
self.moves.set(move_idx, UiRegion::FULL);
|
||||
rsc.widgets_mut().needs_redraw.remove(&id);
|
||||
self.draw_started.insert(id);
|
||||
|
||||
@@ -211,7 +211,7 @@ impl UiRenderState {
|
||||
// coordinates its parent drew, so the chain above applies alike.
|
||||
let moved =
|
||||
region.to_px(self.output_size).top_left - old.to_px(self.output_size).top_left;
|
||||
self.moves.set(slot, moved);
|
||||
self.moves.set(slot, UiRegion::FULL.offset(moved));
|
||||
return Some(size);
|
||||
}
|
||||
if !self.reusable(id, region, rsc) || !old.stretchable() {
|
||||
@@ -269,7 +269,7 @@ impl UiRenderState {
|
||||
*region = region.stretch(&from, &to);
|
||||
}
|
||||
active.region = active.region.stretch(&from, &to);
|
||||
self.moves.set(active.move_idx, Vec2::ZERO);
|
||||
self.moves.set(active.move_idx, UiRegion::FULL);
|
||||
// SAFETY: children cannot be recursive
|
||||
let children = unsafe { forget_ref(&active.children) };
|
||||
for child in children {
|
||||
@@ -367,12 +367,8 @@ impl UiRenderState {
|
||||
/// chain above has moved since, which is the walk the vertex shader does.
|
||||
pub fn window_region(&self, id: &impl IdLike) -> Option<PixelRegion> {
|
||||
let active = self.active.get(&id.id())?;
|
||||
let moved = self.moves.resolve(active.move_idx);
|
||||
let region = active.region.to_px(self.output_size);
|
||||
Some(PixelRegion {
|
||||
top_left: region.top_left + moved,
|
||||
bot_right: region.bot_right + moved,
|
||||
})
|
||||
let region = self.moves.resolve(active.move_idx, active.region);
|
||||
Some(region.to_px(self.output_size))
|
||||
}
|
||||
|
||||
/// redraws a widget that's currently active (drawn)
|
||||
|
||||
Reference in new issue
Block a user