sim_lib_view_spatial/
predict.rs1use std::{cell::RefCell, rc::Rc};
4
5use sim_kernel::{Expr, Result};
6use sim_lib_view_device::{DeviceProfile, EncodedScene, LocalAdapter};
7
8use crate::{PoseView, Reprojector};
9
10pub fn clamp_predicted(pose: &PoseView, max_predict_ms: u64) -> PoseView {
12 let mut clamped = pose.clone();
13 clamped.predict_ns = clamped
14 .predict_ns
15 .min(max_predict_ms.saturating_mul(1_000_000));
16 clamped
17}
18
19#[derive(Debug)]
26pub struct ClampedReprojector {
27 inner: Reprojector,
28 last_good: RefCell<Option<Rc<Expr>>>,
29}
30
31impl ClampedReprojector {
32 pub fn new(max_predict_ms: u64) -> Self {
34 Self {
35 inner: Reprojector::new(max_predict_ms),
36 last_good: RefCell::new(None),
37 }
38 }
39
40 pub fn max_predict_ms(&self) -> u64 {
42 self.inner.max_predict_ms
43 }
44
45 pub fn inner(&self) -> &Reprojector {
47 &self.inner
48 }
49}
50
51impl LocalAdapter for ClampedReprojector {
52 type State = PoseView;
53
54 fn adapt(
55 &self,
56 scene: &EncodedScene,
57 state: &Self::State,
58 profile: &DeviceProfile,
59 ) -> Result<Rc<Expr>> {
60 if pose_exceeds_clamp(state, self.max_predict_ms()) {
61 return Ok(self
62 .last_good
63 .borrow()
64 .clone()
65 .unwrap_or_else(|| scene.shared()));
66 }
67 let clamped = clamp_predicted(state, self.max_predict_ms());
68 let out = self.inner.adapt(scene, &clamped, profile)?;
69 self.last_good.replace(Some(Rc::clone(&out)));
70 Ok(out)
71 }
72}
73
74pub(crate) fn pose_exceeds_clamp(pose: &PoseView, max_predict_ms: u64) -> bool {
75 pose.age_ms > max_predict_ms
76}