fix(kms): gate overlay scanout per-element by buffer GPU node
This commit is contained in:
parent
9d52653d5c
commit
012c77ec81
2 changed files with 95 additions and 42 deletions
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
init_shaders, output_elements,
|
||||
},
|
||||
config::ScreenFilter,
|
||||
shell::Shell,
|
||||
shell::{Shell, element::surface::ScanoutTargetNodeGuard},
|
||||
state::SurfaceDmabufFeedback,
|
||||
utils::prelude::*,
|
||||
wayland::handlers::{
|
||||
|
|
@ -1057,21 +1057,24 @@ impl SurfaceThreadState {
|
|||
vrr = has_active_fullscreen;
|
||||
}
|
||||
|
||||
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)),
|
||||
)
|
||||
.map_err(|err| {
|
||||
anyhow::format_err!("Failed to accumulate elements for rendering: {:?}", err)
|
||||
})?;
|
||||
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)
|
||||
})?
|
||||
};
|
||||
|
||||
if vrr && fullscreen_drives_refresh_rate && !self.timings.past_min_render_time(&self.clock)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use crate::{
|
|||
};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
cell::Cell,
|
||||
sync::{
|
||||
Mutex,
|
||||
atomic::{AtomicBool, Ordering},
|
||||
|
|
@ -14,11 +15,17 @@ use std::{
|
|||
};
|
||||
|
||||
use smithay::{
|
||||
backend::renderer::{
|
||||
ImportAll, Renderer,
|
||||
element::{
|
||||
AsRenderElements, Kind, RenderElementStates,
|
||||
surface::{WaylandSurfaceRenderElement, render_elements_from_surface_tree},
|
||||
backend::{
|
||||
drm::DrmNode,
|
||||
renderer::{
|
||||
ImportAll, Renderer,
|
||||
element::{
|
||||
AsRenderElements, Kind, RenderElementStates,
|
||||
surface::{
|
||||
KindEvaluation, WaylandSurfaceRenderElement, render_elements_from_surface_tree,
|
||||
},
|
||||
},
|
||||
utils::RendererSurfaceStateUserData,
|
||||
},
|
||||
},
|
||||
desktop::{
|
||||
|
|
@ -49,6 +56,7 @@ use smithay::{
|
|||
SubsurfaceCachedState, SurfaceData, TraversalAction, get_parent, with_states,
|
||||
with_surface_tree_downward,
|
||||
},
|
||||
dmabuf::get_dmabuf,
|
||||
seat::WaylandFocus,
|
||||
shell::xdg::{
|
||||
SurfaceCachedState, ToplevelCachedState, ToplevelSurface, XdgToplevelSurfaceData,
|
||||
|
|
@ -67,6 +75,66 @@ 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<Option<DrmNode>> = 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<DrmNode>);
|
||||
|
||||
impl ScanoutTargetNodeGuard {
|
||||
pub fn new(node: Option<DrmNode>) -> 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<DrmNode> {
|
||||
let surface_state = data.data_map.get::<RendererSurfaceStateUserData>()?;
|
||||
let surface_state = surface_state.lock().unwrap();
|
||||
surface_state
|
||||
.buffer()
|
||||
.and_then(|buffer| get_dmabuf(buffer).ok())
|
||||
.and_then(|dmabuf| dmabuf.node())
|
||||
}
|
||||
|
||||
/// Build the [`KindEvaluation`] for a window's surface tree.
|
||||
fn scanout_kind_eval(scanout_override: Option<bool>) -> KindEvaluation {
|
||||
match (scanout_override, SCANOUT_TARGET_NODE.with(|n| n.get())) {
|
||||
// Forced off.
|
||||
(Some(false), _) => Kind::Unspecified.into(),
|
||||
// No node restriction: preserve the previous behaviour exactly.
|
||||
(Some(true), None) => Kind::ScanoutCandidate.into(),
|
||||
(None, None) => FRAME_TIME_FILTER,
|
||||
// Node restriction in effect: only buffers on the scan-out node may be candidates.
|
||||
(Some(true), Some(node)) => KindEvaluation::Closure(Box::new(move |data| {
|
||||
if buffer_node(data) == Some(node) {
|
||||
Kind::ScanoutCandidate
|
||||
} else {
|
||||
Kind::Unspecified
|
||||
}
|
||||
})),
|
||||
(None, Some(node)) => KindEvaluation::Closure(Box::new(move |data| {
|
||||
if buffer_node(data) == Some(node)
|
||||
{
|
||||
frame_time_filter_fn(data)
|
||||
} else {
|
||||
Kind::Unspecified
|
||||
}
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
|
||||
pub struct CosmicSurface(pub Window);
|
||||
|
||||
|
|
@ -836,7 +904,7 @@ impl CosmicSurface {
|
|||
location + offset,
|
||||
scale,
|
||||
alpha,
|
||||
FRAME_TIME_FILTER,
|
||||
scanout_kind_eval(None),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
|
|
@ -868,16 +936,7 @@ impl CosmicSurface {
|
|||
location,
|
||||
scale,
|
||||
alpha,
|
||||
scanout_override
|
||||
.map(|val| {
|
||||
if val {
|
||||
Kind::ScanoutCandidate
|
||||
} else {
|
||||
Kind::Unspecified
|
||||
}
|
||||
.into()
|
||||
})
|
||||
.unwrap_or(FRAME_TIME_FILTER),
|
||||
scanout_kind_eval(scanout_override),
|
||||
)
|
||||
}
|
||||
WindowSurface::X11(surface) => {
|
||||
|
|
@ -891,16 +950,7 @@ impl CosmicSurface {
|
|||
location,
|
||||
scale,
|
||||
alpha,
|
||||
scanout_override
|
||||
.map(|val| {
|
||||
if val {
|
||||
Kind::ScanoutCandidate
|
||||
} else {
|
||||
Kind::Unspecified
|
||||
}
|
||||
.into()
|
||||
})
|
||||
.unwrap_or(FRAME_TIME_FILTER),
|
||||
scanout_kind_eval(scanout_override),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue