diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2023-09-30 17:13:56 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2023-09-30 17:13:56 +0400 |
| commit | a3aa5fca12b59df0c1ee421b482a51a425e25abd (patch) | |
| tree | 3a94f1624912216a3a7e056c4de5d4fcb82b5b4f /src/backend | |
| parent | 21737abbfdb78698e323c0a9490759b427370a74 (diff) | |
| download | niri-a3aa5fca12b59df0c1ee421b482a51a425e25abd.tar.gz niri-a3aa5fca12b59df0c1ee421b482a51a425e25abd.tar.bz2 niri-a3aa5fca12b59df0c1ee421b482a51a425e25abd.zip | |
Refactor frame scheduling
Combine the redraw state variables into one enum, and refactor to get
rid of the requirement that a VBlank must queue a subsequent redraw.
Also fix the bug where ongoing animations that produced no damage could
stall the redrawing.
Diffstat (limited to 'src/backend')
| -rw-r--r-- | src/backend/tty.rs | 77 | ||||
| -rw-r--r-- | src/backend/winit.rs | 14 |
2 files changed, 70 insertions, 21 deletions
diff --git a/src/backend/tty.rs b/src/backend/tty.rs index 11595ef7..6f665432 100644 --- a/src/backend/tty.rs +++ b/src/backend/tty.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; use std::collections::{HashMap, HashSet}; +use std::mem; use std::os::fd::FromRawFd; use std::path::{Path, PathBuf}; use std::rc::Rc; @@ -38,7 +39,7 @@ use smithay_drm_extras::drm_scanner::{DrmScanEvent, DrmScanner}; use smithay_drm_extras::edid::EdidInfo; use crate::config::Config; -use crate::niri::{OutputRenderElements, State}; +use crate::niri::{OutputRenderElements, State, RedrawState}; use crate::utils::get_monotonic_time; use crate::Niri; @@ -703,34 +704,55 @@ impl Tty { .plot(surface.sequence_delta_plot_name, delta); } - assert!(output_state.waiting_for_vblank); - assert!(output_state.estimated_vblank_timer.is_none()); - - output_state.waiting_for_vblank = false; output_state.frame_clock.presented(presentation_time); output_state.current_estimated_sequence = Some(meta.sequence); - niri.queue_redraw(output); + + let redraw_needed = match mem::replace(&mut output_state.redraw_state, RedrawState::Idle) { + RedrawState::Idle => unreachable!(), + RedrawState::Queued(_) => unreachable!(), + RedrawState::WaitingForVBlank { redraw_needed } => redraw_needed, + RedrawState::WaitingForEstimatedVBlank(_) => unreachable!(), + RedrawState::WaitingForEstimatedVBlankAndQueued(_) => unreachable!(), + }; + + if redraw_needed || output_state.unfinished_animations_remain { + niri.queue_redraw(output); + } else { + niri.send_frame_callbacks(&output); + } } - fn on_estimated_vblank_timer(&self, niri: &mut Niri, output: &Output) { + fn on_estimated_vblank_timer(&self, niri: &mut Niri, output: Output) { let span = tracy_client::span!("Tty::on_estimated_vblank_timer"); let name = output.name(); span.emit_text(&name); - let Some(output_state) = niri.output_state.get_mut(output) else { + let Some(output_state) = niri.output_state.get_mut(&output) else { error!("missing output state for {name}"); return; }; - assert!(!output_state.waiting_for_vblank); - let token = output_state.estimated_vblank_timer.take(); - assert!(token.is_some()); + match mem::replace(&mut output_state.redraw_state, RedrawState::Idle) { + RedrawState::Idle => unreachable!(), + RedrawState::Queued(_) => unreachable!(), + RedrawState::WaitingForVBlank { .. } => unreachable!(), + RedrawState::WaitingForEstimatedVBlank(_) => (), + // The timer fired just in front of a redraw. + RedrawState::WaitingForEstimatedVBlankAndQueued((_, idle)) => { + output_state.redraw_state = RedrawState::Queued(idle); + return; + } + } if let Some(sequence) = output_state.current_estimated_sequence.as_mut() { *sequence = sequence.wrapping_add(1); - niri.send_frame_callbacks(output); + if output_state.unfinished_animations_remain { + niri.queue_redraw(output); + } else { + niri.send_frame_callbacks(&output); + } } } @@ -793,10 +815,18 @@ impl Tty { match drm_compositor.queue_frame(data) { Ok(()) => { let output_state = niri.output_state.get_mut(output).unwrap(); - output_state.waiting_for_vblank = true; - if let Some(token) = output_state.estimated_vblank_timer.take() { - niri.event_loop.remove(token); - } + let new_state = RedrawState::WaitingForVBlank { + redraw_needed: false, + }; + match mem::replace(&mut output_state.redraw_state, new_state) { + RedrawState::Idle => unreachable!(), + RedrawState::Queued(_) => (), + RedrawState::WaitingForVBlank { .. } => unreachable!(), + RedrawState::WaitingForEstimatedVBlank(_) => unreachable!(), + RedrawState::WaitingForEstimatedVBlankAndQueued((token, _)) => { + niri.event_loop.remove(token); + } + }; return Some(&surface.dmabuf_feedback); } @@ -904,8 +934,15 @@ fn queue_estimated_vblank_timer( target_presentation_time: Duration, ) { let output_state = niri.output_state.get_mut(&output).unwrap(); - if output_state.estimated_vblank_timer.is_some() { - return; + match mem::take(&mut output_state.redraw_state) { + RedrawState::Idle => unreachable!(), + RedrawState::Queued(_) => (), + RedrawState::WaitingForVBlank { .. } => unreachable!(), + RedrawState::WaitingForEstimatedVBlank(token) + | RedrawState::WaitingForEstimatedVBlankAndQueued((token, _)) => { + output_state.redraw_state = RedrawState::WaitingForEstimatedVBlank(token); + return; + } } let now = get_monotonic_time(); @@ -915,9 +952,9 @@ fn queue_estimated_vblank_timer( .insert_source(timer, move |_, _, data| { data.backend .tty() - .on_estimated_vblank_timer(&mut data.niri, &output); + .on_estimated_vblank_timer(&mut data.niri, output.clone()); TimeoutAction::Drop }) .unwrap(); - output_state.estimated_vblank_timer = Some(token); + output_state.redraw_state = RedrawState::WaitingForEstimatedVBlank(token); } diff --git a/src/backend/winit.rs b/src/backend/winit.rs index e0fbf272..7639b568 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; use std::collections::HashMap; +use std::mem; use std::rc::Rc; use std::sync::{Arc, Mutex}; use std::time::Duration; @@ -18,7 +19,7 @@ use smithay::utils::Transform; use smithay::wayland::dmabuf::DmabufFeedback; use crate::config::Config; -use crate::niri::{OutputRenderElements, State}; +use crate::niri::{OutputRenderElements, RedrawState, State}; use crate::utils::get_monotonic_time; use crate::Niri; @@ -182,7 +183,18 @@ impl Winit { 0, wp_presentation_feedback::Kind::empty(), ); + } + + let output_state = niri.output_state.get_mut(output).unwrap(); + match mem::replace(&mut output_state.redraw_state, RedrawState::Idle) { + RedrawState::Idle => unreachable!(), + RedrawState::Queued(_) => (), + RedrawState::WaitingForVBlank { .. } => unreachable!(), + RedrawState::WaitingForEstimatedVBlank(_) => unreachable!(), + RedrawState::WaitingForEstimatedVBlankAndQueued(_) => unreachable!(), + } + if output_state.unfinished_animations_remain { self.backend.window().request_redraw(); } |
