Skip to main content

sva_engine/render/
drive.rs

1// Concern: pulls or skips a table block by block until its range ends or `until` holds, dropping what no later block reads | Non-concern: what a value computes | IO: (Table, range) -> blocks
2
3use sva_samples::Extent;
4
5use super::RenderConfig;
6use super::table::{Pulled, Table};
7use super::until::{Known, Until};
8use crate::cache::Recording;
9use crate::error::EngineError;
10use crate::flops::Work;
11use crate::query::{DEFAULT_FRAME_SECS, Representation};
12
13pub(super) struct Driver {
14    pub(super) table: Table,
15    pub(super) start: i64,
16    pub(super) at: i64,
17    last: i64,
18    block: usize,
19    until: Option<Until>,
20    frame: usize,
21    stop: Option<i64>,
22    end: Option<i64>,
23    /// Root samples held behind `at`, for `until` to read its open frame.
24    keep: i64,
25    /// Where the samples heard without a break since start from: a skip starts them anew.
26    heard: i64,
27    output: bool,
28    most_bytes: usize,
29    pub(super) work: Work,
30    pub(super) recording: Recording,
31}
32
33pub struct Block {
34    planes: Vec<Vec<f64>>,
35    start: i64,
36}
37
38impl Block {
39    pub fn start(&self) -> i64 {
40        self.start
41    }
42
43    pub fn len(&self) -> usize {
44        self.planes[0].len()
45    }
46
47    pub fn is_empty(&self) -> bool {
48        self.len() == 0
49    }
50
51    pub fn width(&self) -> usize {
52        self.planes.len()
53    }
54
55    pub fn plane(&self, c: usize) -> &[f64] {
56        &self.planes[c]
57    }
58
59    /// A mono block in each of `width` channels; any other as it is.
60    pub(super) fn widened(mut self, width: usize) -> Block {
61        if self.planes.len() == 1 {
62            let copies = vec![self.planes[0].clone(); width.saturating_sub(1)];
63            self.planes.extend(copies);
64        }
65        self
66    }
67}
68
69/// The `envelope` reading's own frame at the render's rate, where one is asked.
70pub(super) fn frame(config: &RenderConfig, rate: u32) -> usize {
71    let secs = config
72        .asks
73        .iter()
74        .find_map(|ask| match ask.representation {
75            Representation::Envelope { frame_secs } => Some(frame_secs),
76            _ => None,
77        })
78        .flatten()
79        .unwrap_or(DEFAULT_FRAME_SECS);
80    ((secs * f64::from(rate)).round() as usize).max(1)
81}
82
83impl Driver {
84    pub(super) fn new(
85        table: Table,
86        range: Extent,
87        block: usize,
88        config: &RenderConfig,
89        recording: Recording,
90    ) -> Driver {
91        let frame = frame(config, config.rate);
92        Driver {
93            table,
94            start: range.start,
95            at: range.start,
96            heard: range.start,
97            output: !super::dropped(config),
98            last: range.end,
99            block,
100            keep: config.until.as_ref().map_or(0, |_| frame as i64),
101            until: config.until.clone(),
102            frame,
103            stop: None,
104            end: None,
105            most_bytes: 0,
106            work: Work {
107                waves: Some(0),
108                ..Work::default()
109            },
110            recording,
111        }
112    }
113
114    /// Ends at `last`, unless `until` already stopped it.
115    pub(super) fn bound(&mut self, last: i64) {
116        self.last = last;
117        if self.stop.is_none() {
118            self.end = None;
119        }
120    }
121
122    pub(super) fn last(&self) -> i64 {
123        self.last
124    }
125
126    pub(super) fn next(&self) -> Extent {
127        Extent::new(self.at, self.next_to(self.block))
128    }
129
130    fn next_to(&self, n: usize) -> i64 {
131        self.last.min(self.at.saturating_add(n as i64)).max(self.at)
132    }
133
134    /// `n` samples from where it stands, cut where its range ends; `None` from there on.
135    pub(super) fn read(&mut self, n: usize) -> Result<Option<Block>, EngineError> {
136        let from = self.at;
137        if !self.pulled(n)? {
138            return Ok(None);
139        }
140        let end = self.end.map_or(self.at, |end| end.clamp(from, self.at));
141        let held = self.table.samples(self.table.root, Extent::new(from, end));
142        Ok(Some(Block {
143            planes: held.planes,
144            start: from,
145        }))
146    }
147
148    /// Stands at `to`, computing nothing before it; the stateful values it started silent,
149    /// each asked from before its run reaches.
150    pub(super) fn skip(&mut self, to: i64) -> Result<Vec<usize>, EngineError> {
151        if self.end.is_some_and(|end| self.at >= end) {
152            return Ok(Vec::new());
153        }
154        let to = to.min(self.last);
155        let silenced = self.table.skipped(Extent::new(to, self.last))?;
156        self.recording.reach(to);
157        (self.at, self.heard) = (to, to);
158        let future = (to < self.last).then(|| Extent::new(to, self.last));
159        self.table.release(future, Extent::NOWHERE, self.since());
160        if self.last <= to {
161            self.end = Some(to);
162        }
163        Ok(silenced)
164    }
165
166    pub(super) fn pull(&mut self) -> Result<bool, EngineError> {
167        self.pulled(self.block)
168    }
169
170    /// Computes `n` samples on from where it stands; false once it ended.
171    pub(super) fn pulled(&mut self, n: usize) -> Result<bool, EngineError> {
172        let from = self.at;
173        if self.end.is_some_and(|end| from >= end) {
174            return Ok(false);
175        }
176        let to = self.next_to(n);
177        self.recording.reach(from);
178        let window = Extent::new(from, to);
179        if from == self.start {
180            let history = self
181                .table
182                .history(window, self.block as i64, &mut self.recording)?;
183            self.priced(&history);
184        }
185        let pulled = self.table.pull(window, &mut self.recording)?;
186        self.priced(&pulled);
187        self.work.samples += (to - from) as u64;
188        self.at = to;
189        self.settle(from, to);
190        let future = (to < self.last).then(|| Extent::new(to, self.last));
191        let keep = Extent::new(from.min(to.saturating_sub(self.keep)), to);
192        self.table.release(future, keep, self.since());
193        Ok(true)
194    }
195
196    fn since(&self) -> Option<i64> {
197        self.output.then_some(self.start)
198    }
199
200    fn priced(&mut self, pulled: &Pulled) {
201        self.work.priced_flops += pulled.priced;
202        self.work.waves = self.work.waves.map(|held| held + pulled.waves);
203        self.most_bytes = self.most_bytes.max(pulled.most_bytes);
204    }
205
206    pub(super) fn most_bytes(&self) -> usize {
207        self.most_bytes
208    }
209
210    /// The one place `until` is checked. A level is known once its frame is whole, so only the
211    /// frames the last block left open are read again; a frame a skip cut into is never known.
212    fn settle(&mut self, from: i64, to: i64) {
213        if self.end.is_some() {
214            return;
215        }
216        if self.last <= to {
217            self.end = Some(to);
218        }
219        let Some(until) = &self.until else {
220            return;
221        };
222        let frame = self.frame as i64;
223        let open = self.start + (from - 1 - self.start).div_euclid(frame) * frame;
224        let base = open.max(self.heard);
225        let heard = self.table.samples(self.table.root, Extent::new(base, to));
226        let planes: Vec<&[f64]> = heard.planes.iter().map(Vec::as_slice).collect();
227        let rate = self.table.values[self.table.root].grid.rate;
228        let known = Known::new(planes, base, self.start, self.frame, rate, to == self.last);
229        if let Some(at) = until.first(&known, base, to) {
230            self.stop = Some(at);
231            self.end = Some(at.max(from));
232        }
233    }
234
235    pub(super) fn end(&self) -> Option<i64> {
236        self.end
237    }
238
239    pub(super) fn stop(&self) -> Option<i64> {
240        self.stop
241    }
242}