use std::time::{Duration, Instant};
#[derive(Debug, Default)]
pub struct InputLatency {
pending: Option<Instant>,
samples: Vec<f64>,
}
impl InputLatency {
pub fn record_input(&mut self, at: Instant) {
self.pending.get_or_insert(at);
}
pub fn frame_presented(&mut self, at: Instant, gpu: Duration) {
if let Some(input) = self.pending.take() {
let latency = at.saturating_duration_since(input) + gpu;
self.samples.push(latency.as_secs_f64() * 1000.0);
}
}
pub fn take_samples(&mut self) -> Vec<f64> {
std::mem::take(&mut self.samples)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_sample_spans_the_oldest_press_to_its_presented_frame() {
let start = Instant::now();
let ms = Duration::from_millis;
let mut latency = InputLatency::default();
latency.frame_presented(start, ms(2));
latency.record_input(start + ms(1));
latency.record_input(start + ms(4));
latency.frame_presented(start + ms(10), ms(3));
latency.frame_presented(start + ms(20), ms(3));
latency.record_input(start + ms(25));
latency.frame_presented(start + ms(30), ms(1));
assert_eq!(latency.take_samples(), [12.0, 6.0]);
assert!(latency.take_samples().is_empty());
}
}