render/wayland: filter scanout candidates by frametime estimation

This commit is contained in:
Victoria Brekenfeld 2025-07-22 16:31:56 +02:00 committed by Victoria Brekenfeld
parent db9380e6db
commit be1424f1ca
4 changed files with 50 additions and 17 deletions

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use crate::utils::prelude::*; use crate::{utils::prelude::*, wayland::handlers::compositor::FRAME_TIME_FILTER};
use smithay::{ use smithay::{
backend::{ backend::{
allocator::Fourcc, allocator::Fourcc,
@ -182,7 +182,7 @@ where
location.to_physical(scale).to_i32_round(), location.to_physical(scale).to_i32_round(),
scale, scale,
1.0, 1.0,
Kind::Unspecified, FRAME_TIME_FILTER,
) )
} }

View file

@ -26,6 +26,7 @@ use crate::{
utils::{prelude::*, quirks::workspace_overview_is_open}, utils::{prelude::*, quirks::workspace_overview_is_open},
wayland::{ wayland::{
handlers::{ handlers::{
compositor::FRAME_TIME_FILTER,
data_device::get_dnd_icon, data_device::get_dnd_icon,
screencopy::{render_session, FrameHolder, SessionData}, screencopy::{render_session, FrameHolder, SessionData},
}, },
@ -48,7 +49,7 @@ use smithay::{
constrain_render_elements, ConstrainAlign, ConstrainScaleBehavior, constrain_render_elements, ConstrainAlign, ConstrainScaleBehavior,
CropRenderElement, Relocate, RelocateRenderElement, RescaleRenderElement, CropRenderElement, Relocate, RelocateRenderElement, RescaleRenderElement,
}, },
AsRenderElements, Element, Id, Kind, RenderElement, Element, Id, Kind, RenderElement,
}, },
gles::{ gles::{
element::{PixelShaderElement, TextureShaderElement}, element::{PixelShaderElement, TextureShaderElement},
@ -796,7 +797,7 @@ where
.to_physical_precise_round(scale), .to_physical_precise_round(scale),
Scale::from(scale), Scale::from(scale),
1.0, 1.0,
Kind::Unspecified, FRAME_TIME_FILTER,
) )
.into_iter() .into_iter()
.flat_map(crop_to_output) .flat_map(crop_to_output)
@ -814,7 +815,7 @@ where
.to_physical_precise_round(scale), .to_physical_precise_round(scale),
Scale::from(scale), Scale::from(scale),
1.0, 1.0,
Kind::Unspecified, FRAME_TIME_FILTER,
) )
.into_iter() .into_iter()
.flat_map(crop_to_output) .flat_map(crop_to_output)
@ -822,21 +823,22 @@ where
); );
} }
Stage::OverrideRedirect { surface, location } => { Stage::OverrideRedirect { surface, location } => {
elements.extend( elements.extend(surface.wl_surface().into_iter().flat_map(|surface| {
AsRenderElements::<R>::render_elements::<WorkspaceRenderElement<R>>( render_elements_from_surface_tree::<_, WorkspaceRenderElement<_>>(
surface,
renderer, renderer,
&surface,
location location
.to_local(output) .to_local(output)
.as_logical() .as_logical()
.to_physical_precise_round(scale), .to_physical_precise_round(scale),
Scale::from(scale), Scale::from(scale),
1.0, 1.0,
FRAME_TIME_FILTER,
) )
.into_iter() .into_iter()
.flat_map(crop_to_output) .flat_map(crop_to_output)
.map(Into::into), .map(Into::into)
); }));
} }
Stage::StickyPopups(layout) => { Stage::StickyPopups(layout) => {
let alpha = match &overview.0 { let alpha = match &overview.0 {
@ -1000,7 +1002,7 @@ where
(0, 0), (0, 0),
scale, scale,
1.0, 1.0,
Kind::Unspecified, FRAME_TIME_FILTER,
) )
} else { } else {
Vec::new() Vec::new()

View file

@ -10,7 +10,6 @@ use std::{
use smithay::{ use smithay::{
backend::renderer::{ backend::renderer::{
element::{ element::{
self,
surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement}, surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement},
utils::select_dmabuf_feedback, utils::select_dmabuf_feedback,
AsRenderElements, RenderElementStates, AsRenderElements, RenderElementStates,
@ -52,7 +51,10 @@ use tracing::trace;
use crate::{ use crate::{
state::{State, SurfaceDmabufFeedback}, state::{State, SurfaceDmabufFeedback},
utils::prelude::*, utils::prelude::*,
wayland::handlers::decoration::{KdeDecorationData, PreferredDecorationMode}, wayland::handlers::{
compositor::FRAME_TIME_FILTER,
decoration::{KdeDecorationData, PreferredDecorationMode},
},
}; };
#[derive(Debug, Clone, PartialEq, Hash, Eq)] #[derive(Debug, Clone, PartialEq, Hash, Eq)]
@ -743,7 +745,7 @@ impl CosmicSurface {
location + offset, location + offset,
scale, scale,
alpha, alpha,
element::Kind::Unspecified, FRAME_TIME_FILTER,
) )
}) })
.collect() .collect()
@ -774,11 +776,22 @@ impl CosmicSurface {
location, location,
scale, scale,
alpha, alpha,
element::Kind::Unspecified, FRAME_TIME_FILTER,
) )
} }
WindowSurface::X11(surface) => { WindowSurface::X11(surface) => {
surface.render_elements(renderer, location, scale, alpha) let Some(surface) = surface.wl_surface() else {
return Vec::new();
};
render_elements_from_surface_tree(
renderer,
&surface,
location,
scale,
alpha,
FRAME_TIME_FILTER,
)
} }
} }
} }

View file

@ -3,7 +3,10 @@
use crate::{shell::grabs::SeatMoveGrabState, state::ClientState, utils::prelude::*}; use crate::{shell::grabs::SeatMoveGrabState, state::ClientState, utils::prelude::*};
use calloop::Interest; use calloop::Interest;
use smithay::{ use smithay::{
backend::renderer::utils::{on_commit_buffer_handler, with_renderer_surface_state}, backend::renderer::{
element::{surface::KindEvaluation, Kind},
utils::{on_commit_buffer_handler, with_renderer_surface_state},
},
delegate_compositor, delegate_compositor,
desktop::{layer_map_for_output, LayerSurface, PopupKind, WindowSurfaceType}, desktop::{layer_map_for_output, LayerSurface, PopupKind, WindowSurfaceType},
reexports::wayland_server::{protocol::wl_surface::WlSurface, Client, Resource}, reexports::wayland_server::{protocol::wl_surface::WlSurface, Client, Resource},
@ -148,6 +151,21 @@ pub fn recursive_frame_time_estimation(
overall_estimate overall_estimate
} }
pub const FRAME_TIME_FILTER: KindEvaluation = KindEvaluation::Dynamic({
fn frame_time_filter_fn(states: &SurfaceData) -> Kind {
let clock = Clock::<Monotonic>::new();
const _20_FPS: Duration = Duration::from_nanos(1_000_000_000 / 20);
if frame_time_estimation(&clock, states).is_some_and(|dur| dur <= _20_FPS) {
Kind::ScanoutCandidate
} else {
Kind::Unspecified
}
}
frame_time_filter_fn
});
impl CompositorHandler for State { impl CompositorHandler for State {
fn compositor_state(&mut self) -> &mut CompositorState { fn compositor_state(&mut self) -> &mut CompositorState {
&mut self.common.compositor_state &mut self.common.compositor_state