1#![warn(missing_debug_implementations)]
90#![deny(missing_docs)]
91
92extern crate gbm_sys as ffi;
93
94#[cfg(feature = "import-wayland")]
95pub use wayland_server;
96
97#[cfg(feature = "drm-support")]
98pub use drm;
99
100mod buffer_object;
101mod device;
102mod surface;
103
104pub use self::{buffer_object::*, device::*, surface::*};
105pub use drm_fourcc::{DrmFourcc as Format, DrmModifier as Modifier};
106
107use std::{fmt, sync::Arc};
108
109#[cfg(feature = "dynamic")]
110static LIB: std::sync::OnceLock<ffi::gbm> = std::sync::OnceLock::new();
111
112struct Gbm {
113 #[cfg(feature = "dynamic")]
114 lib: &'static ffi::gbm,
115}
116
117#[cfg(feature = "dynamic")]
118const LIBGBM_NAMES: &[&str] = &["libgbm.so", "libgbm.so.1", "libgbm.so.2"];
119
120#[cfg(feature = "dynamic")]
121fn get_or_init_lib() -> Result<&'static ffi::gbm, std::io::Error> {
122 if let Some(gbm) = LIB.get() {
123 return Ok(gbm);
124 }
125
126 let mut last_err = None;
127 for name in LIBGBM_NAMES {
128 match unsafe { ffi::gbm::new(*name) } {
129 Ok(l) => {
130 LIB.get_or_init(|| l);
131 return Ok(LIB.get().unwrap());
132 }
133 Err(e) => {
134 last_err = Some(e);
135 }
136 }
137 }
138
139 Err(std::io::Error::other(last_err.unwrap()))
140}
141
142#[allow(clippy::too_many_arguments)]
143#[allow(dead_code)]
144impl Gbm {
145 fn new() -> std::io::Result<Self> {
146 #[cfg(not(feature = "dynamic"))]
147 return Ok(Self {});
148 #[cfg(feature = "dynamic")]
149 Ok(Self {
150 lib: get_or_init_lib()?,
151 })
152 }
153
154 unsafe fn gbm_device_get_fd(&self, gbm: *mut ffi::gbm_device) -> libc::c_int {
155 #[cfg(not(feature = "dynamic"))]
156 return ffi::gbm_device_get_fd(gbm);
157 #[cfg(feature = "dynamic")]
158 return self.lib.gbm_device_get_fd(gbm);
159 }
160
161 unsafe fn gbm_device_get_backend_name(&self, gbm: *mut ffi::gbm_device) -> *const libc::c_char {
162 #[cfg(not(feature = "dynamic"))]
163 return ffi::gbm_device_get_backend_name(gbm);
164 #[cfg(feature = "dynamic")]
165 return self.lib.gbm_device_get_backend_name(gbm);
166 }
167
168 unsafe fn gbm_device_is_format_supported(
169 &self,
170 gbm: *mut ffi::gbm_device,
171 format: u32,
172 flags: u32,
173 ) -> libc::c_int {
174 #[cfg(not(feature = "dynamic"))]
175 return ffi::gbm_device_is_format_supported(gbm, format, flags);
176 #[cfg(feature = "dynamic")]
177 return self.lib.gbm_device_is_format_supported(gbm, format, flags);
178 }
179
180 unsafe fn gbm_device_get_format_modifier_plane_count(
181 &self,
182 gbm: *mut ffi::gbm_device,
183 format: u32,
184 modifier: u64,
185 ) -> libc::c_int {
186 #[cfg(not(feature = "dynamic"))]
187 return ffi::gbm_device_get_format_modifier_plane_count(gbm, format, modifier);
188 #[cfg(feature = "dynamic")]
189 return self
190 .lib
191 .gbm_device_get_format_modifier_plane_count(gbm, format, modifier);
192 }
193
194 unsafe fn gbm_device_destroy(&self, gbm: *mut ffi::gbm_device) {
195 #[cfg(not(feature = "dynamic"))]
196 ffi::gbm_device_destroy(gbm);
197 #[cfg(feature = "dynamic")]
198 self.lib.gbm_device_destroy(gbm);
199 }
200
201 unsafe fn gbm_create_device(&self, fd: libc::c_int) -> *mut ffi::gbm_device {
202 #[cfg(not(feature = "dynamic"))]
203 return ffi::gbm_create_device(fd);
204 #[cfg(feature = "dynamic")]
205 return self.lib.gbm_create_device(fd);
206 }
207
208 unsafe fn gbm_bo_create(
209 &self,
210 gbm: *mut ffi::gbm_device,
211 width: u32,
212 height: u32,
213 format: u32,
214 flags: u32,
215 ) -> *mut ffi::gbm_bo {
216 #[cfg(not(feature = "dynamic"))]
217 return ffi::gbm_bo_create(gbm, width, height, format, flags);
218 #[cfg(feature = "dynamic")]
219 return self.lib.gbm_bo_create(gbm, width, height, format, flags);
220 }
221
222 unsafe fn gbm_bo_create_with_modifiers(
223 &self,
224 gbm: *mut ffi::gbm_device,
225 width: u32,
226 height: u32,
227 format: u32,
228 modifiers: *const u64,
229 count: libc::c_uint,
230 ) -> *mut ffi::gbm_bo {
231 #[cfg(not(feature = "dynamic"))]
232 return ffi::gbm_bo_create_with_modifiers(gbm, width, height, format, modifiers, count);
233 #[cfg(feature = "dynamic")]
234 return self
235 .lib
236 .gbm_bo_create_with_modifiers(gbm, width, height, format, modifiers, count);
237 }
238
239 unsafe fn gbm_bo_create_with_modifiers2(
240 &self,
241 gbm: *mut ffi::gbm_device,
242 width: u32,
243 height: u32,
244 format: u32,
245 modifiers: *const u64,
246 count: libc::c_uint,
247 flags: u32,
248 ) -> *mut ffi::gbm_bo {
249 #[cfg(not(feature = "dynamic"))]
250 return ffi::gbm_bo_create_with_modifiers2(
251 gbm, width, height, format, modifiers, count, flags,
252 );
253 #[cfg(feature = "dynamic")]
254 return self
255 .lib
256 .gbm_bo_create_with_modifiers2(gbm, width, height, format, modifiers, count, flags);
257 }
258
259 unsafe fn gbm_bo_import(
260 &self,
261 gbm: *mut ffi::gbm_device,
262 type_: u32,
263 buffer: *mut libc::c_void,
264 flags: u32,
265 ) -> *mut ffi::gbm_bo {
266 #[cfg(not(feature = "dynamic"))]
267 return ffi::gbm_bo_import(gbm, type_, buffer, flags);
268 #[cfg(feature = "dynamic")]
269 return self.lib.gbm_bo_import(gbm, type_, buffer, flags);
270 }
271
272 unsafe fn gbm_bo_map(
273 &self,
274 bo: *mut ffi::gbm_bo,
275 x: u32,
276 y: u32,
277 width: u32,
278 height: u32,
279 flags: u32,
280 stride: *mut u32,
281 map_data: *mut *mut libc::c_void,
282 ) -> *mut libc::c_void {
283 #[cfg(not(feature = "dynamic"))]
284 return ffi::gbm_bo_map(bo, x, y, width, height, flags, stride, map_data);
285 #[cfg(feature = "dynamic")]
286 return self
287 .lib
288 .gbm_bo_map(bo, x, y, width, height, flags, stride, map_data);
289 }
290
291 unsafe fn gbm_bo_unmap(&self, bo: *mut ffi::gbm_bo, map_data: *mut libc::c_void) {
292 #[cfg(not(feature = "dynamic"))]
293 return ffi::gbm_bo_unmap(bo, map_data);
294 #[cfg(feature = "dynamic")]
295 return self.lib.gbm_bo_unmap(bo, map_data);
296 }
297
298 unsafe fn gbm_bo_get_width(&self, bo: *mut ffi::gbm_bo) -> u32 {
299 #[cfg(not(feature = "dynamic"))]
300 return ffi::gbm_bo_get_width(bo);
301 #[cfg(feature = "dynamic")]
302 return self.lib.gbm_bo_get_width(bo);
303 }
304
305 unsafe fn gbm_bo_get_height(&self, bo: *mut ffi::gbm_bo) -> u32 {
306 #[cfg(not(feature = "dynamic"))]
307 return ffi::gbm_bo_get_height(bo);
308 #[cfg(feature = "dynamic")]
309 return self.lib.gbm_bo_get_height(bo);
310 }
311
312 unsafe fn gbm_bo_get_stride(&self, bo: *mut ffi::gbm_bo) -> u32 {
313 #[cfg(not(feature = "dynamic"))]
314 return ffi::gbm_bo_get_stride(bo);
315 #[cfg(feature = "dynamic")]
316 return self.lib.gbm_bo_get_stride(bo);
317 }
318
319 unsafe fn gbm_bo_get_stride_for_plane(&self, bo: *mut ffi::gbm_bo, plane: libc::c_int) -> u32 {
320 #[cfg(not(feature = "dynamic"))]
321 return ffi::gbm_bo_get_stride_for_plane(bo, plane);
322 #[cfg(feature = "dynamic")]
323 return self.lib.gbm_bo_get_stride_for_plane(bo, plane);
324 }
325
326 unsafe fn gbm_bo_get_format(&self, bo: *mut ffi::gbm_bo) -> u32 {
327 #[cfg(not(feature = "dynamic"))]
328 return ffi::gbm_bo_get_format(bo);
329 #[cfg(feature = "dynamic")]
330 return self.lib.gbm_bo_get_format(bo);
331 }
332
333 unsafe fn gbm_bo_get_bpp(&self, bo: *mut ffi::gbm_bo) -> u32 {
334 #[cfg(not(feature = "dynamic"))]
335 return ffi::gbm_bo_get_bpp(bo);
336 #[cfg(feature = "dynamic")]
337 return self.lib.gbm_bo_get_bpp(bo);
338 }
339
340 unsafe fn gbm_bo_get_offset(&self, bo: *mut ffi::gbm_bo, plane: libc::c_int) -> u32 {
341 #[cfg(not(feature = "dynamic"))]
342 return ffi::gbm_bo_get_offset(bo, plane);
343 #[cfg(feature = "dynamic")]
344 return self.lib.gbm_bo_get_offset(bo, plane);
345 }
346
347 unsafe fn gbm_bo_get_device(&self, bo: *mut ffi::gbm_bo) -> *mut ffi::gbm_device {
348 #[cfg(not(feature = "dynamic"))]
349 return ffi::gbm_bo_get_device(bo);
350 #[cfg(feature = "dynamic")]
351 return self.lib.gbm_bo_get_device(bo);
352 }
353
354 unsafe fn gbm_bo_get_handle(&self, bo: *mut ffi::gbm_bo) -> ffi::gbm_bo_handle {
355 #[cfg(not(feature = "dynamic"))]
356 return ffi::gbm_bo_get_handle(bo);
357 #[cfg(feature = "dynamic")]
358 return self.lib.gbm_bo_get_handle(bo);
359 }
360
361 unsafe fn gbm_bo_get_fd(&self, bo: *mut ffi::gbm_bo) -> libc::c_int {
362 #[cfg(not(feature = "dynamic"))]
363 return ffi::gbm_bo_get_fd(bo);
364 #[cfg(feature = "dynamic")]
365 return self.lib.gbm_bo_get_fd(bo);
366 }
367
368 unsafe fn gbm_bo_get_modifier(&self, bo: *mut ffi::gbm_bo) -> u64 {
369 #[cfg(not(feature = "dynamic"))]
370 return ffi::gbm_bo_get_modifier(bo);
371 #[cfg(feature = "dynamic")]
372 return self.lib.gbm_bo_get_modifier(bo);
373 }
374
375 unsafe fn gbm_bo_get_plane_count(&self, bo: *mut ffi::gbm_bo) -> libc::c_int {
376 #[cfg(not(feature = "dynamic"))]
377 return ffi::gbm_bo_get_plane_count(bo);
378 #[cfg(feature = "dynamic")]
379 return self.lib.gbm_bo_get_plane_count(bo);
380 }
381
382 unsafe fn gbm_bo_get_handle_for_plane(
383 &self,
384 bo: *mut ffi::gbm_bo,
385 plane: libc::c_int,
386 ) -> ffi::gbm_bo_handle {
387 #[cfg(not(feature = "dynamic"))]
388 return ffi::gbm_bo_get_handle_for_plane(bo, plane);
389 #[cfg(feature = "dynamic")]
390 return self.lib.gbm_bo_get_handle_for_plane(bo, plane);
391 }
392
393 unsafe fn gbm_bo_get_fd_for_plane(
394 &self,
395 bo: *mut ffi::gbm_bo,
396 plane: libc::c_int,
397 ) -> libc::c_int {
398 #[cfg(not(feature = "dynamic"))]
399 return ffi::gbm_bo_get_fd_for_plane(bo, plane);
400 #[cfg(feature = "dynamic")]
401 return self.lib.gbm_bo_get_fd_for_plane(bo, plane);
402 }
403
404 unsafe fn gbm_bo_write(
405 &self,
406 bo: *mut ffi::gbm_bo,
407 buf: *const libc::c_void,
408 count: usize,
409 ) -> libc::c_int {
410 #[cfg(not(feature = "dynamic"))]
411 return ffi::gbm_bo_write(bo, buf, count);
412 #[cfg(feature = "dynamic")]
413 return self.lib.gbm_bo_write(bo, buf, count);
414 }
415
416 unsafe fn gbm_bo_set_user_data(
417 &self,
418 bo: *mut ffi::gbm_bo,
419 data: *mut libc::c_void,
420 destroy_user_data: ::std::option::Option<
421 unsafe extern "C" fn(arg1: *mut ffi::gbm_bo, arg2: *mut libc::c_void),
422 >,
423 ) {
424 #[cfg(not(feature = "dynamic"))]
425 return ffi::gbm_bo_set_user_data(bo, data, destroy_user_data);
426 #[cfg(feature = "dynamic")]
427 return self.lib.gbm_bo_set_user_data(bo, data, destroy_user_data);
428 }
429
430 unsafe fn gbm_bo_get_user_data(&self, bo: *mut ffi::gbm_bo) -> *mut libc::c_void {
431 #[cfg(not(feature = "dynamic"))]
432 return ffi::gbm_bo_get_user_data(bo);
433 #[cfg(feature = "dynamic")]
434 return self.lib.gbm_bo_get_user_data(bo);
435 }
436
437 unsafe fn gbm_bo_destroy(&self, bo: *mut ffi::gbm_bo) {
438 #[cfg(not(feature = "dynamic"))]
439 return ffi::gbm_bo_destroy(bo);
440 #[cfg(feature = "dynamic")]
441 return self.lib.gbm_bo_destroy(bo);
442 }
443
444 unsafe fn gbm_surface_create(
445 &self,
446 gbm: *mut ffi::gbm_device,
447 width: u32,
448 height: u32,
449 format: u32,
450 flags: u32,
451 ) -> *mut ffi::gbm_surface {
452 #[cfg(not(feature = "dynamic"))]
453 return ffi::gbm_surface_create(gbm, width, height, format, flags);
454 #[cfg(feature = "dynamic")]
455 return self
456 .lib
457 .gbm_surface_create(gbm, width, height, format, flags);
458 }
459
460 unsafe fn gbm_surface_create_with_modifiers(
461 &self,
462 gbm: *mut ffi::gbm_device,
463 width: u32,
464 height: u32,
465 format: u32,
466 modifiers: *const u64,
467 count: libc::c_uint,
468 ) -> *mut ffi::gbm_surface {
469 #[cfg(not(feature = "dynamic"))]
470 return ffi::gbm_surface_create_with_modifiers(
471 gbm, width, height, format, modifiers, count,
472 );
473 #[cfg(feature = "dynamic")]
474 return self
475 .lib
476 .gbm_surface_create_with_modifiers(gbm, width, height, format, modifiers, count);
477 }
478
479 unsafe fn gbm_surface_create_with_modifiers2(
480 &self,
481 gbm: *mut ffi::gbm_device,
482 width: u32,
483 height: u32,
484 format: u32,
485 modifiers: *const u64,
486 count: libc::c_uint,
487 flags: u32,
488 ) -> *mut ffi::gbm_surface {
489 #[cfg(not(feature = "dynamic"))]
490 return ffi::gbm_surface_create_with_modifiers2(
491 gbm, width, height, format, modifiers, count, flags,
492 );
493 #[cfg(feature = "dynamic")]
494 return self.lib.gbm_surface_create_with_modifiers2(
495 gbm, width, height, format, modifiers, count, flags,
496 );
497 }
498
499 unsafe fn gbm_surface_lock_front_buffer(
500 &self,
501 surface: *mut ffi::gbm_surface,
502 ) -> *mut ffi::gbm_bo {
503 #[cfg(not(feature = "dynamic"))]
504 return ffi::gbm_surface_lock_front_buffer(surface);
505 #[cfg(feature = "dynamic")]
506 return self.lib.gbm_surface_lock_front_buffer(surface);
507 }
508
509 unsafe fn gbm_surface_release_buffer(
510 &self,
511 surface: *mut ffi::gbm_surface,
512 bo: *mut ffi::gbm_bo,
513 ) {
514 #[cfg(not(feature = "dynamic"))]
515 return ffi::gbm_surface_release_buffer(surface, bo);
516 #[cfg(feature = "dynamic")]
517 return self.lib.gbm_surface_release_buffer(surface, bo);
518 }
519
520 unsafe fn gbm_surface_has_free_buffers(&self, surface: *mut ffi::gbm_surface) -> libc::c_int {
521 #[cfg(not(feature = "dynamic"))]
522 return ffi::gbm_surface_has_free_buffers(surface);
523 #[cfg(feature = "dynamic")]
524 return self.lib.gbm_surface_has_free_buffers(surface);
525 }
526
527 unsafe fn gbm_surface_destroy(&self, surface: *mut ffi::gbm_surface) {
528 #[cfg(not(feature = "dynamic"))]
529 return ffi::gbm_surface_destroy(surface);
530 #[cfg(feature = "dynamic")]
531 return self.lib.gbm_surface_destroy(surface);
532 }
533
534 unsafe fn gbm_format_get_name(
535 &self,
536 gbm_format: u32,
537 desc: *mut ffi::gbm_format_name_desc,
538 ) -> *mut libc::c_char {
539 #[cfg(not(feature = "dynamic"))]
540 return ffi::gbm_format_get_name(gbm_format, desc);
541 #[cfg(feature = "dynamic")]
542 return self.lib.gbm_format_get_name(gbm_format, desc);
543 }
544}
545
546pub trait AsRaw<T> {
548 fn as_raw(&self) -> *const T;
550
551 #[doc(hidden)]
552 fn as_raw_mut(&self) -> *mut T {
553 self.as_raw() as *mut _
554 }
555}
556
557struct PtrDrop<T>(*mut T, Option<Box<dyn FnOnce(*mut T) + Send + 'static>>);
561
562impl<T> Drop for PtrDrop<T> {
563 fn drop(&mut self) {
564 (self.1.take().unwrap())(self.0);
565 }
566}
567
568#[derive(Clone)]
583pub(crate) struct Ptr<T>(Arc<PtrDrop<T>>);
584
585unsafe impl<T> Send for Ptr<T> {}
590unsafe impl<T> Sync for Ptr<T> {}
591
592impl<T> Ptr<T> {
593 fn new<F: FnOnce(*mut T) + Send + 'static>(ptr: *mut T, destructor: F) -> Ptr<T> {
594 Ptr(Arc::new(PtrDrop(ptr, Some(Box::new(destructor)))))
595 }
596}
597
598impl<T> std::ops::Deref for Ptr<T> {
599 type Target = *mut T;
600
601 fn deref(&self) -> &Self::Target {
602 &(self.0).0
603 }
604}
605
606impl<T> fmt::Pointer for Ptr<T> {
607 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
608 fmt::Pointer::fmt(&self.0 .0, f)
609 }
610}
611
612#[cfg(test)]
613mod test {
614 use std::os::unix::io::OwnedFd;
615
616 fn is_send<T: Send>() {}
617 fn is_sync<T: Sync>() {}
618
619 #[test]
620 fn device_is_send() {
621 is_send::<super::Device<std::fs::File>>();
622 is_send::<super::Device<OwnedFd>>();
623 }
624
625 #[test]
626 fn device_is_sync() {
627 is_sync::<super::Device<std::fs::File>>();
628 is_sync::<super::Device<OwnedFd>>();
629 }
630
631 #[test]
632 fn surface_is_send() {
633 is_send::<super::Surface<std::fs::File>>();
634 is_send::<super::Surface<OwnedFd>>();
635 }
636
637 #[test]
638 fn surface_is_sync() {
639 is_sync::<super::Surface<std::fs::File>>();
640 is_sync::<super::Surface<OwnedFd>>();
641 }
642
643 #[test]
644 fn unmapped_bo_is_send() {
645 is_send::<super::BufferObject<()>>();
646 }
647
648 #[test]
649 fn unmapped_bo_is_sync() {
650 is_sync::<super::BufferObject<()>>();
651 }
652}