1use std::num::NonZeroUsize;
4
5use sva_samples::{Buffer, Extent};
6
7use super::RenderConfig;
8use super::until::{Known, Until};
9use super::value_graph::{Pulled, ValueGraph, blocks_end};
10use crate::cache::{Gauge, Memory, Progress, Recording};
11use crate::error::EngineError;
12use crate::query::{DEFAULT_FRAME_SECS, Representation};
13
14#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
16pub struct Work {
17 pub samples: u64,
18 pub computed_samples: u64,
19}
20
21pub(super) type Hears<'h> = Option<&'h dyn Fn(Progress)>;
23
24pub(super) struct Driver {
25 pub(super) value_graph: ValueGraph,
26 pub(super) start: i64,
27 pub(super) at: i64,
28 last: i64,
29 block: usize,
30 threads: NonZeroUsize,
31 until: Option<Until>,
32 frame: usize,
33 stop: Option<i64>,
34 end: Option<i64>,
35 keep: i64,
37 heard: i64,
39 output: bool,
40 most_bytes: usize,
41 samples: u64,
42 gauge: Gauge,
43 pub(super) memory: Memory,
44 pub(super) recording: Recording,
45}
46
47pub(super) fn frame(config: &RenderConfig, rate: u32) -> usize {
49 let secs = config
50 .asks
51 .iter()
52 .find_map(|ask| match ask.representation {
53 Representation::Envelope { frame_secs } => Some(frame_secs),
54 _ => None,
55 })
56 .flatten()
57 .unwrap_or(DEFAULT_FRAME_SECS);
58 ((secs * f64::from(rate)).round() as usize).max(1)
59}
60
61impl Driver {
62 pub(super) fn new(
63 value_graph: ValueGraph,
64 range: Extent,
65 block: usize,
66 config: &RenderConfig,
67 (memory, recording): (Memory, Recording),
68 ) -> Driver {
69 let frame = frame(config, config.rate);
70 Driver {
71 value_graph,
72 start: range.start,
73 at: range.start,
74 heard: range.start,
75 output: !super::dropped(config),
76 last: range.end,
77 block,
78 threads: config.threads,
79 keep: config.until.as_ref().map_or(0, |_| frame as i64),
80 until: config.until.clone(),
81 frame,
82 stop: None,
83 end: None,
84 most_bytes: 0,
85 samples: 0,
86 gauge: Gauge::default(),
87 memory,
88 recording,
89 }
90 }
91
92 pub(super) fn bound(&mut self, last: i64) {
94 self.last = last;
95 if self.stop.is_none() {
96 self.end = None;
97 }
98 }
99
100 pub(super) fn last(&self) -> i64 {
101 self.last
102 }
103
104 pub(super) fn next(&self) -> Extent {
105 let to = self
106 .next_to(self.block)
107 .min(blocks_end(self.at, self.threads));
108 Extent::new(self.at, to)
109 }
110
111 fn next_to(&self, n: usize) -> i64 {
112 self.last.min(self.at.saturating_add(n as i64)).max(self.at)
113 }
114
115 pub(super) fn read(&mut self, n: usize, heard: Hears) -> Result<Option<Buffer>, EngineError> {
118 let (from, to) = (self.at, self.next_to(n));
119 if !self.pulled(n, heard)? {
120 return Ok(None);
121 }
122 let mut out = self.played(from);
123 while self.at < to {
124 let at = self.at;
125 if !self.pulled((to - at) as usize, heard)? {
126 break;
127 }
128 let more = self.played(at);
129 for (held, more) in out.planes.iter_mut().zip(more.planes) {
130 held.extend(more);
131 }
132 }
133 Ok(Some(out))
134 }
135
136 pub(super) fn played(&self, from: i64) -> Buffer {
137 let end = self.end.map_or(self.at, |end| end.clamp(from, self.at));
138 self.value_graph
139 .samples(self.value_graph.root, Extent::new(from, end))
140 }
141
142 pub(super) fn skip(&mut self, to: i64) -> Result<Vec<usize>, EngineError> {
145 if self.end.is_some_and(|end| self.at >= end) {
146 return Ok(Vec::new());
147 }
148 let to = to.min(self.last);
149 let silenced = self.value_graph.skipped(Extent::new(to, self.last))?;
150 self.recording.reach(to);
151 (self.at, self.heard) = (to, to);
152 let future = (to < self.last).then(|| Extent::new(to, self.last));
153 self.value_graph
154 .release(future, Extent::NOWHERE, self.since());
155 if self.last <= to {
156 self.end = Some(to);
157 }
158 Ok(silenced)
159 }
160
161 pub(super) fn pull(&mut self, heard: Hears) -> Result<bool, EngineError> {
162 self.pulled(self.block, heard)
163 }
164
165 pub(super) fn progress(&self) -> Progress {
168 let work = self.gauge;
169 let end = self.end.unwrap_or(self.last);
170 let left = match self.at < end {
171 false => Some(Gauge::default()),
172 true if end == i64::MAX => None,
173 true => {
174 let rest = Extent::new(self.at, end);
175 let held = (&self.memory, &self.recording);
176 match self.at == self.start {
177 true => self.value_graph.ahead((self.next(), rest), held),
178 false => self.value_graph.remaining(rest, held),
179 }
180 }
181 };
182 Progress {
183 work,
184 planned_samples: left.map(|left| work.done() + left.done()),
185 }
186 }
187
188 pub(super) fn work(&self) -> Work {
189 Work {
190 samples: self.samples,
191 computed_samples: self.gauge.computed_samples,
192 }
193 }
194
195 pub(super) fn pulled(&mut self, n: usize, heard: Hears) -> Result<bool, EngineError> {
197 let from = self.at;
198 if self.end.is_some_and(|end| from >= end) {
199 return Ok(false);
200 }
201 let to = self.next_to(n).min(blocks_end(from, self.threads));
202 self.recording.reach(from);
203 let asked_range = Extent::new(from, to);
204 let planned_samples = heard.and_then(|_| self.progress().planned_samples);
205 let hears = |before: Gauge| {
206 move |work: Gauge| {
207 let work = before.plus(work);
208 let progress = Progress {
209 work,
210 planned_samples,
211 };
212 heard.into_iter().for_each(|heard| heard(progress));
213 }
214 };
215 if from == self.start {
216 let hears = hears(self.gauge);
217 let history = self.value_graph.history(
218 (asked_range, self.last),
219 self.block as i64,
220 (&self.memory, &mut self.recording),
221 (self.threads, heard.map(|_| &hears as &dyn Fn(Gauge))),
222 )?;
223 self.counted(&history);
224 }
225 let hears = hears(self.gauge);
226 let pulled = self.value_graph.pull(
227 asked_range,
228 (&self.memory, &mut self.recording),
229 (self.threads, heard.map(|_| &hears as &dyn Fn(Gauge))),
230 )?;
231 self.counted(&pulled);
232 self.samples += (to - from) as u64;
233 self.at = to;
234 self.settle(from, to);
235 let future = (to < self.last).then(|| Extent::new(to, self.last));
236 let keep = Extent::new(from.min(to.saturating_sub(self.keep)), to);
237 self.value_graph.release(future, keep, self.since());
238 Ok(true)
239 }
240
241 fn since(&self) -> Option<i64> {
242 self.output.then_some(self.start)
243 }
244
245 fn counted(&mut self, pulled: &Pulled) {
246 self.gauge = self.gauge.plus(pulled.work);
247 self.most_bytes = self.most_bytes.max(pulled.most_bytes);
248 }
249
250 pub(super) fn most_bytes(&self) -> usize {
251 self.most_bytes
252 }
253
254 fn settle(&mut self, from: i64, to: i64) {
257 if self.end.is_some() {
258 return;
259 }
260 if self.last <= to {
261 self.end = Some(to);
262 }
263 let Some(until) = &self.until else {
264 return;
265 };
266 let frame = self.frame as i64;
267 let open = self.start + (from - 1 - self.start).div_euclid(frame) * frame;
268 let base = open.max(self.heard);
269 let heard = self
270 .value_graph
271 .samples(self.value_graph.root, Extent::new(base, to));
272 let planes: Vec<&[f64]> = heard.planes.iter().map(Vec::as_slice).collect();
273 let rate = self.value_graph.values[self.value_graph.root].grid.rate;
274 let known = Known::new(planes, base, self.start, self.frame, rate, to == self.last);
275 if let Some(at) = until.first(&known, base, to) {
276 self.stop = Some(at);
277 self.end = Some(at.max(from));
278 }
279 }
280
281 pub(super) fn end(&self) -> Option<i64> {
282 self.end
283 }
284
285 pub(super) fn stop(&self) -> Option<i64> {
286 self.stop
287 }
288}