cache hex position
This commit is contained in:
@@ -25,6 +25,8 @@ use tokio::time::Duration;
|
|||||||
static REIFY_COUNT: AtomicUsize = AtomicUsize::new(0);
|
static REIFY_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||||
static REIFY_TOTAL_NS: AtomicU64 = AtomicU64::new(0);
|
static REIFY_TOTAL_NS: AtomicU64 = AtomicU64::new(0);
|
||||||
static APP_REIFY_COUNT: AtomicUsize = AtomicUsize::new(0);
|
static APP_REIFY_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
static VISIBLE_LIMIT: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
const VISIBLE_STEP: usize = 12;
|
||||||
|
|
||||||
use tracing_subscriber::{EnvFilter, Layer, layer::SubscriberExt, util::SubscriberInitExt};
|
use tracing_subscriber::{EnvFilter, Layer, layer::SubscriberExt, util::SubscriberInitExt};
|
||||||
|
|
||||||
@@ -75,6 +77,9 @@ pub struct HexagonLauncher {
|
|||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
/// position in the vector is mapped to hex coordinates
|
/// position in the vector is mapped to hex coordinates
|
||||||
apps: Vec<App>,
|
apps: Vec<App>,
|
||||||
|
#[serde(skip)]
|
||||||
|
/// cached world coordinates for each app hex
|
||||||
|
positions: Vec<[f32; 3]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for HexagonLauncher {
|
impl Default for HexagonLauncher {
|
||||||
@@ -84,6 +89,7 @@ impl Default for HexagonLauncher {
|
|||||||
pos: [0.0; 3].into(),
|
pos: [0.0; 3].into(),
|
||||||
rot: Quat::IDENTITY.into(),
|
rot: Quat::IDENTITY.into(),
|
||||||
apps: Vec::new(),
|
apps: Vec::new(),
|
||||||
|
positions: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,6 +115,11 @@ impl ClientState for HexagonLauncher {
|
|||||||
// Sort by name
|
// Sort by name
|
||||||
self.apps
|
self.apps
|
||||||
.sort_by_key(|app| app.app.name().unwrap_or_default().to_string());
|
.sort_by_key(|app| app.app.name().unwrap_or_default().to_string());
|
||||||
|
|
||||||
|
// precompute coordinates for each app to avoid recomputing per-reify
|
||||||
|
self.positions = (0..self.apps.len())
|
||||||
|
.map(|i| Hex::spiral(i + 1).get_coords())
|
||||||
|
.collect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Reify for HexagonLauncher {
|
impl Reify for HexagonLauncher {
|
||||||
@@ -167,24 +178,59 @@ impl Reify for HexagonLauncher {
|
|||||||
))
|
))
|
||||||
.build(),
|
.build(),
|
||||||
)
|
)
|
||||||
.children(
|
// limit how many children we build per-frame to avoid reify explosion;
|
||||||
|
// increase if performance is acceptable, or implement a pager/virtualization.
|
||||||
|
.children({
|
||||||
|
// read configured maximum (fall back to all apps)
|
||||||
|
let env_max = std::env::var("HEX_MAX_VISIBLE")
|
||||||
|
.ok()
|
||||||
|
.and_then(|s| s.parse::<usize>().ok());
|
||||||
|
let configured_max = env_max.unwrap_or(self.apps.len());
|
||||||
|
// desired target: if open -> min(configured_max, apps.len()) else 0
|
||||||
|
let desired = if self.open {
|
||||||
|
std::cmp::min(configured_max, self.apps.len())
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
// nudge the global visible limit toward desired to spread creation cost
|
||||||
|
let current = VISIBLE_LIMIT.load(Ordering::Relaxed);
|
||||||
|
if desired == 0 {
|
||||||
|
// closing -> quickly collapse
|
||||||
|
if current != 0 {
|
||||||
|
VISIBLE_LIMIT.store(0, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
} else if current < desired {
|
||||||
|
let add = (desired - current).min(VISIBLE_STEP);
|
||||||
|
VISIBLE_LIMIT.fetch_add(add, Ordering::Relaxed);
|
||||||
|
} else if current > desired {
|
||||||
|
// clamp down if configured max reduced
|
||||||
|
VISIBLE_LIMIT.store(desired, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
let take_n = std::cmp::min(VISIBLE_LIMIT.load(Ordering::Relaxed), self.apps.len());
|
||||||
|
tracing::debug!(total_apps = self.apps.len(), configured_max, visible = take_n, desired, "building visible app children");
|
||||||
|
|
||||||
self.open
|
self.open
|
||||||
.then(|| {
|
.then(|| {
|
||||||
self.apps.iter().enumerate().map(|(i, app)| {
|
self.apps
|
||||||
Spatial::default()
|
.iter()
|
||||||
.pos(Hex::spiral(i + 1).get_coords())
|
.enumerate()
|
||||||
.build()
|
.take(take_n)
|
||||||
.child(app.reify_substate(move |state: &mut HexagonLauncher| {
|
.map(|(i, app)| {
|
||||||
// log & count access to per-app substate
|
Spatial::default()
|
||||||
APP_REIFY_COUNT.fetch_add(1, Ordering::Relaxed);
|
.pos(self.positions[i])
|
||||||
tracing::trace!(index = i, "accessing app substate");
|
.build()
|
||||||
state.apps.get_mut(i)
|
.child(app.reify_substate(move |state: &mut HexagonLauncher| {
|
||||||
}))
|
// log & count access to per-app substate
|
||||||
})
|
APP_REIFY_COUNT.fetch_add(1, Ordering::Relaxed);
|
||||||
|
tracing::trace!(index = i, "accessing app substate");
|
||||||
|
state.apps.get_mut(i)
|
||||||
|
}))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten(),
|
.flatten()
|
||||||
)
|
})
|
||||||
;
|
;
|
||||||
|
|
||||||
let elapsed = start.elapsed().as_nanos() as u64;
|
let elapsed = start.elapsed().as_nanos() as u64;
|
||||||
|
|||||||
Reference in New Issue
Block a user