1#![allow(non_camel_case_types)]
12
13#[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#[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
41pub 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 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 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 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 pub type DrmEventSequenceHandlerDelegate = unsafe extern "C" fn(fd: c_int, sequence: u64, ns: u64, user_data: u64);
70
71 #[repr(C)]
73 #[derive(Clone, Copy, Default)]
74 pub struct DrmEventContext {
75 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 #[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 #[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 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 #[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 #[repr(C)]
186 #[derive(Clone, Copy, Debug)]
187 pub struct drmModeConnector {
188 pub connector_id: u32,
189 pub encoder_id: u32,
191 pub connector_type: u32,
192 pub connector_type_id: u32,
193 pub connection: DrmModeConnection,
194 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 pub props: *mut u32,
205 pub prop_values: *mut u64,
207
208 pub count_encoders: c_int,
209 pub encoders: *mut u32,
211 }
212
213 #[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 #[repr(C)]
226 #[derive(Clone, Copy, Debug, Default)]
227 pub struct drmModeCrtc {
228 pub crtc_id: u32,
229 pub buffer_id: u32,
231
232 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 pub gamma_size: c_int,
242 }
243
244 #[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 #[repr(transparent)]
258 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
259 pub struct GbmBoFlags(pub u32);
260
261 impl GbmBoFlags {
262 pub const GBM_BO_USE_SCANOUT: Self = Self(1 << 0);
264 pub const GBM_BO_USE_CURSOR: Self = Self(1 << 1);
266 pub const GBM_BO_USE_CURSOR_64X64: Self = Self::GBM_BO_USE_CURSOR;
268 pub const GBM_BO_USE_RENDERING: Self = Self(1 << 2);
271 pub const GBM_BO_USE_WRITE: Self = Self(1 << 3);
274 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 pub type GbmBoUserDataDestroyCallbackDelegate = unsafe extern "C" fn(bo: *mut c_void, data: *mut c_void);
288
289 #[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 pub mod gbm_color_formats {
302 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 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 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 pub(crate) struct LibDrm {
360 pub(crate) drm: LibDrmFunctions,
361 pub(crate) gbm: LibGbmFunctions,
362 }
363
364 impl LibDrm {
365 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 #[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 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 assert_eq!(unsafe { handle.u32 }, 7);
637 }
638
639 #[test]
640 fn the_flags_and_the_format_have_the_values_of_the_headers() {
641 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}