kms: Use recent average frame_time for delay

This commit is contained in:
Victoria Brekenfeld 2022-11-22 18:20:20 +01:00
parent aa2e7c0a02
commit b5ef2c5bde
6 changed files with 55 additions and 58 deletions

View file

@ -1,13 +1,10 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
#[cfg(feature = "debug")]
use crate::state::Fps;
use crate::{ use crate::{
backend::render, backend::render,
config::OutputConfig, config::OutputConfig,
shell::Shell, shell::Shell,
state::{BackendData, ClientState, Common, Data}, state::{BackendData, ClientState, Common, Data, Fps},
utils::prelude::*, utils::prelude::*,
wayland::{ wayland::{
handlers::screencopy::{PendingScreencopyBuffers, UserdataExt}, handlers::screencopy::{PendingScreencopyBuffers, UserdataExt},
@ -69,6 +66,8 @@ use session_fd::*;
use socket::*; use socket::*;
use super::render::{CursorMode, GlMultiRenderer}; use super::render::{CursorMode, GlMultiRenderer};
// for now we assume we need at least 3ms
const MIN_RENDER_TIME: Duration = Duration::from_millis(3);
pub struct KmsState { pub struct KmsState {
devices: HashMap<DrmNode, Device>, devices: HashMap<DrmNode, Device>,
@ -107,7 +106,6 @@ pub struct Surface {
pending: bool, pending: bool,
dirty: bool, dirty: bool,
render_timer_token: Option<RegistrationToken>, render_timer_token: Option<RegistrationToken>,
#[cfg(feature = "debug")]
fps: Fps, fps: Fps,
} }
@ -381,7 +379,7 @@ impl State {
let dispatcher = let dispatcher =
Dispatcher::new(drm, move |event, metadata, data: &mut Data| match event { Dispatcher::new(drm, move |event, metadata, data: &mut Data| match event {
DrmEvent::VBlank(crtc) => { DrmEvent::VBlank(crtc) => {
let rescheduled_output = let rescheduled =
if let Some(device) = data.state.backend.kms().devices.get_mut(&drm_node) { if let Some(device) = data.state.backend.kms().devices.get_mut(&drm_node) {
if let Some(surface) = device.surfaces.get_mut(&crtc) { if let Some(surface) = device.surfaces.get_mut(&crtc) {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
@ -427,7 +425,9 @@ impl State {
} }
surface.pending = false; surface.pending = false;
surface.dirty.then(|| surface.output.clone()) surface.dirty.then(|| {
(surface.output.clone(), surface.fps.avg_rendertime(5))
})
} }
Some(Err(err)) => { Some(Err(err)) => {
slog_scope::warn!("Failed to submit frame: {}", err); slog_scope::warn!("Failed to submit frame: {}", err);
@ -442,7 +442,7 @@ impl State {
None None
}; };
if let Some(output) = rescheduled_output { if let Some((output, avg_rendertime)) = rescheduled {
let mut scheduled_sessions = let mut scheduled_sessions =
data.state.workspace_session_for_output(&output); data.state.workspace_session_for_output(&output);
if let Some(sessions) = output.user_data().get::<PendingScreencopyBuffers>() if let Some(sessions) = output.user_data().get::<PendingScreencopyBuffers>()
@ -452,15 +452,7 @@ impl State {
.extend(sessions.borrow_mut().drain(..)); .extend(sessions.borrow_mut().drain(..));
} }
let output_refresh = match output.current_mode() { let repaint_delay = std::cmp::max(avg_rendertime, MIN_RENDER_TIME);
Some(mode) => mode.refresh,
None => return,
};
// TODO: Record rendering times and use sliding window to estimate duration for next render
let repaint_delay = Duration::from_secs_f64(
((1000.0 / output_refresh as f64) * 0.6).max(0.003), // for now we assume we need at least 3ms
);
if let Err(err) = data.state.backend.kms().schedule_render( if let Err(err) = data.state.backend.kms().schedule_render(
&data.state.common.event_loop_handle, &data.state.common.event_loop_handle,
&output, &output,
@ -781,7 +773,6 @@ impl Device {
pending: false, pending: false,
dirty: false, dirty: false,
render_timer_token: None, render_timer_token: None,
#[cfg(feature = "debug")]
fps: Fps::new(renderer.as_mut()), fps: Fps::new(renderer.as_mut()),
}; };
self.surfaces.insert(crtc, data); self.surfaces.insert(crtc, data);
@ -861,7 +852,6 @@ impl Surface {
&self.output, &self.output,
CursorMode::All, CursorMode::All,
screencopy.map(|sessions| (buffer, sessions)), screencopy.map(|sessions| (buffer, sessions)),
#[cfg(feature = "debug")]
Some(&mut self.fps), Some(&mut self.fps),
) { ) {
Ok((damage, states)) => { Ok((damage, states)) => {

View file

@ -1,10 +1,10 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
use crate::{debug::fps_ui, state::Fps, utils::prelude::*}; use crate::{debug::fps_ui, utils::prelude::*};
use crate::{ use crate::{
shell::{layout::floating::SeatMoveGrabState, CosmicMappedRenderElement}, shell::{layout::floating::SeatMoveGrabState, CosmicMappedRenderElement},
state::Common, state::{Common, Fps},
wayland::{ wayland::{
handlers::{data_device::get_dnd_icon, screencopy::render_session}, handlers::{data_device::get_dnd_icon, screencopy::render_session},
protocols::{ protocols::{
@ -134,7 +134,7 @@ pub fn render_output<R, Target, OffTarget, Source>(
output: &Output, output: &Output,
cursor_mode: CursorMode, cursor_mode: CursorMode,
screencopy: Option<(Source, &[(ScreencopySession, BufferParams)])>, screencopy: Option<(Source, &[(ScreencopySession, BufferParams)])>,
#[cfg(feature = "debug")] fps: Option<&mut Fps>, fps: Option<&mut Fps>,
) -> Result<(Option<Vec<Rectangle<i32, Physical>>>, RenderElementStates), RenderError<R>> ) -> Result<(Option<Vec<Rectangle<i32, Physical>>>, RenderElementStates), RenderError<R>>
where where
R: Renderer R: Renderer
@ -165,7 +165,6 @@ where
&handle, &handle,
cursor_mode, cursor_mode,
screencopy, screencopy,
#[cfg(feature = "debug")]
fps, fps,
) )
} }
@ -181,7 +180,7 @@ pub fn render_workspace<R, Target, OffTarget, Source>(
handle: &WorkspaceHandle, handle: &WorkspaceHandle,
mut cursor_mode: CursorMode, mut cursor_mode: CursorMode,
screencopy: Option<(Source, &[(ScreencopySession, BufferParams)])>, screencopy: Option<(Source, &[(ScreencopySession, BufferParams)])>,
#[cfg(feature = "debug")] mut fps: Option<&mut Fps>, mut fps: Option<&mut Fps>,
) -> Result<(Option<Vec<Rectangle<i32, Physical>>>, RenderElementStates), RenderError<R>> ) -> Result<(Option<Vec<Rectangle<i32, Physical>>>, RenderElementStates), RenderError<R>>
where where
R: Renderer R: Renderer
@ -200,7 +199,6 @@ where
CosmicMappedRenderElement<R>: RenderElement<R>, CosmicMappedRenderElement<R>: RenderElement<R>,
Source: Clone, Source: Clone,
{ {
#[cfg(feature = "debug")]
if let Some(ref mut fps) = fps { if let Some(ref mut fps) = fps {
fps.start(); fps.start();
} }
@ -255,7 +253,6 @@ where
.map(Into::into), .map(Into::into),
); );
#[cfg(feature = "debug")]
if let Some(fps) = fps.as_mut() { if let Some(fps) = fps.as_mut() {
fps.elements(); fps.elements();
} }
@ -263,7 +260,6 @@ where
renderer.bind(target).map_err(RenderError::Rendering)?; renderer.bind(target).map_err(RenderError::Rendering)?;
let res = damage_tracker.render_output(renderer, age, &elements, CLEAR_COLOR, None); let res = damage_tracker.render_output(renderer, age, &elements, CLEAR_COLOR, None);
#[cfg(feature = "debug")]
if let Some(fps) = fps.as_mut() { if let Some(fps) = fps.as_mut() {
fps.render(); fps.render();
} }
@ -311,7 +307,6 @@ where
} }
} }
} }
#[cfg(feature = "debug")]
if let Some(fps) = fps.as_mut() { if let Some(fps) = fps.as_mut() {
fps.screencopy(); fps.screencopy();
} }

View file

@ -65,6 +65,8 @@ impl WinitState {
} else { } else {
None None
}, },
#[cfg(not(feature = "debug"))]
None,
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
Some(&mut self.fps), Some(&mut self.fps),
) { ) {

View file

@ -213,6 +213,8 @@ impl Surface {
} else { } else {
None None
}, },
#[cfg(not(feature = "debug"))]
None,
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
Some(&mut self.fps), Some(&mut self.fps),
) { ) {

View file

@ -14,12 +14,13 @@ use crate::{
}, },
}; };
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_manager_v1::CursorMode; use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_manager_v1::CursorMode;
#[cfg(feature = "debug")]
use smithay::backend::renderer::glow::GlowRenderer;
use smithay::{ use smithay::{
backend::{ backend::{
drm::DrmNode, drm::DrmNode,
renderer::element::{default_primary_scanout_output_compare, RenderElementStates}, renderer::{
element::{default_primary_scanout_output_compare, RenderElementStates},
glow::GlowRenderer,
},
}, },
desktop::utils::{ desktop::utils::{
surface_presentation_feedback_flags_from_states, surface_primary_scanout_output, surface_presentation_feedback_flags_from_states, surface_primary_scanout_output,
@ -35,7 +36,7 @@ use smithay::{
Display, DisplayHandle, Display, DisplayHandle,
}, },
}, },
utils::{Clock, Monotonic, Rectangle}, utils::{Clock, Monotonic},
wayland::{ wayland::{
compositor::CompositorState, data_device::DataDeviceState, dmabuf::DmabufState, compositor::CompositorState, data_device::DataDeviceState, dmabuf::DmabufState,
keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState, output::OutputManagerState, keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState, output::OutputManagerState,
@ -45,7 +46,6 @@ use smithay::{
}; };
use std::{cell::RefCell, ffi::OsString, time::Duration}; use std::{cell::RefCell, ffi::OsString, time::Duration};
#[cfg(feature = "debug")]
use std::{collections::VecDeque, time::Instant}; use std::{collections::VecDeque, time::Instant};
pub struct ClientState { pub struct ClientState {
@ -432,14 +432,13 @@ pub struct Egui {
pub active: bool, pub active: bool,
} }
#[cfg(feature = "debug")]
pub struct Fps { pub struct Fps {
#[cfg(feature = "debug")]
pub state: smithay_egui::EguiState, pub state: smithay_egui::EguiState,
pending_frame: Option<PendingFrame>, pending_frame: Option<PendingFrame>,
pub frames: VecDeque<Frame>, pub frames: VecDeque<Frame>,
} }
#[cfg(feature = "debug")]
#[derive(Debug)] #[derive(Debug)]
struct PendingFrame { struct PendingFrame {
start: Instant, start: Instant,
@ -449,7 +448,6 @@ struct PendingFrame {
duration_displayed: Option<Duration>, duration_displayed: Option<Duration>,
} }
#[cfg(feature = "debug")]
#[derive(Debug)] #[derive(Debug)]
pub struct Frame { pub struct Frame {
pub start: Instant, pub start: Instant,
@ -459,8 +457,11 @@ pub struct Frame {
pub duration_displayed: Duration, pub duration_displayed: Duration,
} }
#[cfg(feature = "debug")]
impl Frame { impl Frame {
fn render_time(&self) -> Duration {
self.duration_elements + self.duration_render
}
fn frame_time(&self) -> Duration { fn frame_time(&self) -> Duration {
self.duration_elements self.duration_elements
+ self.duration_render + self.duration_render
@ -475,7 +476,6 @@ impl Frame {
} }
} }
#[cfg(feature = "debug")]
impl From<PendingFrame> for Frame { impl From<PendingFrame> for Frame {
fn from(pending: PendingFrame) -> Self { fn from(pending: PendingFrame) -> Self {
Frame { Frame {
@ -488,7 +488,6 @@ impl From<PendingFrame> for Frame {
} }
} }
#[cfg(feature = "debug")]
impl Fps { impl Fps {
const WINDOW_SIZE: usize = 360; const WINDOW_SIZE: usize = 360;
@ -582,6 +581,15 @@ impl Fps {
self.frames.iter().map(|f| f.frame_time()).sum::<Duration>() / (self.frames.len() as u32) self.frames.iter().map(|f| f.frame_time()).sum::<Duration>() / (self.frames.len() as u32)
} }
pub fn avg_rendertime(&self, window: usize) -> Duration {
self.frames
.iter()
.take(window)
.map(|f| f.render_time())
.sum::<Duration>()
/ window as u32
}
pub fn avg_fps(&self) -> f64 { pub fn avg_fps(&self) -> f64 {
if self.frames.is_empty() { if self.frames.is_empty() {
return 0.0; return 0.0;
@ -597,33 +605,38 @@ impl Fps {
} }
} }
#[cfg(feature = "debug")]
static INTEL_LOGO: &'static [u8] = include_bytes!("../resources/icons/intel.svg"); static INTEL_LOGO: &'static [u8] = include_bytes!("../resources/icons/intel.svg");
#[cfg(feature = "debug")]
static AMD_LOGO: &'static [u8] = include_bytes!("../resources/icons/amd.svg"); static AMD_LOGO: &'static [u8] = include_bytes!("../resources/icons/amd.svg");
#[cfg(feature = "debug")]
static NVIDIA_LOGO: &'static [u8] = include_bytes!("../resources/icons/nvidia.svg"); static NVIDIA_LOGO: &'static [u8] = include_bytes!("../resources/icons/nvidia.svg");
#[cfg(feature = "debug")]
impl Fps { impl Fps {
pub fn new(renderer: &mut GlowRenderer) -> Fps { pub fn new(_renderer: &mut GlowRenderer) -> Fps {
#[cfg(feature = "debug")]
let state = { let state = {
let state = let state = smithay_egui::EguiState::new(smithay::utils::Rectangle::from_loc_and_size(
smithay_egui::EguiState::new(Rectangle::from_loc_and_size((0, 0), (400, 800))); (0, 0),
(400, 800),
));
let mut visuals: egui::style::Visuals = Default::default(); let mut visuals: egui::style::Visuals = Default::default();
visuals.window_shadow.extrusion = 0.0; visuals.window_shadow.extrusion = 0.0;
state.context().set_visuals(visuals); state.context().set_visuals(visuals);
state state
.load_svg(_renderer, String::from("intel"), INTEL_LOGO)
.unwrap();
state
.load_svg(_renderer, String::from("amd"), AMD_LOGO)
.unwrap();
state
.load_svg(_renderer, String::from("nvidia"), NVIDIA_LOGO)
.unwrap();
state
}; };
state
.load_svg(renderer, String::from("intel"), INTEL_LOGO)
.unwrap();
state
.load_svg(renderer, String::from("amd"), AMD_LOGO)
.unwrap();
state
.load_svg(renderer, String::from("nvidia"), NVIDIA_LOGO)
.unwrap();
Fps { Fps {
#[cfg(feature = "debug")]
state, state,
pending_frame: None, pending_frame: None,
frames: VecDeque::with_capacity(Fps::WINDOW_SIZE + 1), frames: VecDeque::with_capacity(Fps::WINDOW_SIZE + 1),
@ -631,7 +644,6 @@ impl Fps {
} }
} }
#[cfg(feature = "debug")]
pub fn avg_fps<'a>(iter: impl Iterator<Item = &'a Duration>) -> f64 { pub fn avg_fps<'a>(iter: impl Iterator<Item = &'a Duration>) -> f64 {
let sum_secs = iter.map(|d| d.as_secs_f64()).sum::<f64>(); let sum_secs = iter.map(|d| d.as_secs_f64()).sum::<f64>();
1.0 / (sum_secs / Fps::WINDOW_SIZE as f64) 1.0 / (sum_secs / Fps::WINDOW_SIZE as f64)

View file

@ -619,7 +619,6 @@ pub fn render_output_to_buffer(
&output, &output,
cursor_mode, cursor_mode,
None, None,
#[cfg(feature = "debug")]
None, None,
) )
} else { } else {
@ -636,7 +635,6 @@ pub fn render_output_to_buffer(
&output, &output,
cursor_mode, cursor_mode,
None, None,
#[cfg(feature = "debug")]
None, None,
) )
} }
@ -700,7 +698,6 @@ pub fn render_workspace_to_buffer(
handle, handle,
cursor_mode, cursor_mode,
None, None,
#[cfg(feature = "debug")]
None, None,
) )
} else { } else {
@ -718,7 +715,6 @@ pub fn render_workspace_to_buffer(
handle, handle,
cursor_mode, cursor_mode,
None, None,
#[cfg(feature = "debug")]
None, None,
) )
} }