kms: skip cursor updates for fullscreen content above the minimum refresh rate

This commit is contained in:
Victoria Brekenfeld 2025-01-02 20:23:15 +01:00 committed by Victoria Brekenfeld
parent adcb81bbe0
commit b5cd62fd7a
3 changed files with 111 additions and 16 deletions

View file

@ -8,6 +8,7 @@ const FRAME_TIME_WINDOW: usize = 3;
pub struct Timings {
refresh_interval_ns: Option<NonZeroU64>,
min_refresh_interval_ns: Option<NonZeroU64>,
vrr: bool,
pub pending_frame: Option<PendingFrame>,
@ -44,7 +45,11 @@ impl Frame {
impl Timings {
const WINDOW_SIZE: usize = 360;
pub fn new(refresh_interval: Option<Duration>, vrr: bool) -> Self {
pub fn new(
refresh_interval: Option<Duration>,
min_interval: Option<Duration>,
vrr: bool,
) -> 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())
@ -52,8 +57,16 @@ impl Timings {
None
};
let min_refresh_interval_ns = if let Some(interval) = &min_interval {
assert_eq!(interval.as_secs(), 0);
Some(NonZeroU64::new(interval.subsec_nanos().into()).unwrap())
} else {
None
};
Self {
refresh_interval_ns,
min_refresh_interval_ns,
vrr,
pending_frame: None,
@ -76,6 +89,12 @@ impl Timings {
self.previous_frames.clear();
}
pub fn set_min_refresh_interval(&mut self, min_interval: Option<Duration>) {
self.min_refresh_interval_ns = min_interval
.map(|duration| duration.subsec_nanos() as u64)
.and_then(NonZeroU64::new);
}
pub fn set_vrr(&mut self, vrr: bool) {
self.vrr = vrr;
}
@ -255,6 +274,28 @@ impl Timings {
}
}
pub fn past_min_presentation_time(&self, clock: &Clock<Monotonic>) -> bool {
let now: Duration = clock.now().into();
let Some(refresh_interval_ns) = self.min_refresh_interval_ns else {
return true;
};
let Some(last_presentation_time): Option<Duration> = self
.previous_frames
.back()
.map(|frame| frame.presentation_presented.into())
else {
return true;
};
let refresh_interval_ns = refresh_interval_ns.get();
if now <= last_presentation_time {
return false;
}
let next = last_presentation_time + Duration::from_nanos(refresh_interval_ns);
now >= next
}
pub fn next_render_time(&self, clock: &Clock<Monotonic>) -> Duration {
let estimated_presentation_time = self.next_presentation_time(clock);
if estimated_presentation_time.is_zero() {