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
+15
-14
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
Mask, MoveIdx, MoveOffset, PrimitiveRegistry, TextData, Textures, WeakWidget, WidgetId,
|
||||
Widgets,
|
||||
util::{Arena, Id, TrackedArena, Vec2},
|
||||
Mask, MoveIdx, MoveOffset, PrimitiveRegistry, TextData, Textures, UiRegion, WeakWidget,
|
||||
WidgetId, Widgets,
|
||||
util::{Arena, Id, TrackedArena},
|
||||
};
|
||||
|
||||
/// How far the shader will walk a move chain. It bounds a malformed cycle
|
||||
@@ -46,26 +46,27 @@ impl Moves {
|
||||
self.arena.remove(Id::preset(idx.idx() as u32));
|
||||
}
|
||||
|
||||
/// Sets a slot's translation, in physical pixels, relative to its parent.
|
||||
pub fn set(&mut self, idx: MoveIdx, delta: Vec2) {
|
||||
/// Sets the box a slot's contents are placed within, itself given in the
|
||||
/// coordinates of its parent slot.
|
||||
pub fn set(&mut self, idx: MoveIdx, region: UiRegion) {
|
||||
let entry = self.arena.get_mut(Id::preset(idx.idx() as u32));
|
||||
if entry.delta != delta {
|
||||
entry.delta = delta;
|
||||
if entry.region != region {
|
||||
entry.region = region;
|
||||
self.changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// The translation a primitive in `idx` has accumulated, which is the
|
||||
/// same walk the vertex shader does.
|
||||
pub fn resolve(&self, idx: MoveIdx) -> Vec2 {
|
||||
let mut total = Vec2::ZERO;
|
||||
/// Composes a region held in `idx`'s coordinates down the chain, which is
|
||||
/// the same walk the vertex shader does.
|
||||
pub fn resolve(&self, idx: MoveIdx, local: UiRegion) -> UiRegion {
|
||||
let mut region = local;
|
||||
let mut at = idx;
|
||||
for _ in 0..CHAIN_LIMIT {
|
||||
if at == MoveIdx::NONE {
|
||||
return total;
|
||||
return region;
|
||||
}
|
||||
let entry = self.arena[at.idx()];
|
||||
total += entry.delta;
|
||||
region = region.within(&entry.region);
|
||||
at = entry.parent;
|
||||
}
|
||||
debug_assert!(
|
||||
@@ -73,7 +74,7 @@ impl Moves {
|
||||
"a move chain longer than {CHAIN_LIMIT} resolves to the wrong place, \
|
||||
and the shader stops at the same depth"
|
||||
);
|
||||
total
|
||||
region
|
||||
}
|
||||
|
||||
pub fn entries(&self) -> &[MoveOffset] {
|
||||
|
||||
Reference in new issue
Block a user