feat: identify DRM outputs by EDID
This commit is contained in:
1 parent
8d305bf338
commit
5fce7227ed
1 file changed
+45
-3
@@ -26,7 +26,9 @@ use smithay::{
|
|||||||
output::{Mode as OutputMode, Output, PhysicalProperties, Scale, Subpixel},
|
output::{Mode as OutputMode, Output, PhysicalProperties, Scale, Subpixel},
|
||||||
reexports::{
|
reexports::{
|
||||||
calloop::EventLoop,
|
calloop::EventLoop,
|
||||||
drm::control::{Device as ControlDevice, Mode as DrmMode, ModeTypeFlags, connector, crtc},
|
drm::control::{
|
||||||
|
Device as ControlDevice, Mode as DrmMode, ModeTypeFlags, connector, crtc, property,
|
||||||
|
},
|
||||||
input::Libinput,
|
input::Libinput,
|
||||||
rustix::fs::OFlags,
|
rustix::fs::OFlags,
|
||||||
wayland_protocols::wp::presentation_time::server::wp_presentation_feedback::Kind,
|
wayland_protocols::wp::presentation_time::server::wp_presentation_feedback::Kind,
|
||||||
@@ -619,7 +621,8 @@ fn create_direct_output(
|
|||||||
crtc: crtc::Handle,
|
crtc: crtc::Handle,
|
||||||
mode: DrmMode,
|
mode: DrmMode,
|
||||||
) -> Result<DirectOutput, Box<dyn Error>> {
|
) -> Result<DirectOutput, Box<dyn Error>> {
|
||||||
let (output, global) = create_output(state, &connector, mode);
|
let identity = connector_identity(drm, &connector);
|
||||||
|
let (output, global) = create_output(state, &connector, mode, identity);
|
||||||
let drm_surface = drm.create_surface(crtc, mode, &[connector.handle()])?;
|
let drm_surface = drm.create_surface(crtc, mode, &[connector.handle()])?;
|
||||||
let allocator = GbmAllocator::new(
|
let allocator = GbmAllocator::new(
|
||||||
gbm.clone(),
|
gbm.clone(),
|
||||||
@@ -649,9 +652,9 @@ fn create_output(
|
|||||||
state: &mut Ferese,
|
state: &mut Ferese,
|
||||||
connector: &connector::Info,
|
connector: &connector::Info,
|
||||||
mode: DrmMode,
|
mode: DrmMode,
|
||||||
|
identity: String,
|
||||||
) -> (Output, GlobalId) {
|
) -> (Output, GlobalId) {
|
||||||
let name = connector.to_string();
|
let name = connector.to_string();
|
||||||
let identity = format!("drm:{name}");
|
|
||||||
let physical_size = connector.size().unwrap_or((0, 0));
|
let physical_size = connector.size().unwrap_or((0, 0));
|
||||||
let output = Output::new(
|
let output = Output::new(
|
||||||
name,
|
name,
|
||||||
@@ -684,6 +687,40 @@ fn create_output(
|
|||||||
(output, global)
|
(output, global)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn connector_identity(drm: &DrmDevice, connector: &connector::Info) -> String {
|
||||||
|
let edid = drm
|
||||||
|
.get_properties(connector.handle())
|
||||||
|
.ok()
|
||||||
|
.and_then(|properties| {
|
||||||
|
properties.iter().find_map(|(handle, raw)| {
|
||||||
|
let info = drm.get_property(*handle).ok()?;
|
||||||
|
if info.name().to_bytes() != b"EDID" {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
match info.value_type().convert_value(*raw) {
|
||||||
|
property::Value::Blob(blob) if blob != 0 => drm.get_property_blob(blob).ok(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
match edid {
|
||||||
|
Some(edid) if !edid.is_empty() => {
|
||||||
|
format!("drm:{}:{:016x}", connector, stable_hash(&edid))
|
||||||
|
}
|
||||||
|
_ => format!("drm:{connector}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stable_hash(bytes: &[u8]) -> u64 {
|
||||||
|
const FNV_OFFSET: u64 = 0xcbf2_9ce4_8422_2325;
|
||||||
|
const FNV_PRIME: u64 = 0x0000_0100_0000_01b3;
|
||||||
|
|
||||||
|
bytes.iter().fold(FNV_OFFSET, |hash, byte| {
|
||||||
|
(hash ^ u64::from(*byte)).wrapping_mul(FNV_PRIME)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
impl DirectBackendState {
|
impl DirectBackendState {
|
||||||
pub fn record_presentation(
|
pub fn record_presentation(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -750,6 +787,11 @@ mod tests {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn connector_identity_hash_is_stable() {
|
||||||
|
assert_eq!(stable_hash(b"hello"), 0xa430_d846_80aa_bd0b);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn presentation_clock_uses_measured_monotonic_deltas() {
|
fn presentation_clock_uses_measured_monotonic_deltas() {
|
||||||
let mut clock = PresentationClock::default();
|
let mut clock = PresentationClock::default();
|
||||||
|
|||||||
Reference in new issue
Block a user