Files
RedBear-OS/drivers/graphics/driver-graphics/src/kms/objects.rs
T

364 lines
9.7 KiB
Rust

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<T: GraphicsAdapter> {
next_id: KmsObjectId,
pub(super) connectors: Vec<KmsObjectId>,
pub(super) encoders: Vec<KmsObjectId>,
crtcs: Vec<KmsObjectId>,
planes: Vec<KmsObjectId>,
framebuffers: Vec<KmsObjectId>,
pub(super) objects: HashMap<KmsObjectId, KmsObject<T>>,
_marker: PhantomData<T>,
}
impl<T: GraphicsAdapter> KmsObjects<T> {
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<U: KmsObjectKind<T>>(&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<U: KmsObjectKind<T>>(&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<U: KmsObjectKind<T>>(&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<u32> {
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: <T::Crtc as KmsCrtcDriver>::State,
plane_data: T::Plane,
plane_data_state: <T::Plane as KmsPlaneDriver>::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<Item = &Mutex<KmsCrtc<T>>> + use<'_, T> {
self.crtcs
.iter()
.map(|&id| self.get::<Mutex<KmsCrtc<T>>>(id).unwrap())
}
pub fn get_crtc(&self, id: KmsObjectId) -> Result<&Mutex<KmsCrtc<T>>> {
self.get(id)
}
pub fn add_plane(
&mut self,
crtcs: &[KmsObjectId],
plane_type: KmsPlaneType,
driver_data: T::Plane,
driver_data_state: <T::Plane as KmsPlaneDriver>::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<Item = &Mutex<KmsPlane<T>>> + use<'_, T> {
self.planes
.iter()
.map(|&id| self.get::<Mutex<KmsPlane<T>>>(id).unwrap())
}
pub fn get_plane(&self, id: KmsObjectId) -> Result<&Mutex<KmsPlane<T>>> {
self.get(id)
}
pub fn add_framebuffer(&mut self, fb: KmsFramebuffer<T>) -> KmsObjectId {
let id = self.add(fb);
self.framebuffers.push(id);
id
}
pub fn remove_framebuffer(&mut self, id: KmsObjectId) -> Result<()> {
self.remove::<KmsFramebuffer<T>>(id)
}
pub fn fb_ids(&self) -> &[KmsObjectId] {
&self.framebuffers
}
pub fn get_framebuffer(&self, id: KmsObjectId) -> Result<&KmsFramebuffer<T>> {
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<KmsObjectId> for u64 {
fn from(value: KmsObjectId) -> Self {
value.0.into()
}
}
pub(super) trait KmsObjectKind<T: GraphicsAdapter> {
fn into_object(self) -> KmsObject<T>;
fn try_from_object(object: &KmsObject<T>) -> 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! { <T>
Crtc(Mutex<KmsCrtc<T>>) = DRM_MODE_OBJECT_CRTC,
Connector(Mutex<KmsConnector<T>>) = DRM_MODE_OBJECT_CONNECTOR,
Encoder(KmsEncoder) = DRM_MODE_OBJECT_ENCODER,
Property(KmsProperty) = DRM_MODE_OBJECT_PROPERTY,
Plane(Mutex<KmsPlane<T>>) = DRM_MODE_OBJECT_PLANE,
Framebuffer(KmsFramebuffer<T>) = 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<T: GraphicsAdapter> {
pub crtc_index: u32,
pub gamma_size: u32,
pub properties: Vec<KmsPropertyData<Self>>,
pub primary_plane: KmsObjectId,
pub state: KmsCrtcState<T>,
pub driver_data: T::Crtc,
}
#[derive(Debug)]
pub struct KmsCrtcState<T: GraphicsAdapter> {
pub mode: Option<drm_mode_modeinfo>,
pub driver_data: <T::Crtc as KmsCrtcDriver>::State,
}
impl<T: GraphicsAdapter> Clone for KmsCrtcState<T> {
fn clone(&self) -> Self {
Self {
mode: self.mode.clone(),
driver_data: self.driver_data.clone(),
}
}
}
define_object_props!(object, KmsCrtc<T: GraphicsAdapter> {
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<T: GraphicsAdapter> {
pub plane_index: u32,
pub possible_crtcs: u32,
pub plane_type: KmsPlaneType,
pub state: KmsPlaneState<T>,
pub driver_data: T::Plane,
}
#[derive(Debug)]
pub struct KmsPlaneState<T: GraphicsAdapter> {
pub fb_id: Option<KmsObjectId>,
pub crtc_id: Option<KmsObjectId>,
pub src_rect: KmsRect<u32>,
pub crtc_rect: KmsRect<i32>,
pub driver_data: <T::Plane as KmsPlaneDriver>::State,
}
impl<T: GraphicsAdapter> Clone for KmsPlaneState<T> {
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<T> {
pub x: T,
pub y: T,
pub width: u32,
pub height: u32,
}
#[derive(Debug)]
pub struct KmsFramebuffer<T: GraphicsAdapter> {
pub width: u32,
pub height: u32,
pub pixel_format: DrmFourcc,
pub pitch: u32,
pub buffer: Arc<T::Buffer>,
pub driver_data: T::Framebuffer,
}