drivers/graphics: Add helpers for updating the connector state

This commit is contained in:
bjorn3
2026-03-13 22:15:59 +01:00
parent c088e48948
commit 7f8ddd7a7e
8 changed files with 100 additions and 101 deletions
Generated
+1 -1
View File
@@ -592,6 +592,7 @@ version = "0.1.0"
dependencies = [
"common",
"drm-sys",
"edid",
"graphics-ipc",
"inputd",
"libredox",
@@ -2567,7 +2568,6 @@ dependencies = [
"daemon",
"driver-graphics",
"drm-sys",
"edid",
"futures",
"graphics-ipc",
"libredox",
@@ -5,6 +5,8 @@ edition = "2021"
[dependencies]
drm-sys.workspace = true
#TODO: edid is abandoned, fork it an maintain?
edid = "0.3.0"
log.workspace = true
redox-scheme.workspace = true
redox_syscall.workspace = true
@@ -1,8 +1,9 @@
use std::ffi::c_char;
use std::fmt::Debug;
use drm_sys::{
drm_mode_modeinfo, DRM_MODE_CONNECTOR_Unknown, DRM_MODE_OBJECT_CONNECTOR,
DRM_MODE_OBJECT_ENCODER,
DRM_MODE_OBJECT_ENCODER, DRM_MODE_TYPE_PREFERRED,
};
use syscall::Result;
@@ -75,6 +76,88 @@ pub struct DrmConnector<T: Debug + 'static> {
pub driver_data: T,
}
impl<T: Debug + 'static> DrmConnector<T> {
pub fn update_from_size(&mut self, width: u32, height: u32) {
self.modes = vec![Self::modeinfo_for_size(width, height)];
}
pub fn update_from_edid(&mut self, edid: &[u8]) {
let edid = edid::parse(edid).unwrap().1;
if let Some(first_detailed_timing) =
edid.descriptors
.iter()
.find_map(|descriptor| match descriptor {
edid::Descriptor::DetailedTiming(detailed_timing) => Some(detailed_timing),
_ => None,
})
{
self.mm_width = first_detailed_timing.horizontal_size.into();
self.mm_height = first_detailed_timing.vertical_size.into();
} else {
log::error!("No edid timing descriptor detected");
}
self.modes = edid
.descriptors
.iter()
.filter_map(|descriptor| {
match descriptor {
edid::Descriptor::DetailedTiming(detailed_timing) => {
// FIXME extract full information
Some(Self::modeinfo_for_size(
u32::from(detailed_timing.horizontal_active_pixels),
u32::from(detailed_timing.vertical_active_lines),
))
}
_ => None,
}
})
.collect::<Vec<_>>();
// First detailed timing descriptor indicates preferred mode.
for mode in self.modes.iter_mut().skip(1) {
mode.flags &= !DRM_MODE_TYPE_PREFERRED;
}
// FIXME update the EDID property
}
fn modeinfo_for_size(width: u32, height: u32) -> drm_mode_modeinfo {
let mut modeinfo = drm_mode_modeinfo {
// The actual visible display size
hdisplay: width as u16,
vdisplay: height as u16,
// These are used to calculate the refresh rate
clock: 60 * width * height / 1000,
htotal: width as u16,
vtotal: height as u16,
vscan: 0,
vrefresh: 60,
type_: drm_sys::DRM_MODE_TYPE_PREFERRED | drm_sys::DRM_MODE_TYPE_DRIVER,
name: [0; 32],
// These only matter when modesetting physical display adapters. For
// those we should be able to parse the EDID blob.
hsync_start: width as u16,
hsync_end: width as u16,
hskew: 0,
vsync_start: height as u16,
vsync_end: height as u16,
flags: 0,
};
let name = format!("{width}x{height}").into_bytes();
for (to, from) in modeinfo.name.iter_mut().zip(name) {
*to = from as c_char;
}
modeinfo
}
}
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
pub enum DrmConnectorStatus {
+4 -38
View File
@@ -11,10 +11,10 @@ use std::os::fd::BorrowedFd;
use std::sync::Arc;
use drm_sys::{
drm_mode_modeinfo, drm_mode_property_enum, DRM_MODE_DPMS_OFF, DRM_MODE_DPMS_ON,
DRM_MODE_DPMS_STANDBY, DRM_MODE_DPMS_SUSPEND, DRM_MODE_PROP_ATOMIC, DRM_MODE_PROP_BITMASK,
DRM_MODE_PROP_BLOB, DRM_MODE_PROP_ENUM, DRM_MODE_PROP_IMMUTABLE, DRM_MODE_PROP_OBJECT,
DRM_MODE_PROP_RANGE, DRM_MODE_PROP_SIGNED_RANGE, DRM_PROP_NAME_LEN,
drm_mode_property_enum, DRM_MODE_DPMS_OFF, DRM_MODE_DPMS_ON, DRM_MODE_DPMS_STANDBY,
DRM_MODE_DPMS_SUSPEND, DRM_MODE_PROP_ATOMIC, DRM_MODE_PROP_BITMASK, DRM_MODE_PROP_BLOB,
DRM_MODE_PROP_ENUM, DRM_MODE_PROP_IMMUTABLE, DRM_MODE_PROP_OBJECT, DRM_MODE_PROP_RANGE,
DRM_MODE_PROP_SIGNED_RANGE, DRM_PROP_NAME_LEN,
};
use graphics_ipc::v2::Damage;
use inputd::{DisplayHandle, VtEventKind};
@@ -908,37 +908,3 @@ impl<T: GraphicsAdapter> GraphicsSchemeInner<T> {
self.handles.remove(&id);
}
}
pub fn modeinfo_for_size(width: u32, height: u32) -> drm_mode_modeinfo {
let mut modeinfo = drm_mode_modeinfo {
// The actual visible display size
hdisplay: width as u16,
vdisplay: height as u16,
// These are used to calculate the refresh rate
clock: 60 * width * height / 1000,
htotal: width as u16,
vtotal: height as u16,
vscan: 0,
vrefresh: 60,
type_: drm_sys::DRM_MODE_TYPE_PREFERRED | drm_sys::DRM_MODE_TYPE_DRIVER,
name: [0; 32],
// These only matter when modesetting physical display adapters. For
// those we should be able to parse the EDID blob.
hsync_start: width as u16,
hsync_end: width as u16,
hskew: 0,
vsync_start: height as u16,
vsync_end: height as u16,
flags: 0,
};
let name = format!("{width}x{height}").into_bytes();
for (to, from) in modeinfo.name.iter_mut().zip(name) {
*to = from as c_char;
}
modeinfo
}
+2 -7
View File
@@ -6,9 +6,7 @@ use std::ptr::{self, NonNull};
use driver_graphics::connector::DrmConnectorStatus;
use driver_graphics::objects::{DrmObjectId, DrmObjects};
use driver_graphics::{
modeinfo_for_size, Buffer, CursorPlane, GraphicsAdapter, StandardProperties,
};
use driver_graphics::{Buffer, CursorPlane, GraphicsAdapter, StandardProperties};
use drm_sys::DRM_MODE_DPMS_ON;
use graphics_ipc::v2::ipc::{DRM_CAP_DUMB_BUFFER, DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT};
use graphics_ipc::v2::Damage;
@@ -70,10 +68,7 @@ impl GraphicsAdapter for Device {
let connector = objects.get_connector_mut(id).unwrap();
let framebuffer = &self.framebuffers[connector.driver_data.framebuffer_id];
connector.connection = DrmConnectorStatus::Connected;
connector.modes = vec![modeinfo_for_size(
framebuffer.width as u32,
framebuffer.height as u32,
)];
connector.update_from_size(framebuffer.width as u32, framebuffer.height as u32);
// FIXME fetch EDID
}
+2 -7
View File
@@ -4,9 +4,7 @@ use std::ptr::{self, NonNull};
use driver_graphics::connector::DrmConnectorStatus;
use driver_graphics::objects::{DrmObjectId, DrmObjects};
use driver_graphics::{
modeinfo_for_size, Buffer, CursorPlane, GraphicsAdapter, StandardProperties,
};
use driver_graphics::{Buffer, CursorPlane, GraphicsAdapter, StandardProperties};
use drm_sys::DRM_MODE_DPMS_ON;
use graphics_ipc::v2::ipc::{DRM_CAP_DUMB_BUFFER, DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT};
use graphics_ipc::v2::Damage;
@@ -71,11 +69,8 @@ impl GraphicsAdapter for FbAdapter {
id: DrmObjectId,
) {
let connector = objects.get_connector_mut(id).unwrap();
connector.modes = vec![modeinfo_for_size(
connector.driver_data.width,
connector.driver_data.height,
)];
connector.connection = DrmConnectorStatus::Connected;
connector.update_from_size(connector.driver_data.width, connector.driver_data.height);
}
fn display_count(&self) -> usize {
-2
View File
@@ -6,8 +6,6 @@ authors = ["Anhad Singh <andypython@protonmail.com>"]
[dependencies]
drm-sys.workspace = true
#TODO: edid is abandoned, fork it an maintain?
edid = "0.3.0"
log.workspace = true
static_assertions = "1.1.0"
futures = { version = "0.3.28", features = ["executor"] }
+5 -45
View File
@@ -5,12 +5,9 @@ use common::{dma::Dma, sgl};
use driver_graphics::connector::DrmConnectorStatus;
use driver_graphics::objects::{DrmObjectId, DrmObjects};
use driver_graphics::{
modeinfo_for_size, Buffer as DrmBuffer, CursorPlane, GraphicsAdapter, GraphicsScheme,
StandardProperties,
};
use drm_sys::{
DRM_CAP_CURSOR_HEIGHT, DRM_CAP_CURSOR_WIDTH, DRM_MODE_DPMS_ON, DRM_MODE_TYPE_PREFERRED,
Buffer as DrmBuffer, CursorPlane, GraphicsAdapter, GraphicsScheme, StandardProperties,
};
use drm_sys::{DRM_CAP_CURSOR_HEIGHT, DRM_CAP_CURSOR_WIDTH, DRM_MODE_DPMS_ON};
use graphics_ipc::v2::ipc::{DRM_CAP_DUMB_BUFFER, DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT};
use graphics_ipc::v2::Damage;
@@ -314,7 +311,6 @@ impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> {
let connector = objects.get_connector_mut(id).unwrap();
let display = &self.displays[connector.driver_data.display_id as usize];
connector.modes = vec![modeinfo_for_size(display.width, display.height)];
connector.connection = if display.enabled {
DrmConnectorStatus::Connected
} else {
@@ -322,48 +318,12 @@ impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> {
};
if self.has_edid {
let edid = edid::parse(&display.edid).unwrap().1;
if let Some(first_detailed_timing) =
edid.descriptors
.iter()
.find_map(|descriptor| match descriptor {
edid::Descriptor::DetailedTiming(detailed_timing) => {
Some(detailed_timing)
}
_ => None,
})
{
connector.mm_width = first_detailed_timing.horizontal_size.into();
connector.mm_height = first_detailed_timing.vertical_size.into();
} else {
log::error!("No edid timing descriptor detected");
}
connector.modes = edid
.descriptors
.iter()
.filter_map(|descriptor| {
match descriptor {
edid::Descriptor::DetailedTiming(detailed_timing) => {
// FIXME extract full information
Some(modeinfo_for_size(
u32::from(detailed_timing.horizontal_active_pixels),
u32::from(detailed_timing.vertical_active_lines),
))
}
_ => None,
}
})
.collect::<Vec<_>>();
// First detailed timing descriptor indicates preferred mode.
for mode in connector.modes.iter_mut().skip(1) {
mode.flags &= !DRM_MODE_TYPE_PREFERRED;
}
connector.update_from_edid(&display.edid);
let blob = objects.add_blob(display.edid.clone());
objects.set_object_property(id, standard_properties.edid, blob.into());
} else {
connector.update_from_size(display.width, display.height);
}
});
}