linux_drm/
modeset.rs

1use alloc::boxed::Box;
2use alloc::vec::Vec;
3use core::ops::{BitAnd, BitOr};
4
5mod atomic;
6mod buffer;
7mod props;
8
9pub use atomic::*;
10pub use buffer::*;
11pub use props::*;
12
13macro_rules! id_newtype {
14    ($name:ident) => {
15        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
16        #[repr(transparent)]
17        pub struct $name(pub u32);
18
19        impl $name {
20            /// Returns the raw `u32` value of the id.
21            #[inline(always)]
22            pub const fn to_raw(self) -> u32 {
23                self.0
24            }
25
26            /// Returns true if the id is zero, representing the absense of an object.
27            #[inline(always)]
28            pub const fn is_null(self) -> bool {
29                self.0 == 0
30            }
31        }
32
33        impl props::AsRawPropertyValue for $name {
34            #[inline(always)]
35            fn as_raw_property_value(&self) -> u64 {
36                self.0 as u64
37            }
38        }
39
40        impl props::IntoRawPropertyValue for $name {
41            #[inline(always)]
42            fn into_raw_property_value(self) -> (u64, Option<Box<dyn core::any::Any>>) {
43                (self.0 as u64, None)
44            }
45        }
46    };
47}
48
49id_newtype!(FramebufferId);
50id_newtype!(CrtcId);
51id_newtype!(ConnectorId);
52id_newtype!(EncoderId);
53id_newtype!(PlaneId);
54id_newtype!(BufferObjectId);
55id_newtype!(PropertyId);
56id_newtype!(BlobId);
57
58#[derive(Debug, Clone, Copy)]
59#[non_exhaustive]
60pub enum ObjectId {
61    Crtc(CrtcId),
62    Connector(ConnectorId),
63    Encoder(EncoderId),
64    Mode(u32),
65    Property(PropertyId),
66    Framebuffer(FramebufferId),
67    Blob(BlobId),
68    Plane(PlaneId),
69}
70
71impl ObjectId {
72    pub fn as_raw_type_and_id(self) -> (u32, u32) {
73        use crate::ioctl;
74        match self {
75            ObjectId::Crtc(id) => (ioctl::DRM_MODE_OBJECT_CRTC, id.0),
76            ObjectId::Connector(id) => (ioctl::DRM_MODE_OBJECT_CONNECTOR, id.0),
77            ObjectId::Encoder(id) => (ioctl::DRM_MODE_OBJECT_ENCODER, id.0),
78            ObjectId::Mode(id) => (ioctl::DRM_MODE_OBJECT_MODE, id),
79            ObjectId::Property(id) => (ioctl::DRM_MODE_OBJECT_PROPERTY, id.0),
80            ObjectId::Framebuffer(id) => (ioctl::DRM_MODE_OBJECT_FB, id.0),
81            ObjectId::Blob(id) => (ioctl::DRM_MODE_OBJECT_BLOB, id.0),
82            ObjectId::Plane(id) => (ioctl::DRM_MODE_OBJECT_PLANE, id.0),
83        }
84    }
85}
86
87impl From<CrtcId> for ObjectId {
88    fn from(value: CrtcId) -> Self {
89        Self::Crtc(value)
90    }
91}
92
93impl From<ConnectorId> for ObjectId {
94    fn from(value: ConnectorId) -> Self {
95        Self::Connector(value)
96    }
97}
98
99impl From<EncoderId> for ObjectId {
100    fn from(value: EncoderId) -> Self {
101        Self::Encoder(value)
102    }
103}
104
105impl From<PropertyId> for ObjectId {
106    fn from(value: PropertyId) -> Self {
107        Self::Property(value)
108    }
109}
110
111impl From<FramebufferId> for ObjectId {
112    fn from(value: FramebufferId) -> Self {
113        Self::Framebuffer(value)
114    }
115}
116
117impl From<BlobId> for ObjectId {
118    fn from(value: BlobId) -> Self {
119        Self::Blob(value)
120    }
121}
122
123impl From<PlaneId> for ObjectId {
124    fn from(value: PlaneId) -> Self {
125        Self::Plane(value)
126    }
127}
128
129#[derive(Debug)]
130pub struct CardResources {
131    pub fb_ids: Vec<FramebufferId>,
132    pub crtc_ids: Vec<CrtcId>,
133    pub connector_ids: Vec<ConnectorId>,
134    pub encoder_ids: Vec<EncoderId>,
135    pub plane_ids: Vec<PlaneId>,
136    pub min_width: u32,
137    pub max_width: u32,
138    pub min_height: u32,
139    pub max_height: u32,
140}
141
142#[derive(Debug)]
143pub struct ConnectorState {
144    pub id: ConnectorId,
145    pub current_encoder_id: EncoderId,
146    pub connector_type: ConnectorType,
147    pub connector_type_id: u32,
148    pub connection_state: ConnectionState,
149    pub width_mm: u32,
150    pub height_mm: u32,
151    pub subpixel_type: SubpixelType,
152    pub modes: Vec<ModeInfo>,
153    pub props: Vec<ModeProp>,
154    pub available_encoder_ids: Vec<u32>,
155}
156
157impl ConnectorState {
158    pub fn preferred_mode(&self) -> Option<&ModeInfo> {
159        for mode in &self.modes {
160            if (mode.typ & crate::ioctl::DRM_MODE_TYPE_PREFERRED) != 0 {
161                return Some(mode);
162            }
163        }
164        None
165    }
166}
167
168#[derive(Debug, PartialEq, Eq, Copy, Clone)]
169#[repr(u32)]
170pub enum ConnectionState {
171    Connected = 1,
172    Disconnected = 2,
173    Unknown = 3,
174}
175
176impl From<u32> for ConnectionState {
177    fn from(value: u32) -> Self {
178        match value {
179            1 => Self::Connected,
180            2 => Self::Disconnected,
181            _ => Self::Unknown,
182        }
183    }
184}
185
186#[derive(Debug, PartialEq, Eq, Clone, Copy)]
187#[repr(u32)]
188pub enum ConnectorType {
189    Unknown = 0,
190    Vga = 1,
191    DviI = 2,
192    DviD = 3,
193    DviA = 4,
194    Composite = 5,
195    SVideo = 6,
196    Lvds = 7,
197    Component = 8,
198    NinePinDin = 9,
199    DisplayPort = 10,
200    HdmiA = 11,
201    HdmiB = 12,
202    Tv = 13,
203    Edp = 14,
204    Virtual = 15,
205    Dsi = 16,
206    Dpi = 17,
207    Writeback = 18,
208    Spi = 19,
209    Usb = 20,
210    Other = !0, // Not used by kernel, but used by us if kernel returns something we don't know
211}
212
213impl From<u32> for ConnectorType {
214    #[inline]
215    fn from(value: u32) -> Self {
216        if value < 21 {
217            // Safety: all values in this range are valid representations
218            // of this enum, as described above.
219            unsafe { core::mem::transmute(value) }
220        } else {
221            Self::Other
222        }
223    }
224}
225
226#[derive(Debug)]
227pub struct EncoderState {
228    pub encoder_id: EncoderId,
229    pub encoder_type: u32,
230    pub current_crtc_id: CrtcId,
231    pub possible_crtcs: u32,
232    pub possible_clones: u32,
233}
234
235#[derive(Debug)]
236pub struct CrtcState {
237    pub crtc_id: CrtcId,
238    pub fb_id: FramebufferId,
239    pub x: u32,
240    pub y: u32,
241    pub gamma_size: u32,
242    pub mode_valid: u32,
243    pub mode: ModeInfo,
244}
245
246impl From<crate::ioctl::DrmModeCrtc> for CrtcState {
247    fn from(value: crate::ioctl::DrmModeCrtc) -> Self {
248        Self {
249            crtc_id: CrtcId(value.crtc_id),
250            fb_id: FramebufferId(value.fb_id),
251            x: value.x,
252            y: value.y,
253            gamma_size: value.gamma_size,
254            mode_valid: value.mode_valid,
255            mode: value.mode.into(),
256        }
257    }
258}
259
260#[derive(Debug)]
261pub struct PlaneState {
262    pub id: PlaneId,
263    pub crtc_id: CrtcId,
264    pub fb_id: FramebufferId,
265    pub possible_crtcs: u32,
266    pub gamma_size: u32,
267}
268
269#[derive(Debug)]
270pub struct ModeInfo {
271    pub name: Vec<u8>,
272    pub clock: u32,
273    pub hdisplay: u16,
274    pub hsync_start: u16,
275    pub hsync_end: u16,
276    pub htotal: u16,
277    pub hskew: u16,
278    pub vdisplay: u16,
279    pub vsync_start: u16,
280    pub vsync_end: u16,
281    pub vtotal: u16,
282    pub vscan: u16,
283    pub vrefresh: u32,
284    pub flags: u32,
285    pub typ: u32,
286}
287
288impl From<crate::ioctl::DrmModeInfo> for ModeInfo {
289    fn from(value: crate::ioctl::DrmModeInfo) -> Self {
290        let name = value.name[..].split(|c| *c == 0).next().unwrap();
291        let name: &[u8] = unsafe { core::mem::transmute(name) };
292        Self {
293            name: name.to_vec(),
294            clock: value.clock,
295            hdisplay: value.hdisplay,
296            hsync_start: value.hsync_start,
297            hsync_end: value.hsync_end,
298            htotal: value.htotal,
299            hskew: value.hskew,
300            vdisplay: value.vdisplay,
301            vsync_start: value.vsync_start,
302            vsync_end: value.vsync_end,
303            vtotal: value.vtotal,
304            vscan: value.vscan,
305            vrefresh: value.vrefresh,
306            flags: value.flags,
307            typ: value.typ,
308        }
309    }
310}
311
312impl From<&ModeInfo> for crate::ioctl::DrmModeInfo {
313    fn from(value: &ModeInfo) -> Self {
314        let mut name_raw = [0_8; 32];
315        let name_len = core::cmp::min(name_raw.len() - 1, value.name.len());
316        let name_raw_slice = &mut name_raw[0..name_len];
317        name_raw_slice
318            .copy_from_slice(unsafe { core::mem::transmute(&value.name.as_slice()[0..name_len]) });
319        Self {
320            clock: value.clock,
321            hdisplay: value.hdisplay,
322            hsync_start: value.hsync_start,
323            hsync_end: value.hsync_end,
324            htotal: value.htotal,
325            hskew: value.hskew,
326            vdisplay: value.vdisplay,
327            vsync_start: value.vsync_start,
328            vsync_end: value.vsync_end,
329            vtotal: value.vtotal,
330            vscan: value.vscan,
331            vrefresh: value.vrefresh,
332            flags: value.flags,
333            typ: value.typ,
334            name: name_raw,
335        }
336    }
337}
338
339#[derive(Debug)]
340#[repr(u32)]
341pub enum SubpixelType {
342    Unknown = 1,
343    HorizontalRgb = 2,
344    HorizontalBgr = 3,
345    VerticalRgb = 4,
346    VerticalBgr = 5,
347    None = 6,
348}
349
350impl From<u32> for SubpixelType {
351    fn from(value: u32) -> Self {
352        match value {
353            2 => Self::HorizontalRgb,
354            3 => Self::HorizontalBgr,
355            4 => Self::VerticalRgb,
356            5 => Self::VerticalBgr,
357            _ => Self::Unknown,
358        }
359    }
360}
361
362#[derive(Debug)]
363#[repr(transparent)]
364pub struct PageFlipFlags(u32);
365
366impl PageFlipFlags {
367    pub const NONE: Self = Self(0);
368    pub const EVENT: Self = Self(crate::ioctl::DRM_MODE_PAGE_FLIP_EVENT);
369    pub const ASYNC: Self = Self(crate::ioctl::DRM_MODE_PAGE_FLIP_ASYNC);
370}
371
372impl BitOr for PageFlipFlags {
373    type Output = Self;
374
375    #[inline(always)]
376    fn bitor(self, rhs: Self) -> Self::Output {
377        Self(self.0 | rhs.0)
378    }
379}
380
381impl BitAnd for PageFlipFlags {
382    type Output = Self;
383
384    #[inline(always)]
385    fn bitand(self, rhs: Self) -> Self::Output {
386        Self(self.0 | rhs.0)
387    }
388}
389
390impl From<PageFlipFlags> for u32 {
391    #[inline(always)]
392    fn from(value: PageFlipFlags) -> Self {
393        value.0
394    }
395}