use std::collections::HashMap; use std::fmt::Debug; use std::marker::PhantomData; use std::sync::{Arc, Mutex}; use drm_fourcc::DrmFourcc; 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_PLANE, DRM_MODE_OBJECT_PROPERTY, }; use syscall::{Error, Result, ENOENT}; use crate::kms::connector::{KmsConnector, KmsEncoder}; use crate::kms::properties::{ define_object_props, init_standard_props, KmsBlob, KmsProperty, KmsPropertyData, ACTIVE, }; use crate::GraphicsAdapter; #[derive(Debug)] pub struct KmsObjects { next_id: KmsObjectId, pub(super) connectors: Vec, pub(super) encoders: Vec, crtcs: Vec, planes: Vec, framebuffers: Vec, pub(super) 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![], planes: vec![], framebuffers: vec![], objects: HashMap::new(), _marker: PhantomData, }; init_standard_props(&mut objects); objects } pub(super) fn add>(&mut self, data: U) -> KmsObjectId { let id = self.next_id; self.objects.insert(id, data.into_object()); self.next_id.0 += 1; id } pub(super) fn get>(&self, id: KmsObjectId) -> Result<&U> { let object = self.objects.get(&id).ok_or(Error::new(ENOENT))?; if let Some(object) = U::try_from_object(object) { Ok(object) } else { Err(Error::new(ENOENT)) } } pub(super) fn remove>(&mut self, id: KmsObjectId) -> Result<()> { let Some(object) = self.objects.get(&id) else { return Err(Error::new(ENOENT)); }; let Some(_) = U::try_from_object(object) else { return Err(Error::new(ENOENT)); }; self.objects.remove(&id).unwrap(); Ok(()) } pub(crate) fn object_type(&self, id: KmsObjectId) -> Result { let object = self.objects.get(&id).ok_or(Error::new(ENOENT))?; Ok(object.object_type()) } pub fn add_crtc( &mut self, driver_data: T::Crtc, driver_data_state: ::State, plane_data: T::Plane, plane_data_state: ::State, ) -> (KmsObjectId, KmsObjectId) { let primary_plane = self.add_plane(&[], KmsPlaneType::Primary, plane_data, plane_data_state); let crtc_index = self.crtcs.len() as u32; let id = self.add(Mutex::new(KmsCrtc { crtc_index, gamma_size: 0, properties: KmsCrtc::base_properties(), primary_plane, state: KmsCrtcState { mode: None, driver_data: driver_data_state, }, driver_data, })); self.crtcs.push(id); self.get_plane(primary_plane) .unwrap() .lock() .unwrap() .possible_crtcs = 1 << crtc_index; (id, primary_plane) } 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_plane( &mut self, crtcs: &[KmsObjectId], plane_type: KmsPlaneType, driver_data: T::Plane, driver_data_state: ::State, ) -> KmsObjectId { let mut possible_crtcs = 0u32; for &crtc in crtcs { possible_crtcs |= 1 << self.get_crtc(crtc).unwrap().lock().unwrap().crtc_index } let plane_index = self.planes.len() as u32; let id = self.add(Mutex::new(KmsPlane { plane_index, possible_crtcs, plane_type, state: KmsPlaneState { fb_id: None, crtc_id: None, src_rect: KmsRect { x: 0u32, y: 0, width: 0, height: 0, }, crtc_rect: KmsRect { x: 0i32, y: 0, width: 0, height: 0, }, driver_data: driver_data_state, }, driver_data, })); self.planes.push(id); id } pub fn plane_ids(&self) -> &[KmsObjectId] { &self.planes } pub fn planes(&self) -> impl Iterator>> + use<'_, T> { self.planes .iter() .map(|&id| self.get::>>(id).unwrap()) } pub fn get_plane(&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<()> { self.remove::>(id) } 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() } } pub(super) trait KmsObjectKind { fn into_object(self) -> KmsObject; fn try_from_object(object: &KmsObject) -> Option<&Self>; } macro_rules! define_object_kinds { (<$T:ident> $( $variant:ident($data:ty) = $type:ident, )*) => { #[derive(Debug)] pub(super) enum KmsObject<$T: GraphicsAdapter> { $($variant($data),)* } impl<$T: GraphicsAdapter> KmsObject<$T> { fn object_type(&self) -> u32 { match self { $(Self::$variant(_) => $type,)* } } } $( impl<$T: GraphicsAdapter> KmsObjectKind<$T> for $data { fn into_object(self) -> KmsObject<$T> { KmsObject::$variant(self) } fn try_from_object(object: &KmsObject<$T>) -> Option<&$data> { match object { KmsObject::$variant(data) => Some(data), _ => None, } } } )* }; } 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, Plane(Mutex>) = DRM_MODE_OBJECT_PLANE, 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 primary_plane: KmsObjectId, pub state: KmsCrtcState, pub driver_data: T::Crtc, } #[derive(Debug)] pub struct KmsCrtcState { pub mode: Option, pub driver_data: ::State, } impl Clone for KmsCrtcState { fn clone(&self) -> Self { Self { mode: self.mode.clone(), driver_data: self.driver_data.clone(), } } } define_object_props!(object, KmsCrtc { ACTIVE { get => u64::from(object.state.mode.is_some()), } }); pub trait KmsPlaneDriver: Debug { type State: Clone + Debug; } impl KmsPlaneDriver for () { type State = (); } #[derive(Debug)] pub struct KmsPlane { pub plane_index: u32, pub possible_crtcs: u32, pub plane_type: KmsPlaneType, pub state: KmsPlaneState, pub driver_data: T::Plane, } #[derive(Debug)] pub struct KmsPlaneState { pub fb_id: Option, pub crtc_id: Option, pub src_rect: KmsRect, pub crtc_rect: KmsRect, pub driver_data: ::State, } impl Clone for KmsPlaneState { fn clone(&self) -> Self { Self { fb_id: self.fb_id.clone(), crtc_id: self.crtc_id.clone(), src_rect: self.src_rect.clone(), crtc_rect: self.crtc_rect.clone(), driver_data: self.driver_data.clone(), } } } #[derive(Debug, PartialEq)] pub enum KmsPlaneType { Primary, Overlay, Cursor, } #[derive(Debug, Clone)] pub struct KmsRect { pub x: T, pub y: T, pub width: u32, pub height: u32, } #[derive(Debug)] pub struct KmsFramebuffer { pub width: u32, pub height: u32, pub pixel_format: DrmFourcc, pub pitch: u32, pub buffer: Arc, pub driver_data: T::Framebuffer, }