From 031fdc389aaa4dac8546e0fc429bbea2295cc00d Mon Sep 17 00:00:00 2001 From: Ericky Dos Santos Date: Wed, 1 Jul 2026 11:05:56 -0400 Subject: [PATCH] kms: change from thread_local approach to wiring scanout node through function calls to detect scanout candidates --- src/backend/kms/device.rs | 1 + src/backend/kms/mod.rs | 3 +++ src/backend/kms/surface/mod.rs | 36 ++++++++++++------------- src/backend/render/mod.rs | 20 ++++++++++++-- src/shell/element/mod.rs | 17 ++++++++++-- src/shell/element/stack.rs | 10 ++++++- src/shell/element/surface.rs | 46 +++++++++++--------------------- src/shell/element/window.rs | 10 ++++++- src/shell/grabs/moving.rs | 11 +++++++- src/shell/layout/floating/mod.rs | 13 ++++++--- src/shell/layout/tiling/mod.rs | 31 ++++++++++++++++----- src/shell/workspace.rs | 10 ++++++- 12 files changed, 140 insertions(+), 68 deletions(-) diff --git a/src/backend/kms/device.rs b/src/backend/kms/device.rs index 2b0e8f9d..44682dc5 100644 --- a/src/backend/kms/device.rs +++ b/src/backend/kms/device.rs @@ -943,6 +943,7 @@ impl LockedDevice<'_> { output, CursorMode::All, None, + None, ) .with_context(|| "Failed to render outputs")?, None => Vec::new(), diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index 13832da8..16559e4e 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -978,6 +978,7 @@ impl KmsGuard<'_> { output, CursorMode::All, None, + None, ) .with_context(|| "Failed to render outputs")?; @@ -1088,6 +1089,7 @@ impl KmsGuard<'_> { output, CursorMode::All, None, + None, ) .with_context(|| "Failed to render outputs")?; @@ -1132,6 +1134,7 @@ impl KmsGuard<'_> { output, CursorMode::All, None, + None, ) .with_context(|| "Failed to render outputs")?; diff --git a/src/backend/kms/surface/mod.rs b/src/backend/kms/surface/mod.rs index fa196b87..a277af2e 100644 --- a/src/backend/kms/surface/mod.rs +++ b/src/backend/kms/surface/mod.rs @@ -8,7 +8,7 @@ use crate::{ init_shaders, output_elements, }, config::ScreenFilter, - shell::{Shell, element::surface::ScanoutTargetNodeGuard}, + shell::Shell, state::SurfaceDmabufFeedback, utils::prelude::*, wayland::handlers::{ @@ -1057,24 +1057,22 @@ impl SurfaceThreadState { vrr = has_active_fullscreen; } - let mut elements = { - let _scanout_node = ScanoutTargetNodeGuard::new(Some(self.target_node)); - output_elements( - Some(&render_node), - &mut renderer, - &self.shell, - self.clock.now(), - self.mirroring.as_ref().unwrap_or(&self.output), - CursorMode::All, - #[cfg(not(feature = "debug"))] - None, - #[cfg(feature = "debug")] - Some((&self.egui, &self.timings)), - ) - .map_err(|err| { - anyhow::format_err!("Failed to accumulate elements for rendering: {:?}", err) - })? - }; + let mut elements = output_elements( + Some(&render_node), + &mut renderer, + &self.shell, + self.clock.now(), + self.mirroring.as_ref().unwrap_or(&self.output), + CursorMode::All, + #[cfg(not(feature = "debug"))] + None, + #[cfg(feature = "debug")] + Some((&self.egui, &self.timings)), + Some(self.target_node), + ) + .map_err(|err| { + anyhow::format_err!("Failed to accumulate elements for rendering: {:?}", err) + })?; if vrr && fullscreen_drives_refresh_rate && !self.timings.past_min_render_time(&self.clock) { diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index bfbb21a3..d847f533 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -475,6 +475,7 @@ pub fn cursor_elements<'a, 'frame, R>( output: &Output, mode: CursorMode, exclude_dnd_icon: bool, + scanout_node: Option, ) -> Vec> where R: AsGlowRenderer, @@ -549,7 +550,14 @@ where .lock() .unwrap() .as_ref() - .map(|state| state.render::, R>(renderer, output, theme)) + .map(|state| { + state.render::, R>( + renderer, + output, + theme, + scanout_node, + ) + }) { elements.extend(grab_elements.into_iter().map(|elem| { CosmicElement::MoveGrab(RescaleRenderElement::from_element( @@ -615,6 +623,7 @@ pub fn output_elements( output: &Output, cursor_mode: CursorMode, _fps: Option<(&EguiState, &Timings)>, + scanout_node: Option, ) -> Result>, RenderError> where R: AsGlowRenderer, @@ -690,6 +699,7 @@ where workspace, cursor_mode, element_filter, + scanout_node, )?; #[cfg(feature = "debug")] @@ -713,6 +723,7 @@ pub fn workspace_elements( current: (WorkspaceHandle, usize), cursor_mode: CursorMode, element_filter: ElementFilter, + scanout_node: Option, ) -> Result>, RenderError> where R: AsGlowRenderer, @@ -743,6 +754,7 @@ where output, cursor_mode, element_filter == ElementFilter::ExcludeWorkspaceOverview, + scanout_node, )); let shell = shell.read(); @@ -907,7 +919,7 @@ where elements.extend( layout - .render_popups(renderer, alpha) + .render_popups(renderer, alpha, scanout_node) .into_iter() .map(Into::into) .flat_map(crop_to_output) @@ -951,6 +963,7 @@ where active_hint, alpha, theme.cosmic(), + scanout_node, ) .into_iter() .map(Into::into) @@ -966,6 +979,7 @@ where !move_active && is_active_space, overview.clone(), theme.cosmic(), + scanout_node, ) { Ok(elements) => { elements @@ -995,6 +1009,7 @@ where resize_indicator.clone(), active_hint, theme.cosmic(), + scanout_node, ) { Ok(elements) => { elements @@ -1511,6 +1526,7 @@ where current, cursor_mode, element_filter, + None, )?; if let Some(additional_damage) = additional_damage { diff --git a/src/shell/element/mod.rs b/src/shell/element/mod.rs index f58259bf..8639aeb6 100644 --- a/src/shell/element/mod.rs +++ b/src/shell/element/mod.rs @@ -8,6 +8,7 @@ use cosmic_comp_config::AppearanceConfig; use id_tree::NodeId; use smithay::{ backend::{ + drm::DrmNode, input::KeyState, renderer::{ element::{ @@ -589,6 +590,7 @@ impl CosmicMapped { location: smithay::utils::Point, scale: smithay::utils::Scale, alpha: f32, + scanout_node: Option, ) -> Vec where R: AsGlowRenderer, @@ -599,11 +601,19 @@ impl CosmicMapped { match &self.element { CosmicMappedInternal::Stack(s) => s .popup_render_elements::>( - renderer, location, scale, alpha, + renderer, + location, + scale, + alpha, + scanout_node, ), CosmicMappedInternal::Window(w) => w .popup_render_elements::>( - renderer, location, scale, alpha, + renderer, + location, + scale, + alpha, + scanout_node, ), _ => unreachable!(), } @@ -664,6 +674,7 @@ impl CosmicMapped { scale: smithay::utils::Scale, alpha: f32, scanout_override: Option, + scanout_node: Option, ) -> Vec where R: AsGlowRenderer, @@ -854,6 +865,7 @@ impl CosmicMapped { scale, alpha, scanout_override, + scanout_node, ), CosmicMappedInternal::Window(w) => w .render_elements::>( @@ -863,6 +875,7 @@ impl CosmicMapped { scale, alpha, scanout_override, + scanout_node, ), _ => unreachable!(), }); diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index 9f8584f5..17df320f 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -37,6 +37,7 @@ use cosmic_settings_config::shortcuts; use shortcuts::action::{Direction, FocusDirection}; use smithay::{ backend::{ + drm::DrmNode, input::KeyState, renderer::{ ImportAll, ImportMem, Renderer, @@ -654,6 +655,7 @@ impl CosmicStack { location: Point, scale: Scale, alpha: f32, + scanout_node: Option, ) -> Vec where R: AsGlowRenderer, @@ -667,7 +669,11 @@ impl CosmicStack { windows[active] .popup_render_elements::>( - renderer, window_loc, scale, alpha, + renderer, + window_loc, + scale, + alpha, + scanout_node, ) .into_iter() .map(C::from) @@ -750,6 +756,7 @@ impl CosmicStack { scale: Scale, alpha: f32, scanout_override: Option, + scanout_node: Option, ) -> Vec where R: AsGlowRenderer, @@ -823,6 +830,7 @@ impl CosmicStack { scale, alpha, scanout_override, + scanout_node, ) .into_iter() .map(move |elem| { diff --git a/src/shell/element/surface.rs b/src/shell/element/surface.rs index 8b0a606e..2bd72f25 100644 --- a/src/shell/element/surface.rs +++ b/src/shell/element/surface.rs @@ -6,7 +6,6 @@ use crate::{ }; use std::{ borrow::Cow, - cell::Cell, sync::{ Mutex, atomic::{AtomicBool, Ordering}, @@ -75,29 +74,6 @@ use crate::{ }, }; -thread_local! { - /// The scan-out target [`DrmNode`] of the surface thread that is currently accumulating - /// render elements, if any. - static SCANOUT_TARGET_NODE: Cell> = const { Cell::new(None) }; -} - -/// RAII guard that sets the current thread's scan-out target node and restores the previous value -/// on drop. Hold it only across render-element accumulation so the gate can't outlive a render pass. -/// See [`SCANOUT_TARGET_NODE`]. -pub struct ScanoutTargetNodeGuard(Option); - -impl ScanoutTargetNodeGuard { - pub fn new(node: Option) -> Self { - ScanoutTargetNodeGuard(SCANOUT_TARGET_NODE.with(|n| n.replace(node))) - } -} - -impl Drop for ScanoutTargetNodeGuard { - fn drop(&mut self) { - SCANOUT_TARGET_NODE.with(|n| n.set(self.0)); - } -} - /// The [`DrmNode`] the surface's currently committed buffer was allocated on, if it is a dmabuf. fn buffer_node(data: &SurfaceData) -> Option { let surface_state = data.data_map.get::()?; @@ -109,8 +85,15 @@ fn buffer_node(data: &SurfaceData) -> Option { } /// Build the [`KindEvaluation`] for a window's surface tree. -fn scanout_kind_eval(scanout_override: Option) -> KindEvaluation { - match (scanout_override, SCANOUT_TARGET_NODE.with(|n| n.get())) { +/// +/// `scanout_node`, when set, is the scan-out target [`DrmNode`] of the output currently being +/// rendered: only buffers allocated on that node may be promoted to overlay scan-out candidates. +/// It is `None` for render passes that never scan out to a plane (e.g. screen-copy). +fn scanout_kind_eval( + scanout_override: Option, + scanout_node: Option, +) -> KindEvaluation { + match (scanout_override, scanout_node) { // Forced off. (Some(false), _) => Kind::Unspecified.into(), // No node restriction: preserve the previous behaviour exactly. @@ -125,8 +108,7 @@ fn scanout_kind_eval(scanout_override: Option) -> KindEvaluation { } })), (None, Some(node)) => KindEvaluation::Closure(Box::new(move |data| { - if buffer_node(data) == Some(node) - { + if buffer_node(data) == Some(node) { frame_time_filter_fn(data) } else { Kind::Unspecified @@ -884,6 +866,7 @@ impl CosmicSurface { location: Point, scale: Scale, alpha: f32, + scanout_node: Option, ) -> Vec where R: Renderer + ImportAll, @@ -904,7 +887,7 @@ impl CosmicSurface { location + offset, scale, alpha, - scanout_kind_eval(None), + scanout_kind_eval(None, scanout_node), ) }) .collect() @@ -920,6 +903,7 @@ impl CosmicSurface { scale: Scale, alpha: f32, scanout_override: Option, + scanout_node: Option, ) -> Vec where R: Renderer + ImportAll, @@ -936,7 +920,7 @@ impl CosmicSurface { location, scale, alpha, - scanout_kind_eval(scanout_override), + scanout_kind_eval(scanout_override, scanout_node), ) } WindowSurface::X11(surface) => { @@ -950,7 +934,7 @@ impl CosmicSurface { location, scale, alpha, - scanout_kind_eval(scanout_override), + scanout_kind_eval(scanout_override, scanout_node), ) } } diff --git a/src/shell/element/window.rs b/src/shell/element/window.rs index 0adbfab7..52ffd16d 100644 --- a/src/shell/element/window.rs +++ b/src/shell/element/window.rs @@ -23,6 +23,7 @@ use cosmic::iced::{Color, Task}; use cosmic_comp_config::AppearanceConfig; use smithay::{ backend::{ + drm::DrmNode, input::KeyState, renderer::{ ImportAll, ImportMem, Renderer, @@ -357,6 +358,7 @@ impl CosmicWindow { location: Point, scale: Scale, alpha: f32, + scanout_node: Option, ) -> Vec where R: Renderer + ImportAll + ImportMem, @@ -374,7 +376,11 @@ impl CosmicWindow { self.0.with_program(|p| { p.window .popup_render_elements::>( - renderer, window_loc, scale, alpha, + renderer, + window_loc, + scale, + alpha, + scanout_node, ) .into_iter() .map(C::from) @@ -470,6 +476,7 @@ impl CosmicWindow { scale: Scale, alpha: f32, scanout_override: Option, + scanout_node: Option, ) -> Vec where R: AsGlowRenderer, @@ -553,6 +560,7 @@ impl CosmicWindow { scale, alpha, scanout_override, + scanout_node, ) }); if window_elements.is_empty() { diff --git a/src/shell/grabs/moving.rs b/src/shell/grabs/moving.rs index e73b108d..1fd8a9b6 100644 --- a/src/shell/grabs/moving.rs +++ b/src/shell/grabs/moving.rs @@ -21,6 +21,7 @@ use calloop::LoopHandle; use cosmic::theme::CosmicTheme; use smithay::{ backend::{ + drm::DrmNode, input::ButtonState, renderer::{ ImportAll, ImportMem, Renderer, @@ -68,7 +69,13 @@ pub struct MoveGrabState { impl MoveGrabState { #[profiling::function] - pub fn render(&self, renderer: &mut R, output: &Output, theme: &CosmicTheme) -> Vec + pub fn render( + &self, + renderer: &mut R, + output: &Output, + theme: &CosmicTheme, + scanout_node: Option, + ) -> Vec where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, @@ -198,6 +205,7 @@ impl MoveGrabState { output_scale, alpha, Some(false), + scanout_node, ); let p_elements = self .window @@ -207,6 +215,7 @@ impl MoveGrabState { .to_physical_precise_round(output_scale), output_scale, alpha, + scanout_node, ); let shadow_element = self.window.shadow_render_element( renderer, diff --git a/src/shell/layout/floating/mod.rs b/src/shell/layout/floating/mod.rs index e3829e58..84677188 100644 --- a/src/shell/layout/floating/mod.rs +++ b/src/shell/layout/floating/mod.rs @@ -10,9 +10,12 @@ use cosmic_comp_config::AppearanceConfig; use cosmic_settings_config::shortcuts::action::ResizeDirection; use keyframe::{ease, functions::EaseInOutCubic}; use smithay::{ - backend::renderer::element::{ - AsRenderElements, RenderElement, - utils::{Relocate, RelocateRenderElement, RescaleRenderElement}, + backend::{ + drm::DrmNode, + renderer::element::{ + AsRenderElements, RenderElement, + utils::{Relocate, RelocateRenderElement, RescaleRenderElement}, + }, }, desktop::{PopupKind, Space, WindowSurfaceType, layer_map_for_output, space::SpaceElement}, input::Seat, @@ -1439,6 +1442,7 @@ impl FloatingLayout { &self, renderer: &mut R, alpha: f32, + scanout_node: Option, ) -> Vec> where R: AsGlowRenderer, @@ -1474,6 +1478,7 @@ impl FloatingLayout { .to_physical_precise_round(output_scale), output_scale.into(), alpha, + scanout_node, ), ); } @@ -1490,6 +1495,7 @@ impl FloatingLayout { indicator_thickness: u8, alpha: f32, theme: &cosmic::theme::CosmicTheme, + scanout_node: Option, ) -> Vec> where R: AsGlowRenderer, @@ -1530,6 +1536,7 @@ impl FloatingLayout { output_scale.into(), alpha, None, + scanout_node, ); window_elements.extend( elem.shadow_render_element( diff --git a/src/shell/layout/tiling/mod.rs b/src/shell/layout/tiling/mod.rs index e7a7f0f1..45ca985e 100644 --- a/src/shell/layout/tiling/mod.rs +++ b/src/shell/layout/tiling/mod.rs @@ -46,15 +46,18 @@ use keyframe::{ functions::{EaseInOutCubic, Linear}, }; use smithay::{ - backend::renderer::{ - element::{ - AsRenderElements, Id, RenderElement, - utils::{ - ConstrainAlign, ConstrainScaleBehavior, RescaleRenderElement, - constrain_render_elements, + backend::{ + drm::DrmNode, + renderer::{ + element::{ + AsRenderElements, Id, RenderElement, + utils::{ + ConstrainAlign, ConstrainScaleBehavior, RescaleRenderElement, + constrain_render_elements, + }, }, + glow::GlowRenderer, }, - glow::GlowRenderer, }, desktop::{PopupKind, WindowSurfaceType, layer_map_for_output, space::SpaceElement}, input::Seat, @@ -4007,6 +4010,7 @@ impl TilingLayout { resize_indicator: Option<(ResizeMode, ResizeIndicator)>, indicator_thickness: u8, theme: &cosmic::theme::CosmicTheme, + scanout_node: Option, ) -> Result>, OutputNotMapped> where R: AsGlowRenderer, @@ -4093,6 +4097,7 @@ impl TilingLayout { indicator_thickness, swap_desc.is_some(), theme, + scanout_node, )); geometries @@ -4149,6 +4154,7 @@ impl TilingLayout { &self.swapping_stack_surface_id, &self.backdrop_id, theme, + scanout_node, )); // tiling hints @@ -4167,6 +4173,7 @@ impl TilingLayout { non_exclusive_zone: Rectangle, overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree>)>), theme: &cosmic::theme::CosmicTheme, + scanout_node: Option, ) -> Result>, OutputNotMapped> where R: AsGlowRenderer, @@ -4242,6 +4249,7 @@ impl TilingLayout { output_scale, percentage, swap_desc.is_some(), + scanout_node, )); geometries @@ -4281,6 +4289,7 @@ impl TilingLayout { percentage, overview, swap_desc.clone(), + scanout_node, )); Ok(elements) @@ -4973,6 +4982,7 @@ fn render_old_tree_popups( output_scale: f64, percentage: f32, is_swap_mode: bool, + scanout_node: Option, ) -> Vec> where R: AsGlowRenderer, @@ -4998,6 +5008,7 @@ where - elem_geometry.loc, Scale::from(output_scale), alpha, + scanout_node, ), ); }, @@ -5016,6 +5027,7 @@ fn render_old_tree_windows( indicator_thickness: u8, is_swap_mode: bool, theme: &cosmic::theme::CosmicTheme, + scanout_node: Option, ) -> Vec> where R: AsGlowRenderer, @@ -5052,6 +5064,7 @@ where Scale::from(output_scale), alpha, None, + scanout_node, ); elements.extend(window_elements.into_iter().flat_map(|element| { @@ -5196,6 +5209,7 @@ fn render_new_tree_popups( percentage: f32, overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree>)>), swap_desc: Option, + scanout_node: Option, ) -> Vec> where R: AsGlowRenderer, @@ -5234,6 +5248,7 @@ where - elem_geometry.loc, Scale::from(output_scale), alpha, + scanout_node, ), ); } @@ -5262,6 +5277,7 @@ fn render_new_tree_windows( swapping_stack_surface_id: &Id, backdrop_id: &Id, theme: &cosmic::theme::CosmicTheme, + scanout_node: Option, ) -> Vec> where R: AsGlowRenderer, @@ -5597,6 +5613,7 @@ where Scale::from(output_scale), alpha, None, + scanout_node, ); if swap_desc diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index 2b4db98c..f4e3dcab 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -31,6 +31,7 @@ use cosmic_protocols::workspace::v2::server::zcosmic_workspace_handle_v2::Tiling use id_tree::Tree; use indexmap::IndexSet; use keyframe::{ease, functions::EaseInOutCubic}; +use smithay::backend::drm::DrmNode; use smithay::backend::renderer::element::Kind; use smithay::output::WeakOutput; use smithay::utils::user_data::UserDataMap; @@ -1612,6 +1613,7 @@ impl Workspace { resize_indicator: Option<(ResizeMode, ResizeIndicator)>, indicator_thickness: u8, theme: &CosmicTheme, + scanout_node: Option, ) -> Result>, OutputNotMapped> where R: AsGlowRenderer, @@ -1700,6 +1702,7 @@ impl Workspace { output_scale.into(), alpha, Some(true), + scanout_node, ) .into_iter() .map(animation_rescale) @@ -1772,6 +1775,7 @@ impl Workspace { indicator_thickness, alpha, theme, + scanout_node, ) .into_iter() .map(WorkspaceRenderElement::from), @@ -1801,6 +1805,7 @@ impl Workspace { resize_indicator, indicator_thickness, theme, + scanout_node, )? .into_iter() .map(WorkspaceRenderElement::from), @@ -1836,6 +1841,7 @@ impl Workspace { render_focus: bool, overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree>)>), theme: &CosmicTheme, + scanout_node: Option, ) -> Result>, OutputNotMapped> where R: AsGlowRenderer, @@ -1909,6 +1915,7 @@ impl Workspace { render_loc, output_scale.into(), alpha, + scanout_node, ) .into_iter() .map(Into::into), @@ -1947,7 +1954,7 @@ impl Workspace { elements.extend( self.floating_layer - .render_popups::(renderer, alpha) + .render_popups::(renderer, alpha, scanout_node) .into_iter() .map(WorkspaceRenderElement::from), ); @@ -1961,6 +1968,7 @@ impl Workspace { zone, overview, theme, + scanout_node, )? .into_iter() .map(WorkspaceRenderElement::from),