From be1424f1ca79770dea88ab7b8793e6ea3abd1b5f Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Tue, 22 Jul 2025 16:31:56 +0200 Subject: [PATCH] render/wayland: filter scanout candidates by frametime estimation --- src/backend/render/cursor.rs | 4 ++-- src/backend/render/mod.rs | 20 +++++++++++--------- src/shell/element/surface.rs | 23 ++++++++++++++++++----- src/wayland/handlers/compositor.rs | 20 +++++++++++++++++++- 4 files changed, 50 insertions(+), 17 deletions(-) diff --git a/src/backend/render/cursor.rs b/src/backend/render/cursor.rs index 3abf7ad7..4d183823 100644 --- a/src/backend/render/cursor.rs +++ b/src/backend/render/cursor.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only -use crate::utils::prelude::*; +use crate::{utils::prelude::*, wayland::handlers::compositor::FRAME_TIME_FILTER}; use smithay::{ backend::{ allocator::Fourcc, @@ -182,7 +182,7 @@ where location.to_physical(scale).to_i32_round(), scale, 1.0, - Kind::Unspecified, + FRAME_TIME_FILTER, ) } diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index bf2fbfac..10fed897 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -26,6 +26,7 @@ use crate::{ utils::{prelude::*, quirks::workspace_overview_is_open}, wayland::{ handlers::{ + compositor::FRAME_TIME_FILTER, data_device::get_dnd_icon, screencopy::{render_session, FrameHolder, SessionData}, }, @@ -48,7 +49,7 @@ use smithay::{ constrain_render_elements, ConstrainAlign, ConstrainScaleBehavior, CropRenderElement, Relocate, RelocateRenderElement, RescaleRenderElement, }, - AsRenderElements, Element, Id, Kind, RenderElement, + Element, Id, Kind, RenderElement, }, gles::{ element::{PixelShaderElement, TextureShaderElement}, @@ -796,7 +797,7 @@ where .to_physical_precise_round(scale), Scale::from(scale), 1.0, - Kind::Unspecified, + FRAME_TIME_FILTER, ) .into_iter() .flat_map(crop_to_output) @@ -814,7 +815,7 @@ where .to_physical_precise_round(scale), Scale::from(scale), 1.0, - Kind::Unspecified, + FRAME_TIME_FILTER, ) .into_iter() .flat_map(crop_to_output) @@ -822,21 +823,22 @@ where ); } Stage::OverrideRedirect { surface, location } => { - elements.extend( - AsRenderElements::::render_elements::>( - surface, + elements.extend(surface.wl_surface().into_iter().flat_map(|surface| { + render_elements_from_surface_tree::<_, WorkspaceRenderElement<_>>( renderer, + &surface, location .to_local(output) .as_logical() .to_physical_precise_round(scale), Scale::from(scale), 1.0, + FRAME_TIME_FILTER, ) .into_iter() .flat_map(crop_to_output) - .map(Into::into), - ); + .map(Into::into) + })); } Stage::StickyPopups(layout) => { let alpha = match &overview.0 { @@ -1000,7 +1002,7 @@ where (0, 0), scale, 1.0, - Kind::Unspecified, + FRAME_TIME_FILTER, ) } else { Vec::new() diff --git a/src/shell/element/surface.rs b/src/shell/element/surface.rs index 3cb345a8..0f64bcf9 100644 --- a/src/shell/element/surface.rs +++ b/src/shell/element/surface.rs @@ -10,7 +10,6 @@ use std::{ use smithay::{ backend::renderer::{ element::{ - self, surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement}, utils::select_dmabuf_feedback, AsRenderElements, RenderElementStates, @@ -52,7 +51,10 @@ use tracing::trace; use crate::{ state::{State, SurfaceDmabufFeedback}, utils::prelude::*, - wayland::handlers::decoration::{KdeDecorationData, PreferredDecorationMode}, + wayland::handlers::{ + compositor::FRAME_TIME_FILTER, + decoration::{KdeDecorationData, PreferredDecorationMode}, + }, }; #[derive(Debug, Clone, PartialEq, Hash, Eq)] @@ -743,7 +745,7 @@ impl CosmicSurface { location + offset, scale, alpha, - element::Kind::Unspecified, + FRAME_TIME_FILTER, ) }) .collect() @@ -774,11 +776,22 @@ impl CosmicSurface { location, scale, alpha, - element::Kind::Unspecified, + FRAME_TIME_FILTER, ) } 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, + ) } } } diff --git a/src/wayland/handlers/compositor.rs b/src/wayland/handlers/compositor.rs index 8564b047..886de1db 100644 --- a/src/wayland/handlers/compositor.rs +++ b/src/wayland/handlers/compositor.rs @@ -3,7 +3,10 @@ use crate::{shell::grabs::SeatMoveGrabState, state::ClientState, utils::prelude::*}; use calloop::Interest; 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, desktop::{layer_map_for_output, LayerSurface, PopupKind, WindowSurfaceType}, reexports::wayland_server::{protocol::wl_surface::WlSurface, Client, Resource}, @@ -148,6 +151,21 @@ pub fn recursive_frame_time_estimation( overall_estimate } +pub const FRAME_TIME_FILTER: KindEvaluation = KindEvaluation::Dynamic({ + fn frame_time_filter_fn(states: &SurfaceData) -> Kind { + let clock = Clock::::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 { fn compositor_state(&mut self) -> &mut CompositorState { &mut self.common.compositor_state