Move background rendering to Workspace

Per-output background-color doesn't work yet.
This commit is contained in:
Ivan Molodetskikh
2025-09-21 20:26:49 +03:00
parent d5f4e79e4c
commit a5e285865b
4 changed files with 56 additions and 42 deletions

View File

@@ -272,7 +272,7 @@ impl TestCase for Layout {
.monitor_for_output(&self.output) .monitor_for_output(&self.output)
.unwrap() .unwrap()
.render_elements(renderer, RenderTarget::Output, true) .render_elements(renderer, RenderTarget::Output, true)
.flat_map(|(_, iter)| iter) .flat_map(|(_, _, iter)| iter)
.map(|elem| Box::new(elem) as _) .map(|elem| Box::new(elem) as _)
.collect() .collect()
} }

View File

@@ -23,6 +23,7 @@ use crate::input::swipe_tracker::SwipeTracker;
use crate::niri_render_elements; use crate::niri_render_elements;
use crate::render_helpers::renderer::NiriRenderer; use crate::render_helpers::renderer::NiriRenderer;
use crate::render_helpers::shadow::ShadowRenderElement; use crate::render_helpers::shadow::ShadowRenderElement;
use crate::render_helpers::solid_color::SolidColorRenderElement;
use crate::render_helpers::RenderTarget; use crate::render_helpers::RenderTarget;
use crate::rubber_band::RubberBand; use crate::rubber_band::RubberBand;
use crate::utils::transaction::Transaction; use crate::utils::transaction::Transaction;
@@ -175,6 +176,7 @@ niri_render_elements! {
InsertHint = CropRenderElement<InsertHintRenderElement>, InsertHint = CropRenderElement<InsertHintRenderElement>,
UncroppedInsertHint = InsertHintRenderElement, UncroppedInsertHint = InsertHintRenderElement,
Shadow = ShadowRenderElement, Shadow = ShadowRenderElement,
SolidColor = SolidColorRenderElement,
} }
} }
@@ -1619,6 +1621,7 @@ impl<W: LayoutElement> Monitor<W> {
) -> impl Iterator< ) -> impl Iterator<
Item = ( Item = (
Rectangle<f64, Logical>, Rectangle<f64, Logical>,
MonitorRenderElement<R>,
impl Iterator<Item = MonitorRenderElement<R>> + 'a, impl Iterator<Item = MonitorRenderElement<R>> + 'a,
), ),
> { > {
@@ -1692,7 +1695,7 @@ impl<W: LayoutElement> Monitor<W> {
let iter = floating.chain(hint).chain(scrolling); let iter = floating.chain(hint).chain(scrolling);
let iter = iter.map(move |elem| { let scale_relocate = move |elem| {
let elem = RescaleRenderElement::from_element(elem, Point::from((0, 0)), zoom); let elem = RescaleRenderElement::from_element(elem, Point::from((0, 0)), zoom);
RelocateRenderElement::from_element( RelocateRenderElement::from_element(
elem, elem,
@@ -1702,9 +1705,14 @@ impl<W: LayoutElement> Monitor<W> {
geo.loc.to_physical_precise_round(scale), geo.loc.to_physical_precise_round(scale),
Relocate::Relative, Relocate::Relative,
) )
}); };
(geo, iter) let iter = iter.map(scale_relocate);
let background = ws.render_background();
let background = scale_relocate(MonitorInnerRenderElement::SolidColor(background));
(geo, background, iter)
}) })
} }

View File

@@ -6,6 +6,7 @@ use niri_config::{
CenterFocusedColumn, CornerRadius, OutputName, PresetSize, Workspace as WorkspaceConfig, CenterFocusedColumn, CornerRadius, OutputName, PresetSize, Workspace as WorkspaceConfig,
}; };
use niri_ipc::{ColumnDisplay, PositionChange, SizeChange, WindowLayout}; use niri_ipc::{ColumnDisplay, PositionChange, SizeChange, WindowLayout};
use smithay::backend::renderer::element::Kind;
use smithay::backend::renderer::gles::GlesRenderer; use smithay::backend::renderer::gles::GlesRenderer;
use smithay::desktop::{layer_map_for_output, Window}; use smithay::desktop::{layer_map_for_output, Window};
use smithay::output::Output; use smithay::output::Output;
@@ -29,6 +30,7 @@ use crate::animation::Clock;
use crate::niri_render_elements; use crate::niri_render_elements;
use crate::render_helpers::renderer::NiriRenderer; use crate::render_helpers::renderer::NiriRenderer;
use crate::render_helpers::shadow::ShadowRenderElement; use crate::render_helpers::shadow::ShadowRenderElement;
use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement};
use crate::render_helpers::RenderTarget; use crate::render_helpers::RenderTarget;
use crate::utils::id::IdCounter; use crate::utils::id::IdCounter;
use crate::utils::transaction::{Transaction, TransactionBlocker}; use crate::utils::transaction::{Transaction, TransactionBlocker};
@@ -87,6 +89,9 @@ pub struct Workspace<W: LayoutElement> {
/// This workspace's shadow in the overview. /// This workspace's shadow in the overview.
shadow: Shadow, shadow: Shadow,
/// This workspace's background.
background_buffer: SolidColorBuffer,
/// Clock for driving animations. /// Clock for driving animations.
pub(super) clock: Clock, pub(super) clock: Clock,
@@ -246,6 +251,8 @@ impl<W: LayoutElement> Workspace<W> {
let shadow_config = let shadow_config =
compute_workspace_shadow_config(options.overview.workspace_shadow, view_size); compute_workspace_shadow_config(options.overview.workspace_shadow, view_size);
let background_color = options.layout.background_color.to_array_unpremul();
Self { Self {
scrolling, scrolling,
floating, floating,
@@ -256,6 +263,7 @@ impl<W: LayoutElement> Workspace<W> {
view_size, view_size,
working_area, working_area,
shadow: Shadow::new(shadow_config), shadow: Shadow::new(shadow_config),
background_buffer: SolidColorBuffer::new(view_size, background_color),
output: Some(output), output: Some(output),
clock, clock,
base_options, base_options,
@@ -309,6 +317,8 @@ impl<W: LayoutElement> Workspace<W> {
let shadow_config = let shadow_config =
compute_workspace_shadow_config(options.overview.workspace_shadow, view_size); compute_workspace_shadow_config(options.overview.workspace_shadow, view_size);
let background_color = options.layout.background_color.to_array_unpremul();
Self { Self {
scrolling, scrolling,
floating, floating,
@@ -320,6 +330,7 @@ impl<W: LayoutElement> Workspace<W> {
view_size, view_size,
working_area, working_area,
shadow: Shadow::new(shadow_config), shadow: Shadow::new(shadow_config),
background_buffer: SolidColorBuffer::new(view_size, background_color),
clock, clock,
base_options, base_options,
options, options,
@@ -409,6 +420,9 @@ impl<W: LayoutElement> Workspace<W> {
compute_workspace_shadow_config(options.overview.workspace_shadow, self.view_size); compute_workspace_shadow_config(options.overview.workspace_shadow, self.view_size);
self.shadow.update_config(shadow_config); self.shadow.update_config(shadow_config);
let background_color = options.layout.background_color.to_array_unpremul();
self.background_buffer.set_color(background_color);
self.base_options = base_options; self.base_options = base_options;
self.options = options; self.options = options;
} }
@@ -563,6 +577,8 @@ impl<W: LayoutElement> Workspace<W> {
self.shadow.update_config(shadow_config); self.shadow.update_config(shadow_config);
} }
self.background_buffer.resize(size);
if scale_transform_changed { if scale_transform_changed {
for window in self.windows() { for window in self.windows() {
window.set_preferred_scale_transform(self.scale, self.transform); window.set_preferred_scale_transform(self.scale, self.transform);
@@ -1513,6 +1529,15 @@ impl<W: LayoutElement> Workspace<W> {
self.shadow.render(renderer, Point::from((0., 0.))) self.shadow.render(renderer, Point::from((0., 0.)))
} }
pub fn render_background(&self) -> SolidColorRenderElement {
SolidColorRenderElement::from_buffer(
&self.background_buffer,
Point::new(0., 0.),
1.,
Kind::Unspecified,
)
}
pub fn render_above_top_layer(&self) -> bool { pub fn render_above_top_layer(&self) -> bool {
self.scrolling.render_above_top_layer() self.scrolling.render_above_top_layer()
} }
@@ -1831,6 +1856,12 @@ impl<W: LayoutElement> Workspace<W> {
assert!(self.view_size.w > 0.); assert!(self.view_size.w > 0.);
assert!(self.view_size.h > 0.); assert!(self.view_size.h > 0.);
assert_eq!(self.background_buffer.size(), self.view_size);
assert_eq!(
self.background_buffer.color().components(),
options.layout.background_color.to_array_unpremul(),
);
assert_eq!(self.view_size, self.scrolling.view_size()); assert_eq!(self.view_size, self.scrolling.view_size());
assert_eq!(self.working_area, self.scrolling.parent_area()); assert_eq!(self.working_area, self.scrolling.parent_area());
assert_eq!(&self.clock, self.scrolling.clock()); assert_eq!(&self.clock, self.scrolling.clock());

View File

@@ -474,9 +474,8 @@ pub struct OutputState {
/// would occur, based on the last presentation time and output refresh interval. Sequence /// would occur, based on the last presentation time and output refresh interval. Sequence
/// is incremented in that timer, before attempting a redraw or sending frame callbacks. /// is incremented in that timer, before attempting a redraw or sending frame callbacks.
pub frame_callback_sequence: u32, pub frame_callback_sequence: u32,
/// Solid color buffer for the background that we use instead of clearing to avoid damage /// Solid color buffer for the backdrop that we use instead of clearing to avoid damage
/// tracking issues and make screenshots easier. /// tracking issues and make screenshots easier.
pub background_buffer: SolidColorBuffer,
pub backdrop_buffer: SolidColorBuffer, pub backdrop_buffer: SolidColorBuffer,
pub lock_render_state: LockRenderState, pub lock_render_state: LockRenderState,
pub lock_surface: Option<LockSurface>, pub lock_surface: Option<LockSurface>,
@@ -1655,12 +1654,6 @@ impl State {
resized_outputs.push(output.clone()); resized_outputs.push(output.clone());
} }
let background_color = config
.and_then(|c| c.background_color)
.unwrap_or_else(|| full_config.resolve_layout().background_color)
.to_array_unpremul();
let background_color = Color32F::from(background_color);
let mut backdrop_color = config let mut backdrop_color = config
.and_then(|c| c.backdrop_color) .and_then(|c| c.backdrop_color)
.unwrap_or(full_config.overview.backdrop_color) .unwrap_or(full_config.overview.backdrop_color)
@@ -1669,10 +1662,6 @@ impl State {
let backdrop_color = Color32F::from(backdrop_color); let backdrop_color = Color32F::from(backdrop_color);
if let Some(state) = self.niri.output_state.get_mut(output) { if let Some(state) = self.niri.output_state.get_mut(output) {
if state.background_buffer.color() != background_color {
state.background_buffer.set_color(background_color);
recolored_outputs.push(output.clone());
}
if state.backdrop_buffer.color() != backdrop_color { if state.backdrop_buffer.color() != backdrop_color {
state.backdrop_buffer.set_color(backdrop_color); state.backdrop_buffer.set_color(backdrop_color);
recolored_outputs.push(output.clone()); recolored_outputs.push(output.clone());
@@ -2904,11 +2893,6 @@ impl Niri {
.map(|c| ipc_transform_to_smithay(c.transform)) .map(|c| ipc_transform_to_smithay(c.transform))
.unwrap_or(Transform::Normal); .unwrap_or(Transform::Normal);
let background_color = c
.and_then(|c| c.background_color)
.unwrap_or_else(|| config.resolve_layout().background_color)
.to_array_unpremul();
let mut backdrop_color = c let mut backdrop_color = c
.and_then(|c| c.backdrop_color) .and_then(|c| c.backdrop_color)
.unwrap_or(config.overview.backdrop_color) .unwrap_or(config.overview.backdrop_color)
@@ -2947,7 +2931,6 @@ impl Niri {
frame_clock: FrameClock::new(refresh_interval, vrr), frame_clock: FrameClock::new(refresh_interval, vrr),
last_drm_sequence: None, last_drm_sequence: None,
frame_callback_sequence: 0, frame_callback_sequence: 0,
background_buffer: SolidColorBuffer::new(size, background_color),
backdrop_buffer: SolidColorBuffer::new(size, backdrop_color), backdrop_buffer: SolidColorBuffer::new(size, backdrop_color),
lock_render_state, lock_render_state,
lock_surface: None, lock_surface: None,
@@ -3056,7 +3039,6 @@ impl Niri {
self.layout.update_output_size(output); self.layout.update_output_size(output);
if let Some(state) = self.output_state.get_mut(output) { if let Some(state) = self.output_state.get_mut(output) {
state.background_buffer.resize(output_size);
state.backdrop_buffer.resize(output_size); state.backdrop_buffer.resize(output_size);
state.lock_color_buffer.resize(output_size); state.lock_color_buffer.resize(output_size);
@@ -4239,13 +4221,6 @@ impl Niri {
// Prepare the background elements. // Prepare the background elements.
let state = self.output_state.get(output).unwrap(); let state = self.output_state.get(output).unwrap();
let background_buffer = state.background_buffer.clone();
let background = SolidColorRenderElement::from_buffer(
&background_buffer,
(0., 0.),
1.,
Kind::Unspecified,
);
let backdrop = SolidColorRenderElement::from_buffer( let backdrop = SolidColorRenderElement::from_buffer(
&state.backdrop_buffer, &state.backdrop_buffer,
(0., 0.), (0., 0.),
@@ -4286,7 +4261,7 @@ impl Niri {
let zoom = mon.overview_zoom(); let zoom = mon.overview_zoom();
let monitor_elements = Vec::from_iter( let monitor_elements = Vec::from_iter(
mon.render_elements(renderer, target, focus_ring) mon.render_elements(renderer, target, focus_ring)
.map(|(geo, iter)| (geo, Vec::from_iter(iter))), .map(|(geo, bg, iter)| (geo, bg, Vec::from_iter(iter))),
); );
let workspace_shadow_elements = Vec::from_iter(mon.render_workspace_shadows(renderer)); let workspace_shadow_elements = Vec::from_iter(mon.render_workspace_shadows(renderer));
let insert_hint_elements = mon.render_insert_hint_between_workspaces(renderer); let insert_hint_elements = mon.render_insert_hint_between_workspaces(renderer);
@@ -4330,17 +4305,24 @@ impl Niri {
.into_iter() .into_iter()
.map(OutputRenderElements::from), .map(OutputRenderElements::from),
); );
let mut ws_background = None;
elements.extend( elements.extend(
monitor_elements monitor_elements
.into_iter() .into_iter()
.flat_map(|(_ws_geo, iter)| iter) .flat_map(|(_ws_geo, ws_bg, iter)| {
ws_background = Some(ws_bg);
iter
})
.map(OutputRenderElements::from), .map(OutputRenderElements::from),
); );
elements.extend(top_layer.into_iter().map(OutputRenderElements::from)); elements.extend(top_layer.into_iter().map(OutputRenderElements::from));
elements.extend(layer_elems.into_iter().map(OutputRenderElements::from)); elements.extend(layer_elems.into_iter().map(OutputRenderElements::from));
elements.push(OutputRenderElements::from(background)); if let Some(ws_background) = ws_background {
elements.push(OutputRenderElements::from(ws_background));
}
elements.extend( elements.extend(
workspace_shadow_elements workspace_shadow_elements
@@ -4362,7 +4344,7 @@ impl Niri {
.map(OutputRenderElements::from), .map(OutputRenderElements::from),
); );
for (ws_geo, ws_elements) in monitor_elements { for (ws_geo, ws_background, ws_elements) in monitor_elements {
// Collect all other layer-shell elements. // Collect all other layer-shell elements.
let mut layer_elems = SplitElements::default(); let mut layer_elems = SplitElements::default();
extend_from_layer(&mut layer_elems, Layer::Bottom, false); extend_from_layer(&mut layer_elems, Layer::Bottom, false);
@@ -4386,11 +4368,7 @@ impl Niri {
.map(OutputRenderElements::from), .map(OutputRenderElements::from),
); );
if let Some(elem) = elements.push(OutputRenderElements::from(ws_background));
scale_relocate_crop(background.clone(), output_scale, zoom, ws_geo)
{
elements.push(OutputRenderElements::from(elem));
}
} }
elements.extend( elements.extend(
@@ -6351,9 +6329,6 @@ niri_render_elements! {
Wayland = WaylandSurfaceRenderElement<R>, Wayland = WaylandSurfaceRenderElement<R>,
NamedPointer = MemoryRenderBufferRenderElement<R>, NamedPointer = MemoryRenderBufferRenderElement<R>,
SolidColor = SolidColorRenderElement, SolidColor = SolidColorRenderElement,
RelocatedSolidColor = CropRenderElement<RelocateRenderElement<RescaleRenderElement<
SolidColorRenderElement
>>>,
ScreenshotUi = ScreenshotUiRenderElement, ScreenshotUi = ScreenshotUiRenderElement,
ExitConfirmDialog = ExitConfirmDialogRenderElement, ExitConfirmDialog = ExitConfirmDialogRenderElement,
Texture = PrimaryGpuTextureRenderElement, Texture = PrimaryGpuTextureRenderElement,