Skip to main content

ferroui_linuxframebuffer/output/
drm.rs

1//! The declarations of `libdrm` and `libgbm` the DRM output uses (the port
2//! of `Output/Drm.cs`).
3//!
4//! The structures are those of `xf86drmMode.h`, `xf86drm.h` and `gbm.h`,
5//! declared `#[repr(C)]` and tested for their sizes and the offsets of
6//! their fields. The reference declares platform invokes of `libdrm.so.2`
7//! and `libgbm.so.1`; here both libraries are opened at run time and their
8//! functions resolved into a table ([`lib_drm::LibDrm`]), as the `libinput`
9//! backend does (`native_library.rs`).
10
11#![allow(non_camel_case_types)]
12
13/// The state of a connector (`drmModeConnection`).
14///
15/// A value of the library, which may be one this declaration does not
16/// name: a number with the known values as constants.
17#[repr(transparent)]
18#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
19pub struct DrmModeConnection(pub u32);
20
21impl DrmModeConnection {
22    pub const DRM_MODE_CONNECTED: Self = Self(1);
23    pub const DRM_MODE_DISCONNECTED: Self = Self(2);
24    pub const DRM_MODE_UNKNOWNCONNECTION: Self = Self(3);
25}
26
27/// The order of the subpixels of a connector (`drmModeSubPixel`).
28#[repr(transparent)]
29#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
30pub struct DrmModeSubPixel(pub u32);
31
32impl DrmModeSubPixel {
33    pub const DRM_MODE_SUBPIXEL_UNKNOWN: Self = Self(1);
34    pub const DRM_MODE_SUBPIXEL_HORIZONTAL_RGB: Self = Self(2);
35    pub const DRM_MODE_SUBPIXEL_HORIZONTAL_BGR: Self = Self(3);
36    pub const DRM_MODE_SUBPIXEL_VERTICAL_RGB: Self = Self(4);
37    pub const DRM_MODE_SUBPIXEL_VERTICAL_BGR: Self = Self(5);
38    pub const DRM_MODE_SUBPIXEL_NONE: Self = Self(6);
39}
40
41/// The functions and structures of the two libraries (the static class
42/// `LibDrm` of the reference).
43pub mod lib_drm {
44    use super::{DrmModeConnection, DrmModeSubPixel};
45    use ferroui_base::PixelSize;
46    use std::ffi::{c_char, c_int, c_uint, c_void};
47
48    /// The handler of a vertical blank event.
49    pub type DrmEventVBlankHandlerDelegate =
50        unsafe extern "C" fn(fd: c_int, sequence: c_uint, tv_sec: c_uint, tv_usec: c_uint, user_data: *mut c_void);
51
52    /// The handler of a page flip event.
53    pub type DrmEventPageFlipHandlerDelegate =
54        unsafe extern "C" fn(fd: c_int, sequence: c_uint, tv_sec: c_uint, tv_usec: c_uint, user_data: *mut c_void);
55
56    /// The handler of a page flip event that names the CRTC. (The
57    /// reference declares a pointer as its result; the C function returns
58    /// nothing.)
59    pub type DrmEventPageFlipHandler2Delegate = unsafe extern "C" fn(
60        fd: c_int,
61        sequence: c_uint,
62        tv_sec: c_uint,
63        tv_usec: c_uint,
64        crtc_id: c_uint,
65        user_data: *mut c_void,
66    );
67
68    /// The handler of a sequence event.
69    pub type DrmEventSequenceHandlerDelegate = unsafe extern "C" fn(fd: c_int, sequence: u64, ns: u64, user_data: u64);
70
71    /// `drmEventContext`: the handlers `drmHandleEvent` calls.
72    #[repr(C)]
73    #[derive(Clone, Copy, Default)]
74    pub struct DrmEventContext {
75        /// 4: the version of the structure with every handler below.
76        pub version: c_int,
77        pub vblank_handler: Option<DrmEventVBlankHandlerDelegate>,
78        pub page_flip_handler: Option<DrmEventPageFlipHandlerDelegate>,
79        pub page_flip_handler2: Option<DrmEventPageFlipHandler2Delegate>,
80        pub sequence_handler: Option<DrmEventSequenceHandlerDelegate>,
81    }
82
83    /// `drmModeRes`: the resources of a card.
84    #[repr(C)]
85    #[derive(Clone, Copy, Debug)]
86    pub struct drmModeRes {
87        pub count_fbs: c_int,
88        pub fbs: *mut u32,
89
90        pub count_crtcs: c_int,
91        pub crtcs: *mut u32,
92
93        pub count_connectors: c_int,
94        pub connectors: *mut u32,
95
96        pub count_encoders: c_int,
97        pub encoders: *mut u32,
98
99        pub(crate) min_width: u32,
100        pub(crate) max_width: u32,
101        pub(crate) min_height: u32,
102        pub(crate) max_height: u32,
103    }
104
105    /// The kind of a mode (`DRM_MODE_TYPE_*`), a set of flags.
106    #[repr(transparent)]
107    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
108    pub struct DrmModeType(pub u32);
109
110    impl DrmModeType {
111        pub const DRM_MODE_TYPE_BUILTIN: Self = Self(1 << 0);
112        pub const DRM_MODE_TYPE_CLOCK_C: Self = Self((1 << 1) | Self::DRM_MODE_TYPE_BUILTIN.0);
113        pub const DRM_MODE_TYPE_CRTC_C: Self = Self((1 << 2) | Self::DRM_MODE_TYPE_BUILTIN.0);
114        pub const DRM_MODE_TYPE_PREFERRED: Self = Self(1 << 3);
115        pub const DRM_MODE_TYPE_DEFAULT: Self = Self(1 << 4);
116        pub const DRM_MODE_TYPE_USERDEF: Self = Self(1 << 5);
117        pub const DRM_MODE_TYPE_DRIVER: Self = Self(1 << 6);
118
119        /// Whether every flag of `flags` is set (`HasAllFlags`).
120        pub const fn has_all_flags(self, flags: Self) -> bool {
121            self.0 & flags.0 == flags.0
122        }
123    }
124
125    impl std::ops::BitOr for DrmModeType {
126        type Output = Self;
127
128        fn bitor(self, rhs: Self) -> Self {
129            Self(self.0 | rhs.0)
130        }
131    }
132
133    /// `drmModeModeInfo`: a display mode.
134    #[repr(C)]
135    #[derive(Clone, Copy, Debug)]
136    pub struct drmModeModeInfo {
137        pub clock: u32,
138        pub hdisplay: u16,
139        pub hsync_start: u16,
140        pub hsync_end: u16,
141        pub htotal: u16,
142        pub hskew: u16,
143        pub vdisplay: u16,
144        pub vsync_start: u16,
145        pub vsync_end: u16,
146        pub vtotal: u16,
147        pub vscan: u16,
148
149        pub vrefresh: u32,
150
151        pub flags: u32,
152        pub type_: DrmModeType,
153        pub name: [c_char; 32],
154    }
155
156    impl Default for drmModeModeInfo {
157        fn default() -> Self {
158            Self {
159                clock: 0,
160                hdisplay: 0,
161                hsync_start: 0,
162                hsync_end: 0,
163                htotal: 0,
164                hskew: 0,
165                vdisplay: 0,
166                vsync_start: 0,
167                vsync_end: 0,
168                vtotal: 0,
169                vscan: 0,
170                vrefresh: 0,
171                flags: 0,
172                type_: DrmModeType::default(),
173                name: [0; 32],
174            }
175        }
176    }
177
178    impl drmModeModeInfo {
179        pub fn resolution(&self) -> PixelSize {
180            PixelSize::new(self.hdisplay as i32, self.vdisplay as i32)
181        }
182    }
183
184    /// `drmModeConnector`: a connector and its modes.
185    #[repr(C)]
186    #[derive(Clone, Copy, Debug)]
187    pub struct drmModeConnector {
188        pub connector_id: u32,
189        /// Encoder currently connected to
190        pub encoder_id: u32,
191        pub connector_type: u32,
192        pub connector_type_id: u32,
193        pub connection: DrmModeConnection,
194        /// HxW in millimeters
195        pub mm_width: u32,
196        pub mm_height: u32,
197        pub subpixel: DrmModeSubPixel,
198
199        pub count_modes: c_int,
200        pub modes: *mut drmModeModeInfo,
201
202        pub count_props: c_int,
203        /// List of property ids
204        pub props: *mut u32,
205        /// List of property values
206        pub prop_values: *mut u64,
207
208        pub count_encoders: c_int,
209        /// List of encoder ids
210        pub encoders: *mut u32,
211    }
212
213    /// `drmModeEncoder`.
214    #[repr(C)]
215    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
216    pub struct drmModeEncoder {
217        pub encoder_id: u32,
218        pub encoder_type: u32,
219        pub crtc_id: u32,
220        pub possible_crtcs: u32,
221        pub possible_clones: u32,
222    }
223
224    /// `drmModeCrtc`.
225    #[repr(C)]
226    #[derive(Clone, Copy, Debug, Default)]
227    pub struct drmModeCrtc {
228        pub crtc_id: u32,
229        /// FB id to connect to 0 = disconnect
230        pub buffer_id: u32,
231
232        /// Position on the framebuffer
233        pub x: u32,
234        pub y: u32,
235        pub width: u32,
236        pub height: u32,
237        pub mode_valid: c_int,
238        pub mode: drmModeModeInfo,
239
240        /// Number of gamma stops
241        pub gamma_size: c_int,
242    }
243
244    /// The flags of `drmModePageFlip` (`DRM_MODE_PAGE_FLIP_*`).
245    #[repr(transparent)]
246    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
247    pub struct DrmModePageFlip(pub u32);
248
249    impl DrmModePageFlip {
250        pub const EVENT: Self = Self(1);
251        pub const ASYNC: Self = Self(2);
252        pub const ABSOLUTE: Self = Self(4);
253        pub const RELATIVE: Self = Self(8);
254    }
255
256    /// The uses of a buffer object (`enum gbm_bo_flags`), a set of flags.
257    #[repr(transparent)]
258    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
259    pub struct GbmBoFlags(pub u32);
260
261    impl GbmBoFlags {
262        /// Buffer is going to be presented to the screen using an API such as KMS
263        pub const GBM_BO_USE_SCANOUT: Self = Self(1 << 0);
264        /// Buffer is going to be used as cursor
265        pub const GBM_BO_USE_CURSOR: Self = Self(1 << 1);
266        /// Deprecated
267        pub const GBM_BO_USE_CURSOR_64X64: Self = Self::GBM_BO_USE_CURSOR;
268        /// Buffer is to be used for rendering - for example it is going to be used
269        /// as the storage for a color buffer
270        pub const GBM_BO_USE_RENDERING: Self = Self(1 << 2);
271        /// Buffer can be used for gbm_bo_write.  This is guaranteed to work
272        /// with GBM_BO_USE_CURSOR, but may not work for other combinations.
273        pub const GBM_BO_USE_WRITE: Self = Self(1 << 3);
274        /// Buffer is linear, i.e. not tiled.
275        pub const GBM_BO_USE_LINEAR: Self = Self(1 << 4);
276    }
277
278    impl std::ops::BitOr for GbmBoFlags {
279        type Output = Self;
280
281        fn bitor(self, rhs: Self) -> Self {
282            Self(self.0 | rhs.0)
283        }
284    }
285
286    /// Called by `libgbm` when a buffer object with user data is destroyed.
287    pub type GbmBoUserDataDestroyCallbackDelegate = unsafe extern "C" fn(bo: *mut c_void, data: *mut c_void);
288
289    /// `union gbm_bo_handle`: the handle of a buffer object.
290    #[repr(C)]
291    #[derive(Clone, Copy)]
292    pub union GbmBoHandle {
293        pub ptr: *mut c_void,
294        pub s32: i32,
295        pub u32: u32,
296        pub s64: i64,
297        pub u64: u64,
298    }
299
300    /// The pixel formats of buffers (`GBM_FORMAT_*`).
301    pub mod gbm_color_formats {
302        /// The code of a format: four characters, the first in the low byte.
303        pub const fn four_cc(a: u8, b: u8, c: u8, d: u8) -> u32 {
304            (a as u32) | (b as u32) << 8 | (c as u32) << 16 | (d as u32) << 24
305        }
306
307        pub const GBM_FORMAT_XRGB8888: u32 = four_cc(b'X', b'R', b'2', b'4');
308    }
309
310    #[cfg(target_os = "linux")]
311    pub(crate) use imp::LibDrm;
312
313    #[cfg(target_os = "linux")]
314    mod imp {
315        use super::*;
316        use crate::native_library::load_library;
317        use std::io;
318        use std::sync::OnceLock;
319
320        ferroui_base::native_functions! {
321            /// The functions of `libdrm` the output calls.
322            pub struct LibDrmFunctions(lib) {
323                lib::drmModeGetResources: unsafe extern "C" fn(c_int) -> *mut drmModeRes;
324                lib::drmModeFreeResources: unsafe extern "C" fn(*mut drmModeRes);
325                lib::drmModeGetConnector: unsafe extern "C" fn(c_int, u32) -> *mut drmModeConnector;
326                lib::drmModeGetConnectorCurrent: unsafe extern "C" fn(c_int, u32) -> *mut drmModeConnector;
327                lib::drmModeFreeConnector: unsafe extern "C" fn(*mut drmModeConnector);
328                lib::drmModeGetEncoder: unsafe extern "C" fn(c_int, u32) -> *mut drmModeEncoder;
329                lib::drmModeFreeEncoder: unsafe extern "C" fn(*mut drmModeEncoder);
330                lib::drmModeGetCrtc: unsafe extern "C" fn(c_int, u32) -> *mut drmModeCrtc;
331                lib::drmModeFreeCrtc: unsafe extern "C" fn(*mut drmModeCrtc);
332                lib::drmModeAddFB: unsafe extern "C" fn(c_int, u32, u32, u8, u8, u32, u32, *mut u32) -> c_int;
333                lib::drmModeAddFB2: unsafe extern "C" fn(c_int, u32, u32, u32, *const u32, *const u32, *const u32, *mut u32, u32) -> c_int;
334                lib::drmModeSetCrtc: unsafe extern "C" fn(c_int, u32, u32, u32, u32, *mut u32, c_int, *mut drmModeModeInfo) -> c_int;
335                lib::drmModeRmFB: unsafe extern "C" fn(c_int, u32) -> c_int;
336                lib::drmModePageFlip: unsafe extern "C" fn(c_int, u32, u32, u32, *mut c_void) -> c_int;
337                lib::drmHandleEvent: unsafe extern "C" fn(c_int, *mut DrmEventContext) -> c_int;
338            }
339        }
340
341        ferroui_base::native_functions! {
342            /// The functions of `libgbm` the output calls.
343            pub struct LibGbmFunctions(lib) {
344                lib::gbm_create_device: unsafe extern "C" fn(c_int) -> *mut c_void;
345                lib::gbm_surface_create: unsafe extern "C" fn(*mut c_void, u32, u32, u32, u32) -> *mut c_void;
346                lib::gbm_surface_lock_front_buffer: unsafe extern "C" fn(*mut c_void) -> *mut c_void;
347                lib::gbm_surface_release_buffer: unsafe extern "C" fn(*mut c_void, *mut c_void);
348                lib::gbm_bo_get_user_data: unsafe extern "C" fn(*mut c_void) -> *mut c_void;
349                lib::gbm_bo_set_user_data: unsafe extern "C" fn(*mut c_void, *mut c_void, Option<GbmBoUserDataDestroyCallbackDelegate>);
350                lib::gbm_bo_get_width: unsafe extern "C" fn(*mut c_void) -> u32;
351                lib::gbm_bo_get_height: unsafe extern "C" fn(*mut c_void) -> u32;
352                lib::gbm_bo_get_stride: unsafe extern "C" fn(*mut c_void) -> u32;
353                lib::gbm_bo_get_format: unsafe extern "C" fn(*mut c_void) -> u32;
354                lib::gbm_bo_get_handle: unsafe extern "C" fn(*mut c_void) -> GbmBoHandle;
355            }
356        }
357
358        /// The two libraries, opened once for the process.
359        pub(crate) struct LibDrm {
360            pub(crate) drm: LibDrmFunctions,
361            pub(crate) gbm: LibGbmFunctions,
362        }
363
364        impl LibDrm {
365            /// The libraries; an error that names the library or the
366            /// function that is missing.
367            pub(crate) fn get() -> io::Result<&'static LibDrm> {
368                static LIBRARIES: OnceLock<Result<LibDrm, String>> = OnceLock::new();
369                LIBRARIES
370                    .get_or_init(|| {
371                        Ok(LibDrm {
372                            drm: load_library(c"libdrm.so.2", LibDrmFunctions::load)?,
373                            gbm: load_library(c"libgbm.so.1", LibGbmFunctions::load)?,
374                        })
375                    })
376                    .as_ref()
377                    .map_err(|error| io::Error::new(io::ErrorKind::NotFound, error.clone()))
378            }
379        }
380
381        // The functions of the reference's class, each a call of the table of its library.
382        //
383        // # Safety (of every function below)
384        // The arguments satisfy the contract of the C function of the same name: a descriptor of
385        // an open card, objects of the library that are alive, pointers to as many elements as
386        // the function reads or writes.
387        #[allow(clippy::missing_safety_doc, clippy::too_many_arguments)]
388        impl LibDrm {
389            pub(crate) unsafe fn drm_mode_get_resources(&self, fd: c_int) -> *mut drmModeRes {
390                unsafe { (self.drm.drmModeGetResources)(fd) }
391            }
392
393            pub(crate) unsafe fn drm_mode_free_resources(&self, res: *mut drmModeRes) {
394                unsafe { (self.drm.drmModeFreeResources)(res) }
395            }
396
397            pub(crate) unsafe fn drm_mode_get_connector(&self, fd: c_int, connector: u32) -> *mut drmModeConnector {
398                unsafe { (self.drm.drmModeGetConnector)(fd, connector) }
399            }
400
401            pub(crate) unsafe fn drm_mode_get_connector_current(&self, fd: c_int, connector: u32) -> *mut drmModeConnector {
402                unsafe { (self.drm.drmModeGetConnectorCurrent)(fd, connector) }
403            }
404
405            pub(crate) unsafe fn drm_mode_free_connector(&self, res: *mut drmModeConnector) {
406                unsafe { (self.drm.drmModeFreeConnector)(res) }
407            }
408
409            pub(crate) unsafe fn drm_mode_get_encoder(&self, fd: c_int, id: u32) -> *mut drmModeEncoder {
410                unsafe { (self.drm.drmModeGetEncoder)(fd, id) }
411            }
412
413            pub(crate) unsafe fn drm_mode_free_encoder(&self, enc: *mut drmModeEncoder) {
414                unsafe { (self.drm.drmModeFreeEncoder)(enc) }
415            }
416
417            pub(crate) unsafe fn drm_mode_get_crtc(&self, fd: c_int, id: u32) -> *mut drmModeCrtc {
418                unsafe { (self.drm.drmModeGetCrtc)(fd, id) }
419            }
420
421            pub(crate) unsafe fn drm_mode_free_crtc(&self, enc: *mut drmModeCrtc) {
422                unsafe { (self.drm.drmModeFreeCrtc)(enc) }
423            }
424
425            pub(crate) unsafe fn drm_mode_add_fb(
426                &self,
427                fd: c_int,
428                width: u32,
429                height: u32,
430                depth: u8,
431                bpp: u8,
432                pitch: u32,
433                bo_handle: u32,
434                buf_id: &mut u32,
435            ) -> c_int {
436                unsafe { (self.drm.drmModeAddFB)(fd, width, height, depth, bpp, pitch, bo_handle, buf_id) }
437            }
438
439            pub(crate) unsafe fn drm_mode_add_fb2(
440                &self,
441                fd: c_int,
442                width: u32,
443                height: u32,
444                pixel_format: u32,
445                bo_handles: &[u32; 4],
446                pitches: &[u32; 4],
447                offsets: &[u32; 4],
448                buf_id: &mut u32,
449                flags: u32,
450            ) -> c_int {
451                unsafe {
452                    (self.drm.drmModeAddFB2)(
453                        fd,
454                        width,
455                        height,
456                        pixel_format,
457                        bo_handles.as_ptr(),
458                        pitches.as_ptr(),
459                        offsets.as_ptr(),
460                        buf_id,
461                        flags,
462                    )
463                }
464            }
465
466            pub(crate) unsafe fn drm_mode_set_crtc(
467                &self,
468                fd: c_int,
469                crtc_id: u32,
470                buffer_id: u32,
471                x: u32,
472                y: u32,
473                connectors: *mut u32,
474                count: c_int,
475                mode: *mut drmModeModeInfo,
476            ) -> c_int {
477                unsafe { (self.drm.drmModeSetCrtc)(fd, crtc_id, buffer_id, x, y, connectors, count, mode) }
478            }
479
480            pub(crate) unsafe fn drm_mode_rm_fb(&self, fd: c_int, id: u32) -> c_int {
481                unsafe { (self.drm.drmModeRmFB)(fd, id) }
482            }
483
484            pub(crate) unsafe fn drm_mode_page_flip(
485                &self,
486                fd: c_int,
487                crtc_id: u32,
488                fb_id: u32,
489                flags: DrmModePageFlip,
490                user_data: *mut c_void,
491            ) -> c_int {
492                unsafe { (self.drm.drmModePageFlip)(fd, crtc_id, fb_id, flags.0, user_data) }
493            }
494
495            pub(crate) unsafe fn drm_handle_event(&self, fd: c_int, context: *mut DrmEventContext) -> c_int {
496                unsafe { (self.drm.drmHandleEvent)(fd, context) }
497            }
498
499            pub(crate) unsafe fn gbm_create_device(&self, fd: c_int) -> *mut c_void {
500                unsafe { (self.gbm.gbm_create_device)(fd) }
501            }
502
503            pub(crate) unsafe fn gbm_surface_create(
504                &self,
505                device: *mut c_void,
506                width: u32,
507                height: u32,
508                format: u32,
509                flags: GbmBoFlags,
510            ) -> *mut c_void {
511                unsafe { (self.gbm.gbm_surface_create)(device, width, height, format, flags.0) }
512            }
513
514            pub(crate) unsafe fn gbm_surface_lock_front_buffer(&self, surface: *mut c_void) -> *mut c_void {
515                unsafe { (self.gbm.gbm_surface_lock_front_buffer)(surface) }
516            }
517
518            pub(crate) unsafe fn gbm_surface_release_buffer(&self, surface: *mut c_void, bo: *mut c_void) {
519                unsafe { (self.gbm.gbm_surface_release_buffer)(surface, bo) }
520            }
521
522            pub(crate) unsafe fn gbm_bo_get_user_data(&self, bo: *mut c_void) -> *mut c_void {
523                unsafe { (self.gbm.gbm_bo_get_user_data)(bo) }
524            }
525
526            pub(crate) unsafe fn gbm_bo_set_user_data(
527                &self,
528                bo: *mut c_void,
529                user_data: *mut c_void,
530                on_free: Option<GbmBoUserDataDestroyCallbackDelegate>,
531            ) {
532                unsafe { (self.gbm.gbm_bo_set_user_data)(bo, user_data, on_free) }
533            }
534
535            pub(crate) unsafe fn gbm_bo_get_width(&self, bo: *mut c_void) -> u32 {
536                unsafe { (self.gbm.gbm_bo_get_width)(bo) }
537            }
538
539            pub(crate) unsafe fn gbm_bo_get_height(&self, bo: *mut c_void) -> u32 {
540                unsafe { (self.gbm.gbm_bo_get_height)(bo) }
541            }
542
543            pub(crate) unsafe fn gbm_bo_get_stride(&self, bo: *mut c_void) -> u32 {
544                unsafe { (self.gbm.gbm_bo_get_stride)(bo) }
545            }
546
547            pub(crate) unsafe fn gbm_bo_get_format(&self, bo: *mut c_void) -> u32 {
548                unsafe { (self.gbm.gbm_bo_get_format)(bo) }
549            }
550
551            pub(crate) unsafe fn gbm_bo_get_handle(&self, bo: *mut c_void) -> GbmBoHandle {
552                unsafe { (self.gbm.gbm_bo_get_handle)(bo) }
553            }
554        }
555    }
556}
557
558#[cfg(test)]
559mod tests {
560    // Not from the reference, which has no tests for this file. The sizes
561    // and offsets are those of the C declarations (xf86drmMode.h,
562    // xf86drm.h, gbm.h) on the architectures the platform runs on.
563    use super::lib_drm::*;
564    use super::*;
565    use std::mem::{offset_of, size_of};
566
567    #[test]
568    fn the_mode_info_is_the_kernels_mode_info_of_68_bytes() {
569        assert_eq!(size_of::<drmModeModeInfo>(), 68);
570        assert_eq!(offset_of!(drmModeModeInfo, hdisplay), 4);
571        assert_eq!(offset_of!(drmModeModeInfo, vdisplay), 14);
572        assert_eq!(offset_of!(drmModeModeInfo, vscan), 22);
573        assert_eq!(offset_of!(drmModeModeInfo, vrefresh), 24);
574        assert_eq!(offset_of!(drmModeModeInfo, flags), 28);
575        assert_eq!(offset_of!(drmModeModeInfo, type_), 32);
576        assert_eq!(offset_of!(drmModeModeInfo, name), 36);
577    }
578
579    #[test]
580    fn the_encoder_and_the_crtc_have_the_layout_of_the_library() {
581        assert_eq!(size_of::<drmModeEncoder>(), 20);
582        assert_eq!(offset_of!(drmModeEncoder, possible_crtcs), 12);
583        assert_eq!(size_of::<drmModeCrtc>(), 100);
584        assert_eq!(offset_of!(drmModeCrtc, mode_valid), 24);
585        assert_eq!(offset_of!(drmModeCrtc, mode), 28);
586        assert_eq!(offset_of!(drmModeCrtc, gamma_size), 96);
587    }
588
589    #[cfg(target_pointer_width = "64")]
590    #[test]
591    fn the_structures_with_pointers_have_the_layout_of_the_library_on_64_bits() {
592        assert_eq!(size_of::<drmModeRes>(), 80);
593        assert_eq!(offset_of!(drmModeRes, crtcs), 24);
594        assert_eq!(offset_of!(drmModeRes, count_connectors), 32);
595        assert_eq!(offset_of!(drmModeRes, connectors), 40);
596        assert_eq!(offset_of!(drmModeRes, count_encoders), 48);
597        assert_eq!(offset_of!(drmModeRes, encoders), 56);
598        assert_eq!(offset_of!(drmModeRes, min_width), 64);
599        assert_eq!(offset_of!(drmModeRes, max_height), 76);
600
601        assert_eq!(size_of::<drmModeConnector>(), 88);
602        assert_eq!(offset_of!(drmModeConnector, connection), 16);
603        assert_eq!(offset_of!(drmModeConnector, subpixel), 28);
604        assert_eq!(offset_of!(drmModeConnector, count_modes), 32);
605        assert_eq!(offset_of!(drmModeConnector, modes), 40);
606        assert_eq!(offset_of!(drmModeConnector, count_props), 48);
607        assert_eq!(offset_of!(drmModeConnector, props), 56);
608        assert_eq!(offset_of!(drmModeConnector, prop_values), 64);
609        assert_eq!(offset_of!(drmModeConnector, count_encoders), 72);
610        assert_eq!(offset_of!(drmModeConnector, encoders), 80);
611
612        assert_eq!(size_of::<DrmEventContext>(), 40);
613        assert_eq!(offset_of!(DrmEventContext, vblank_handler), 8);
614        assert_eq!(offset_of!(DrmEventContext, page_flip_handler), 16);
615        assert_eq!(offset_of!(DrmEventContext, page_flip_handler2), 24);
616        assert_eq!(offset_of!(DrmEventContext, sequence_handler), 32);
617    }
618
619    #[cfg(target_pointer_width = "32")]
620    #[test]
621    fn the_structures_with_pointers_have_the_layout_of_the_library_on_32_bits() {
622        assert_eq!(size_of::<drmModeRes>(), 48);
623        assert_eq!(offset_of!(drmModeRes, connectors), 20);
624        assert_eq!(offset_of!(drmModeRes, min_width), 32);
625        assert_eq!(size_of::<drmModeConnector>(), 60);
626        assert_eq!(offset_of!(drmModeConnector, modes), 36);
627        assert_eq!(offset_of!(drmModeConnector, encoders), 56);
628        assert_eq!(size_of::<DrmEventContext>(), 20);
629    }
630
631    #[test]
632    fn the_handle_of_a_buffer_object_is_a_union_of_eight_bytes() {
633        assert_eq!(size_of::<GbmBoHandle>(), 8);
634        let handle = GbmBoHandle { u64: 0x1_0000_0007 };
635        // SAFETY: every field of the union is plain data of the same storage.
636        assert_eq!(unsafe { handle.u32 }, 7);
637    }
638
639    #[test]
640    fn the_flags_and_the_format_have_the_values_of_the_headers() {
641        // GBM_FORMAT_XRGB8888 of gbm.h: __gbm_fourcc_code('X', 'R', '2', '4').
642        assert_eq!(gbm_color_formats::GBM_FORMAT_XRGB8888, 0x3432_5258);
643        assert_eq!((GbmBoFlags::GBM_BO_USE_SCANOUT | GbmBoFlags::GBM_BO_USE_RENDERING).0, 5);
644        assert_eq!(GbmBoFlags::GBM_BO_USE_CURSOR_64X64, GbmBoFlags::GBM_BO_USE_CURSOR);
645        assert_eq!(DrmModePageFlip::EVENT.0, 1);
646        assert_eq!(DrmModeType::DRM_MODE_TYPE_CLOCK_C.0, 3);
647        assert!((DrmModeType::DRM_MODE_TYPE_PREFERRED | DrmModeType::DRM_MODE_TYPE_DRIVER)
648            .has_all_flags(DrmModeType::DRM_MODE_TYPE_PREFERRED));
649        assert!(!DrmModeType::DRM_MODE_TYPE_DRIVER.has_all_flags(DrmModeType::DRM_MODE_TYPE_PREFERRED));
650        assert_eq!(DrmModeConnection::DRM_MODE_CONNECTED.0, 1);
651        assert_eq!(DrmModeSubPixel::DRM_MODE_SUBPIXEL_NONE.0, 6);
652    }
653}