364 lines
9.7 KiB
Rust
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,
|
|
}
|