diff options
| author | Shaun Ren <shaun.ren@linux.com> | 2025-08-30 20:42:46 -0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2025-10-02 10:02:16 +0300 |
| commit | 5c91e3191dff08177740d642344d9eb67122139d (patch) | |
| tree | 7722c928bbc9e855c28266a65939bb9d2026525e | |
| parent | b7f1e382a28961216afa6916c9c704e08a3c9617 (diff) | |
| download | niri-5c91e3191dff08177740d642344d9eb67122139d.tar.gz niri-5c91e3191dff08177740d642344d9eb67122139d.tar.bz2 niri-5c91e3191dff08177740d642344d9eb67122139d.zip | |
tty: Add support for disabling DRM devices
| -rw-r--r-- | docs/wiki/Configuration:-Debug-Options.md | 16 | ||||
| -rw-r--r-- | niri-config/src/debug.rs | 6 | ||||
| -rw-r--r-- | niri-config/src/lib.rs | 6 | ||||
| -rw-r--r-- | src/backend/tty.rs | 81 | ||||
| -rw-r--r-- | src/niri.rs | 4 |
5 files changed, 109 insertions, 4 deletions
diff --git a/docs/wiki/Configuration:-Debug-Options.md b/docs/wiki/Configuration:-Debug-Options.md index 3bf2d70e..5dea65f2 100644 --- a/docs/wiki/Configuration:-Debug-Options.md +++ b/docs/wiki/Configuration:-Debug-Options.md @@ -18,6 +18,8 @@ debug { disable-direct-scanout restrict-primary-scanout-to-matching-format render-drm-device "/dev/dri/renderD129" + ignore-drm-device "/dev/dri/renderD128" + ignore-drm-device "/dev/dri/renderD130" force-pipewire-invalid-modifier dbus-interfaces-in-non-session-instances wait-for-frame-completion-before-queueing @@ -115,6 +117,20 @@ debug { } ``` +### `ignore-drm-device` + +<sup>Since: next release</sup> + +List DRM devices that niri will ignore. +Useful for GPU passthrough when you don't want niri to open a certain device. + +```kdl +debug { + ignore-drm-device "/dev/dri/renderD128" + ignore-drm-device "/dev/dri/renderD130" +} +``` + ### `force-pipewire-invalid-modifier` <sup>Since: 25.01</sup> diff --git a/niri-config/src/debug.rs b/niri-config/src/debug.rs index 82bfe875..d69dd2bf 100644 --- a/niri-config/src/debug.rs +++ b/niri-config/src/debug.rs @@ -13,6 +13,7 @@ pub struct Debug { pub keep_max_bpc_unchanged: bool, pub restrict_primary_scanout_to_matching_format: bool, pub render_drm_device: Option<PathBuf>, + pub ignored_drm_devices: Vec<PathBuf>, pub force_pipewire_invalid_modifier: bool, pub emulate_zero_presentation_time: bool, pub disable_resize_throttling: bool, @@ -45,6 +46,8 @@ pub struct DebugPart { pub restrict_primary_scanout_to_matching_format: Option<Flag>, #[knuffel(child, unwrap(argument))] pub render_drm_device: Option<PathBuf>, + #[knuffel(children(name = "ignore-drm-device"), unwrap(argument))] + pub ignored_drm_devices: Vec<PathBuf>, #[knuffel(child)] pub force_pipewire_invalid_modifier: Option<Flag>, #[knuffel(child)] @@ -91,6 +94,9 @@ impl MergeWith<DebugPart> for Debug { ); merge_clone_opt!((self, part), preview_render, render_drm_device); + + self.ignored_drm_devices + .extend(part.ignored_drm_devices.iter().cloned()); } } diff --git a/niri-config/src/lib.rs b/niri-config/src/lib.rs index ac133c62..2ba2a121 100644 --- a/niri-config/src/lib.rs +++ b/niri-config/src/lib.rs @@ -831,6 +831,8 @@ mod tests { debug { render-drm-device "/dev/dri/renderD129" + ignore-drm-device "/dev/dri/renderD128" + ignore-drm-device "/dev/dri/renderD130" } workspace "workspace-1" { @@ -2008,6 +2010,10 @@ mod tests { render_drm_device: Some( "/dev/dri/renderD129", ), + ignored_drm_devices: [ + "/dev/dri/renderD128", + "/dev/dri/renderD130", + ], force_pipewire_invalid_modifier: false, emulate_zero_presentation_time: false, disable_resize_throttling: false, diff --git a/src/backend/tty.rs b/src/backend/tty.rs index 6c55098a..08aef704 100644 --- a/src/backend/tty.rs +++ b/src/backend/tty.rs @@ -83,6 +83,8 @@ pub struct Tty { primary_node: DrmNode, // DRM render node corresponding to the primary GPU. primary_render_node: DrmNode, + // Ignored DRM nodes. + ignored_nodes: HashSet<DrmNode>, // Devices indexed by DRM node (not necessarily the render node). devices: HashMap<DrmNode, OutputDevice>, // The dma-buf global corresponds to the output device (the primary GPU). It is only `Some()` @@ -328,6 +330,11 @@ impl Tty { } info!("using as the render node: {node_path}"); + let mut ignored_nodes = ignored_nodes_from_config(&config.borrow()); + if ignored_nodes.remove(&primary_node) || ignored_nodes.remove(&primary_render_node) { + warn!("ignoring the primary node or render node is not allowed"); + } + Ok(Self { config, session, @@ -336,6 +343,7 @@ impl Tty { gpu_manager, primary_node, primary_render_node, + ignored_nodes, devices: HashMap::new(), dmabuf_global: None, update_output_config_on_resume: false, @@ -504,6 +512,11 @@ impl Tty { let node = DrmNode::from_dev_id(device_id)?; + if self.ignored_nodes.contains(&node) { + debug!("node is ignored, skipping"); + return Ok(()); + } + let open_flags = OFlags::RDWR | OFlags::CLOEXEC | OFlags::NOCTTY | OFlags::NONBLOCK; let fd = self.session.open(path, open_flags)?; let device_fd = DrmDeviceFd::new(DeviceFd::from(fd)); @@ -1822,6 +1835,48 @@ impl Tty { } self.update_output_config_on_resume = false; + // Update ignored nodes. + let mut ignored_nodes = ignored_nodes_from_config(&self.config.borrow()); + if ignored_nodes.remove(&self.primary_node) + || ignored_nodes.remove(&self.primary_render_node) + { + warn!("ignoring the primary node or render node is not allowed"); + } + if ignored_nodes != self.ignored_nodes { + self.ignored_nodes = ignored_nodes; + + let mut device_list = self + .udev_dispatcher + .as_source_ref() + .device_list() + .map(|(device_id, path)| (device_id, path.to_owned())) + .collect::<HashMap<_, _>>(); + + let removed_devices = self + .devices + .keys() + .filter(|node| { + self.ignored_nodes.contains(node) || !device_list.contains_key(&node.dev_id()) + }) + .copied() + .collect::<Vec<_>>(); + + for node in removed_devices { + device_list.remove(&node.dev_id()); + self.device_removed(node.dev_id(), niri); + } + + for node in self.devices.keys() { + device_list.remove(&node.dev_id()); + } + + for (device_id, path) in device_list { + if let Err(err) = self.device_added(device_id, &path, niri) { + warn!("error adding device {path:?}: {err:?}"); + } + } + } + // Figure out if we should disable laptop panels. let mut disable_laptop_panels = false; if niri.is_lid_closed { @@ -2181,10 +2236,7 @@ impl GammaProps { } } -fn primary_node_from_config(config: &Config) -> Option<(DrmNode, DrmNode)> { - let path = config.debug.render_drm_device.as_ref()?; - debug!("attempting to use render node from config: {path:?}"); - +fn primary_node_from_render_node(path: &Path) -> Option<(DrmNode, DrmNode)> { match DrmNode::from_path(path) { Ok(node) => { if node.ty() == NodeType::Render { @@ -2215,9 +2267,30 @@ fn primary_node_from_config(config: &Config) -> Option<(DrmNode, DrmNode)> { warn!("error opening {path:?} as DRM node: {err:?}"); } } + None } +fn primary_node_from_config(config: &Config) -> Option<(DrmNode, DrmNode)> { + let path = config.debug.render_drm_device.as_ref()?; + debug!("attempting to use render node from config: {path:?}"); + + primary_node_from_render_node(path) +} + +fn ignored_nodes_from_config(config: &Config) -> HashSet<DrmNode> { + let mut disabled_nodes = HashSet::new(); + + for path in &config.debug.ignored_drm_devices { + if let Some((primary_node, render_node)) = primary_node_from_render_node(path) { + disabled_nodes.insert(primary_node); + disabled_nodes.insert(render_node); + } + } + + disabled_nodes +} + fn surface_dmabuf_feedback( compositor: &GbmDrmCompositor, primary_formats: FormatSet, diff --git a/src/niri.rs b/src/niri.rs index 3702c69d..b972f5c1 100644 --- a/src/niri.rs +++ b/src/niri.rs @@ -1504,6 +1504,10 @@ impl State { output_config_changed = true; } + if config.debug.ignored_drm_devices != old_config.debug.ignored_drm_devices { + output_config_changed = true; + } + // FIXME: move backdrop rendering into layout::Monitor, then this will become unnecessary. if config.overview.backdrop_color != old_config.overview.backdrop_color { output_config_changed = true; |
