use std::collections::HashMap; use std::fmt::Debug; use std::marker::PhantomData; use std::sync::{Arc, Mutex}; use drm_sys::{ drm_mode_modeinfo, DRM_MODE_OBJECT_BLOB, DRM_MODE_OBJECT_CONNECTOR, DRM_MODE_OBJECT_CRTC, DRM_MODE_OBJECT_ENCODER, DRM_MODE_OBJECT_FB, DRM_MODE_OBJECT_PROPERTY, }; use syscall::{Error, Result, EINVAL}; use crate::kms::connector::{KmsConnector, KmsEncoder}; use crate::kms::properties::{ define_object_props, init_standard_props, KmsBlob, KmsProperty, KmsPropertyData, }; use crate::GraphicsAdapter; #[derive(Debug)] pub struct KmsObjects { next_id: KmsObjectId, pub(crate) connectors: Vec, pub(crate) encoders: Vec, crtcs: Vec, framebuffers: Vec, pub(crate) objects: HashMap>, _marker: PhantomData, } impl KmsObjects { pub(crate) fn new() -> Self { let mut objects = KmsObjects { next_id: KmsObjectId(1), connectors: vec![], encoders: vec![], crtcs: vec![], framebuffers: vec![], objects: HashMap::new(), _marker: PhantomData, }; init_standard_props(&mut objects); objects } pub(crate) fn add>>(&mut self, data: U) -> KmsObjectId { let id = self.next_id; self.objects.insert(id, data.into()); self.next_id.0 += 1; id } pub(crate) fn get<'a, U: 'a>(&'a self, id: KmsObjectId) -> Result<&'a U> where &'a U: TryFrom<&'a KmsObject>, { let object = self.objects.get(&id).ok_or(Error::new(EINVAL))?; if let Ok(object) = object.try_into() { Ok(object) } else { Err(Error::new(EINVAL)) } } pub fn object_type(&self, id: KmsObjectId) -> Result { let object = self.objects.get(&id).ok_or(Error::new(EINVAL))?; Ok(object.object_type()) } pub fn add_crtc( &mut self, driver_data: T::Crtc, driver_data_state: ::State, ) -> KmsObjectId { let crtc_index = self.crtcs.len() as u32; let id = self.add(Mutex::new(KmsCrtc { crtc_index, gamma_size: 0, properties: KmsCrtc::base_properties(), state: KmsCrtcState { fb_id: None, mode: None, driver_data: driver_data_state, }, driver_data, })); self.crtcs.push(id); id } pub fn crtc_ids(&self) -> &[KmsObjectId] { &self.crtcs } pub fn crtcs(&self) -> impl Iterator>> + use<'_, T> { self.crtcs .iter() .map(|&id| self.get::>>(id).unwrap()) } pub fn get_crtc(&self, id: KmsObjectId) -> Result<&Mutex>> { self.get(id) } pub fn add_framebuffer(&mut self, fb: KmsFramebuffer) -> KmsObjectId { let id = self.add(fb); self.framebuffers.push(id); id } pub fn remove_framebuffer(&mut self, id: KmsObjectId) -> Result<()> { let Some(object) = self.objects.get(&id) else { return Err(Error::new(EINVAL)); }; let KmsObject::Framebuffer(_) = object else { return Err(Error::new(EINVAL)); }; self.objects.remove(&id).unwrap(); Ok(()) } pub fn fb_ids(&self) -> &[KmsObjectId] { &self.framebuffers } pub fn get_framebuffer(&self, id: KmsObjectId) -> Result<&KmsFramebuffer> { self.get(id) } } #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub struct KmsObjectId(pub(crate) u32); impl KmsObjectId { pub const INVALID: KmsObjectId = KmsObjectId(0); } impl From for u64 { fn from(value: KmsObjectId) -> Self { value.0.into() } } macro_rules! define_object_kinds { (<$T:ident> $( $variant:ident($data:ty) = $type:ident, )*) => { #[derive(Debug)] pub(crate) enum KmsObject<$T: GraphicsAdapter> { $($variant($data),)* } impl<$T: GraphicsAdapter> KmsObject<$T> { fn object_type(&self) -> u32 { match self { $(Self::$variant(_) => $type,)* } } } $( impl<$T: GraphicsAdapter> From<$data> for KmsObject<$T> { fn from(value: $data) -> Self { Self::$variant(value) } } impl<'a, $T: GraphicsAdapter> TryFrom<&'a KmsObject<$T>> for &'a $data { type Error = (); fn try_from(value: &'a KmsObject) -> Result { match value { KmsObject::$variant(data) => Ok(data), _ => Err(()), } } } )* }; } define_object_kinds! { Crtc(Mutex>) = DRM_MODE_OBJECT_CRTC, Connector(Mutex>) = DRM_MODE_OBJECT_CONNECTOR, Encoder(KmsEncoder) = DRM_MODE_OBJECT_ENCODER, Property(KmsProperty) = DRM_MODE_OBJECT_PROPERTY, Framebuffer(KmsFramebuffer) = DRM_MODE_OBJECT_FB, Blob(KmsBlob) = DRM_MODE_OBJECT_BLOB, } pub trait KmsCrtcDriver: Debug { type State: Clone + Debug; } impl KmsCrtcDriver for () { type State = (); } #[derive(Debug)] pub struct KmsCrtc { pub crtc_index: u32, pub gamma_size: u32, pub properties: Vec>, pub state: KmsCrtcState, pub driver_data: T::Crtc, } #[derive(Debug)] pub struct KmsCrtcState { pub fb_id: Option, pub mode: Option, pub driver_data: ::State, } impl Clone for KmsCrtcState { fn clone(&self) -> Self { Self { fb_id: self.fb_id.clone(), mode: self.mode.clone(), driver_data: self.driver_data.clone(), } } } define_object_props!(object, KmsCrtc {}); #[derive(Debug)] pub struct KmsFramebuffer { pub width: u32, pub height: u32, pub pitch: u32, pub bpp: u32, pub depth: u32, pub buffer: Arc, pub driver_data: T::Framebuffer, }