diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2024-09-03 12:13:04 +0300 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2024-09-03 13:48:08 +0300 |
| commit | f0157e03e72714264e684295fac226e2046f0b38 (patch) | |
| tree | 7bfd198f59697704c5464c8498d3f8d7ff80131d /src/backend/tty.rs | |
| parent | 4b7c16b04a7c80f5f9b6fcbc4a1d8c9448dffbdb (diff) | |
| download | niri-f0157e03e72714264e684295fac226e2046f0b38.tar.gz niri-f0157e03e72714264e684295fac226e2046f0b38.tar.bz2 niri-f0157e03e72714264e684295fac226e2046f0b38.zip | |
Use libdisplay-info for make/model/serial parsing, implement throughout
Diffstat (limited to 'src/backend/tty.rs')
| -rw-r--r-- | src/backend/tty.rs | 203 |
1 files changed, 103 insertions, 100 deletions
diff --git a/src/backend/tty.rs b/src/backend/tty.rs index 17b16eec..b4c892a8 100644 --- a/src/backend/tty.rs +++ b/src/backend/tty.rs @@ -4,7 +4,6 @@ use std::fmt::Write; use std::iter::zip; use std::num::NonZeroU64; use std::os::fd::AsFd; -use std::panic::{catch_unwind, AssertUnwindSafe}; use std::path::Path; use std::rc::Rc; use std::sync::{Arc, Mutex}; @@ -14,7 +13,7 @@ use std::{io, mem}; use anyhow::{anyhow, bail, ensure, Context}; use bytemuck::cast_slice_mut; use libc::dev_t; -use niri_config::Config; +use niri_config::{Config, OutputName}; use smithay::backend::allocator::dmabuf::Dmabuf; use smithay::backend::allocator::format::FormatSet; use smithay::backend::allocator::gbm::{GbmAllocator, GbmBufferFlags, GbmDevice}; @@ -52,7 +51,6 @@ use smithay::wayland::drm_lease::{ DrmLease, DrmLeaseBuilder, DrmLeaseRequest, DrmLeaseState, LeaseRejected, }; use smithay_drm_extras::drm_scanner::{DrmScanEvent, DrmScanner}; -use smithay_drm_extras::edid::EdidInfo; use wayland_protocols::wp::linux_dmabuf::zv1::server::zwp_linux_dmabuf_feedback_v1::TrancheFlags; use wayland_protocols::wp::presentation_time::server::wp_presentation_feedback; @@ -178,7 +176,7 @@ struct TtyOutputState { } struct Surface { - name: String, + name: OutputName, compositor: GbmDrmCompositor, connector: connector::Handle, dmabuf_feedback: Option<SurfaceDmabufFeedback>, @@ -440,7 +438,7 @@ impl Tty { continue; }; let Some(output_state) = niri.output_state.get_mut(&output) else { - error!("missing state for output {:?}", surface.name); + error!("missing state for output {:?}", surface.name.connector); continue; }; @@ -746,26 +744,22 @@ impl Tty { connector: connector::Info, crtc: crtc::Handle, ) -> anyhow::Result<()> { - let output_name = format!( - "{}-{}", - connector.interface().as_str(), - connector.interface_id(), - ); - debug!("connecting connector: {output_name}"); + let connector_name = format_connector_name(&connector); + debug!("connecting connector: {connector_name}"); let device = self.devices.get_mut(&node).context("missing device")?; + let output_name = make_output_name(&device.drm, connector.handle(), connector_name.clone()); + let non_desktop = find_drm_property(&device.drm, connector.handle(), "non-desktop") .and_then(|(_, info, value)| info.value_type().convert_value(value).as_boolean()) .unwrap_or(false); if non_desktop { debug!("output is non desktop"); - let description = get_edid_info(&device.drm, connector.handle()) - .map(|info| truncate_to_nul(info.model)) - .unwrap_or_else(|| "Unknown".into()); + let description = output_name.format_description(); if let Some(lease_state) = &mut device.drm_lease_state { - lease_state.add_connector::<State>(connector.handle(), output_name, description); + lease_state.add_connector::<State>(connector.handle(), connector_name, description); } device .non_desktop_connectors @@ -881,22 +875,13 @@ impl Tty { // Update the output mode. let (physical_width, physical_height) = connector.size().unwrap_or((0, 0)); - let (make, model) = get_edid_info(&device.drm, connector.handle()) - .map(|info| { - ( - truncate_to_nul(info.manufacturer), - truncate_to_nul(info.model), - ) - }) - .unwrap_or_else(|| ("Unknown".into(), "Unknown".into())); - let output = Output::new( - output_name.clone(), + connector_name.clone(), PhysicalProperties { size: (physical_width as i32, physical_height as i32).into(), subpixel: connector.subpixel().into(), - model, - make, + model: output_name.model.as_deref().unwrap_or("Unknown").to_owned(), + make: output_name.make.as_deref().unwrap_or("Unknown").to_owned(), }, ); @@ -907,6 +892,7 @@ impl Tty { output .user_data() .insert_if_missing(|| TtyOutputState { node, crtc }); + output.user_data().insert_if_missing(|| output_name.clone()); let mut planes = surface.planes().clone(); @@ -993,17 +979,18 @@ impl Tty { } let vblank_frame_name = - tracy_client::FrameName::new_leak(format!("vblank on {output_name}")); - let time_since_presentation_plot_name = - tracy_client::PlotName::new_leak(format!("{output_name} time since presentation, ms")); + tracy_client::FrameName::new_leak(format!("vblank on {connector_name}")); + let time_since_presentation_plot_name = tracy_client::PlotName::new_leak(format!( + "{connector_name} time since presentation, ms" + )); let presentation_misprediction_plot_name = tracy_client::PlotName::new_leak(format!( - "{output_name} presentation misprediction, ms" + "{connector_name} presentation misprediction, ms" )); let sequence_delta_plot_name = - tracy_client::PlotName::new_leak(format!("{output_name} sequence delta")); + tracy_client::PlotName::new_leak(format!("{connector_name} sequence delta")); let surface = Surface { - name: output_name.clone(), + name: output_name, connector: connector.handle(), compositor, dmabuf_feedback, @@ -1066,7 +1053,7 @@ impl Tty { return; }; - debug!("disconnecting connector: {:?}", surface.name); + debug!("disconnecting connector: {:?}", surface.name.connector); let output = niri .global_space @@ -1108,7 +1095,7 @@ impl Tty { // Finish the Tracy frame, if any. drop(surface.vblank_frame.take()); - let name = &surface.name; + let name = &surface.name.connector; trace!("vblank on {name} {meta:?}"); span.emit_text(name); @@ -1311,7 +1298,7 @@ impl Tty { return rv; }; - span.emit_text(&surface.name); + span.emit_text(&surface.name.connector); if !device.drm.is_active() { warn!("device is inactive"); @@ -1526,22 +1513,10 @@ impl Tty { for (node, device) in &self.devices { for (connector, crtc) in device.drm_scanner.crtcs() { - let name = format!( - "{}-{}", - connector.interface().as_str(), - connector.interface_id(), - ); - + let connector_name = format_connector_name(connector); let physical_size = connector.size(); - - let (make, model) = get_edid_info(&device.drm, connector.handle()) - .map(|info| { - ( - truncate_to_nul(info.manufacturer), - truncate_to_nul(info.model), - ) - }) - .unwrap_or_else(|| ("Unknown".into(), "Unknown".into())); + let output_name = + make_output_name(&device.drm, connector.handle(), connector_name.clone()); let surface = device.surfaces.get(&crtc); let current_crtc_mode = surface.map(|surface| surface.compositor.pending_mode()); @@ -1589,9 +1564,10 @@ impl Tty { .map(logical_output); let ipc_output = niri_ipc::Output { - name, - make, - model, + name: connector_name, + make: output_name.make.unwrap_or_else(|| "Unknown".into()), + model: output_name.model.unwrap_or_else(|| "Unknown".into()), + serial: output_name.serial, physical_size, modes, current_mode, @@ -1736,7 +1712,7 @@ impl Tty { continue; }; let Some(output_state) = niri.output_state.get_mut(&output) else { - error!("missing state for output {:?}", surface.name); + error!("missing state for output {:?}", surface.name.connector); continue; }; @@ -1759,7 +1735,7 @@ impl Tty { warn!( "output {:?}: configured mode {}x{}{} could not be found, \ falling back to preferred", - surface.name, + surface.name.connector, target.width, target.height, if let Some(refresh) = target.refresh { @@ -1770,7 +1746,10 @@ impl Tty { ); } - debug!("output {:?}: picking mode: {mode:?}", surface.name); + debug!( + "output {:?}: picking mode: {mode:?}", + surface.name.connector + ); if let Err(err) = surface.compositor.use_mode(mode) { warn!("error changing mode: {err:?}"); continue; @@ -1796,12 +1775,8 @@ impl Tty { continue; } - let output_name = format!( - "{}-{}", - connector.interface().as_str(), - connector.interface_id(), - ); - + let connector_name = format_connector_name(connector); + let output_name = make_output_name(&device.drm, connector.handle(), connector_name); let config = self .config .borrow() @@ -1845,6 +1820,30 @@ impl Tty { pub fn get_device_from_node(&mut self, node: DrmNode) -> Option<&mut OutputDevice> { self.devices.get_mut(&node) } + + pub fn disconnected_connector_name_by_name_match(&self, target: &str) -> Option<OutputName> { + for device in self.devices.values() { + for (connector, crtc) in device.drm_scanner.crtcs() { + // Check if connected. + if connector.state() != connector::State::Connected { + continue; + } + + // Check if already enabled. + if device.surfaces.contains_key(&crtc) { + continue; + } + + let connector_name = format_connector_name(connector); + let output_name = make_output_name(&device.drm, connector.handle(), connector_name); + if output_name.matches(target) { + return Some(output_name); + } + } + } + + None + } } impl GammaProps { @@ -2277,23 +2276,21 @@ fn pick_mode( mode.map(|m| (*m, fallback)) } -fn truncate_to_nul(mut s: String) -> String { - if let Some(index) = s.find('\0') { - s.truncate(index); - } - s -} - -fn get_edid_info(device: &DrmDevice, connector: connector::Handle) -> Option<EdidInfo> { - match catch_unwind(AssertUnwindSafe(move || { - EdidInfo::for_connector(device, connector) - })) { - Ok(info) => info, - Err(err) => { - warn!("edid-rs panicked: {err:?}"); - None - } - } +fn get_edid_info( + device: &DrmDevice, + connector: connector::Handle, +) -> anyhow::Result<libdisplay_info::info::Info> { + let (_, info, value) = + find_drm_property(device, connector, "EDID").context("no EDID property")?; + let blob = info + .value_type() + .convert_value(value) + .as_blob() + .context("EDID was not blob type")?; + let data = device + .get_property_blob(blob) + .context("error getting EDID blob value")?; + libdisplay_info::info::Info::parse_edid(&data).context("error parsing EDID") } fn set_max_bpc(device: &DrmDevice, connector: connector::Handle, bpc: u64) -> anyhow::Result<u64> { @@ -2415,41 +2412,47 @@ fn try_to_change_vrr( match set_vrr_enabled(device, crtc, enable_vrr) { Ok(enabled) => { if enabled != enable_vrr { - warn!("output {:?}: failed {} VRR", surface.name, word); + warn!("output {:?}: failed {} VRR", surface.name.connector, word); } surface.vrr_enabled = enabled; output_state.frame_clock.set_vrr(enabled); } Err(err) => { - warn!("output {:?}: error {} VRR: {err:?}", surface.name, word); + warn!( + "output {:?}: error {} VRR: {err:?}", + surface.name.connector, word + ); } } } else if enable_vrr { warn!( "output {:?}: cannot enable VRR because connector is not vrr_capable", - surface.name + surface.name.connector ); } } -#[cfg(test)] -mod tests { - use super::*; - - #[track_caller] - fn check(input: &str, expected: &str) { - let input = String::from(input); - assert_eq!(truncate_to_nul(input), expected); - } +fn format_connector_name(connector: &connector::Info) -> String { + format!( + "{}-{}", + connector.interface().as_str(), + connector.interface_id(), + ) +} - #[test] - fn truncate_to_nul_works() { - check("", ""); - check("qwer", "qwer"); - check("abc\0def", "abc"); - check("\0as", ""); - check("a\0\0\0b", "a"); - check("bb😁\0cc", "bb😁"); +fn make_output_name( + device: &DrmDevice, + connector: connector::Handle, + connector_name: String, +) -> OutputName { + let info = get_edid_info(device, connector) + .map_err(|err| warn!("error getting EDID info for {connector_name}: {err:?}")) + .ok(); + OutputName { + connector: connector_name, + make: info.as_ref().and_then(|info| info.make()), + model: info.as_ref().and_then(|info| info.model()), + serial: info.as_ref().and_then(|info| info.serial()), } } |
