diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2024-12-20 08:49:18 +0300 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2024-12-22 15:19:46 +0300 |
| commit | fbb0054232fb859636ea7e32bdc45c71e185f0c6 (patch) | |
| tree | 0a36a33a9b38c91423854c17eb96ace9bd10f14a /src/backend | |
| parent | 2d3c36edae2cbce10ec57995c5a4418fb2424bd2 (diff) | |
| download | niri-fbb0054232fb859636ea7e32bdc45c71e185f0c6.tar.gz niri-fbb0054232fb859636ea7e32bdc45c71e185f0c6.tar.bz2 niri-fbb0054232fb859636ea7e32bdc45c71e185f0c6.zip | |
Add a Headless backend for tests
Rendering and stuff is unimplemented.
Diffstat (limited to 'src/backend')
| -rw-r--r-- | src/backend/headless.rs | 139 | ||||
| -rw-r--r-- | src/backend/mod.rs | 28 |
2 files changed, 167 insertions, 0 deletions
diff --git a/src/backend/headless.rs b/src/backend/headless.rs new file mode 100644 index 00000000..5b8c7428 --- /dev/null +++ b/src/backend/headless.rs @@ -0,0 +1,139 @@ +//! Headless backend for tests. +//! +//! This can eventually grow into a more complete backend if needed, but for now it's missing some +//! crucial parts like rendering. + +use std::mem; +use std::sync::{Arc, Mutex}; + +use niri_config::OutputName; +use smithay::backend::allocator::dmabuf::Dmabuf; +use smithay::backend::renderer::element::RenderElementStates; +use smithay::backend::renderer::gles::GlesRenderer; +use smithay::output::{Mode, Output, PhysicalProperties, Subpixel}; +use smithay::reexports::wayland_protocols::wp::presentation_time::server::wp_presentation_feedback; +use smithay::utils::Size; + +use super::{IpcOutputMap, OutputId, RenderResult}; +use crate::niri::{Niri, RedrawState}; +use crate::utils::{get_monotonic_time, logical_output}; + +pub struct Headless { + ipc_outputs: Arc<Mutex<IpcOutputMap>>, +} + +impl Headless { + pub fn new() -> Self { + Self { + ipc_outputs: Default::default(), + } + } + + pub fn init(&mut self, _niri: &mut Niri) {} + + pub fn add_output(&mut self, niri: &mut Niri, n: u8, size: (u16, u16)) { + let connector = format!("headless-{n}"); + let make = "niri".to_string(); + let model = "headless".to_string(); + let serial = n.to_string(); + + let output = Output::new( + connector.clone(), + PhysicalProperties { + size: (0, 0).into(), + subpixel: Subpixel::Unknown, + make: make.clone(), + model: model.clone(), + }, + ); + + let mode = Mode { + size: Size::from((i32::from(size.0), i32::from(size.1))), + refresh: 60_000, + }; + output.change_current_state(Some(mode), None, None, None); + output.set_preferred(mode); + + output.user_data().insert_if_missing(|| OutputName { + connector, + make: Some(make), + model: Some(model), + serial: Some(serial), + }); + + let physical_properties = output.physical_properties(); + self.ipc_outputs.lock().unwrap().insert( + OutputId::next(), + niri_ipc::Output { + name: output.name(), + make: physical_properties.make, + model: physical_properties.model, + serial: None, + physical_size: None, + modes: vec![niri_ipc::Mode { + width: size.0, + height: size.1, + refresh_rate: 60_000, + is_preferred: true, + }], + current_mode: Some(0), + vrr_supported: false, + vrr_enabled: false, + logical: Some(logical_output(&output)), + }, + ); + + niri.add_output(output, None, false); + } + + pub fn seat_name(&self) -> String { + "headless".to_owned() + } + + pub fn with_primary_renderer<T>( + &mut self, + _f: impl FnOnce(&mut GlesRenderer) -> T, + ) -> Option<T> { + None + } + + pub fn render(&mut self, niri: &mut Niri, output: &Output) -> RenderResult { + let states = RenderElementStates::default(); + let mut presentation_feedbacks = niri.take_presentation_feedbacks(output, &states); + presentation_feedbacks.presented::<_, smithay::utils::Monotonic>( + get_monotonic_time(), + std::time::Duration::ZERO, + 0, + wp_presentation_feedback::Kind::empty(), + ); + + let output_state = niri.output_state.get_mut(output).unwrap(); + match mem::replace(&mut output_state.redraw_state, RedrawState::Idle) { + RedrawState::Idle => unreachable!(), + RedrawState::Queued => (), + RedrawState::WaitingForVBlank { .. } => unreachable!(), + RedrawState::WaitingForEstimatedVBlank(_) => unreachable!(), + RedrawState::WaitingForEstimatedVBlankAndQueued(_) => unreachable!(), + } + + output_state.frame_callback_sequence = output_state.frame_callback_sequence.wrapping_add(1); + + // FIXME: request redraw on unfinished animations remain + + RenderResult::Submitted + } + + pub fn import_dmabuf(&mut self, _dmabuf: &Dmabuf) -> bool { + unimplemented!() + } + + pub fn ipc_outputs(&self) -> Arc<Mutex<IpcOutputMap>> { + self.ipc_outputs.clone() + } +} + +impl Default for Headless { + fn default() -> Self { + Self::new() + } +} diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 2213b8bd..9652eec9 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -17,9 +17,13 @@ pub use tty::Tty; pub mod winit; pub use winit::Winit; +pub mod headless; +pub use headless::Headless; + pub enum Backend { Tty(Tty), Winit(Winit), + Headless(Headless), } #[derive(PartialEq, Eq)] @@ -54,6 +58,7 @@ impl Backend { match self { Backend::Tty(tty) => tty.init(niri), Backend::Winit(winit) => winit.init(niri), + Backend::Headless(headless) => headless.init(niri), } } @@ -61,6 +66,7 @@ impl Backend { match self { Backend::Tty(tty) => tty.seat_name(), Backend::Winit(winit) => winit.seat_name(), + Backend::Headless(headless) => headless.seat_name(), } } @@ -71,6 +77,7 @@ impl Backend { match self { Backend::Tty(tty) => tty.with_primary_renderer(f), Backend::Winit(winit) => winit.with_primary_renderer(f), + Backend::Headless(headless) => headless.with_primary_renderer(f), } } @@ -83,6 +90,7 @@ impl Backend { match self { Backend::Tty(tty) => tty.render(niri, output, target_presentation_time), Backend::Winit(winit) => winit.render(niri, output), + Backend::Headless(headless) => headless.render(niri, output), } } @@ -90,6 +98,7 @@ impl Backend { match self { Backend::Tty(_) => CompositorMod::Super, Backend::Winit(_) => CompositorMod::Alt, + Backend::Headless(_) => CompositorMod::Super, } } @@ -97,6 +106,7 @@ impl Backend { match self { Backend::Tty(tty) => tty.change_vt(vt), Backend::Winit(_) => (), + Backend::Headless(_) => (), } } @@ -104,6 +114,7 @@ impl Backend { match self { Backend::Tty(tty) => tty.suspend(), Backend::Winit(_) => (), + Backend::Headless(_) => (), } } @@ -111,6 +122,7 @@ impl Backend { match self { Backend::Tty(tty) => tty.toggle_debug_tint(), Backend::Winit(winit) => winit.toggle_debug_tint(), + Backend::Headless(_) => (), } } @@ -118,6 +130,7 @@ impl Backend { match self { Backend::Tty(tty) => tty.import_dmabuf(dmabuf), Backend::Winit(winit) => winit.import_dmabuf(dmabuf), + Backend::Headless(headless) => headless.import_dmabuf(dmabuf), } } @@ -125,6 +138,7 @@ impl Backend { match self { Backend::Tty(tty) => tty.early_import(surface), Backend::Winit(_) => (), + Backend::Headless(_) => (), } } @@ -132,6 +146,7 @@ impl Backend { match self { Backend::Tty(tty) => tty.ipc_outputs(), Backend::Winit(winit) => winit.ipc_outputs(), + Backend::Headless(headless) => headless.ipc_outputs(), } } @@ -143,6 +158,7 @@ impl Backend { match self { Backend::Tty(tty) => tty.primary_gbm_device(), Backend::Winit(_) => None, + Backend::Headless(_) => None, } } @@ -150,6 +166,7 @@ impl Backend { match self { Backend::Tty(tty) => tty.set_monitors_active(active), Backend::Winit(_) => (), + Backend::Headless(_) => (), } } @@ -157,6 +174,7 @@ impl Backend { match self { Backend::Tty(tty) => tty.set_output_on_demand_vrr(niri, output, enable_vrr), Backend::Winit(_) => (), + Backend::Headless(_) => (), } } @@ -164,6 +182,7 @@ impl Backend { match self { Backend::Tty(tty) => tty.on_output_config_changed(niri), Backend::Winit(_) => (), + Backend::Headless(_) => (), } } @@ -171,6 +190,7 @@ impl Backend { match self { Backend::Tty(tty) => tty.on_debug_config_changed(), Backend::Winit(_) => (), + Backend::Headless(_) => (), } } @@ -197,4 +217,12 @@ impl Backend { panic!("backend is not Winit") } } + + pub fn headless(&mut self) -> &mut Headless { + if let Self::Headless(v) = self { + v + } else { + panic!("backend is not Headless") + } + } } |
