mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-22 02:01:55 +07:00
61 lines
1.8 KiB
Rust
61 lines
1.8 KiB
Rust
|
|
use std::num::NonZeroU64;
|
||
|
|
use std::time::Duration;
|
||
|
|
|
||
|
|
use crate::utils::get_monotonic_time;
|
||
|
|
|
||
|
|
#[derive(Debug)]
|
||
|
|
pub struct FrameClock {
|
||
|
|
last_presentation_time: Option<Duration>,
|
||
|
|
refresh_interval_ns: Option<NonZeroU64>,
|
||
|
|
}
|
||
|
|
|
||
|
|
impl FrameClock {
|
||
|
|
pub fn new(refresh_interval: Option<Duration>) -> Self {
|
||
|
|
let refresh_interval_ns = if let Some(interval) = &refresh_interval {
|
||
|
|
assert_eq!(interval.as_secs(), 0);
|
||
|
|
Some(NonZeroU64::new(interval.subsec_nanos().into()).unwrap())
|
||
|
|
} else {
|
||
|
|
None
|
||
|
|
};
|
||
|
|
|
||
|
|
Self {
|
||
|
|
last_presentation_time: None,
|
||
|
|
refresh_interval_ns,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn presented(&mut self, presentation_time: Duration) {
|
||
|
|
if presentation_time.is_zero() {
|
||
|
|
// Not interested in these.
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
self.last_presentation_time = Some(presentation_time);
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn next_presentation_time(&self) -> Duration {
|
||
|
|
let mut now = get_monotonic_time();
|
||
|
|
|
||
|
|
let Some(refresh_interval_ns) = self.refresh_interval_ns else {
|
||
|
|
return now;
|
||
|
|
};
|
||
|
|
let Some(last_presentation_time) = self.last_presentation_time else {
|
||
|
|
return now;
|
||
|
|
};
|
||
|
|
|
||
|
|
let refresh_interval_ns = refresh_interval_ns.get();
|
||
|
|
|
||
|
|
if now <= last_presentation_time {
|
||
|
|
// Got an early VBlank.
|
||
|
|
now += Duration::from_nanos(refresh_interval_ns);
|
||
|
|
// Assume two-frame early VBlanks don't happen. Overflow checks will catch them.
|
||
|
|
}
|
||
|
|
|
||
|
|
let since_last = now - last_presentation_time;
|
||
|
|
let since_last_ns =
|
||
|
|
since_last.as_secs() * 1_000_000_000 + u64::from(since_last.subsec_nanos());
|
||
|
|
let to_next_ns = (since_last_ns / refresh_interval_ns + 1) * refresh_interval_ns;
|
||
|
|
last_presentation_time + Duration::from_nanos(to_next_ns)
|
||
|
|
}
|
||
|
|
}
|