Skip to main content

drmkit_gbm/
lib.rs

1// SPDX-FileCopyrightText: (c) 2026 Joel Winarske
2// SPDX-License-Identifier: MIT
3
4//! GBM buffer allocation.
5//!
6//! A thin layer over libgbm, in the shape the rest of drmkit expects: errors
7//! as a typed enum, formats as drmkit `FourCC`s, and a buffer that hands out
8//! the descriptor a scanout path needs.
9//!
10//! GBM is how a GPU-rendered surface becomes something KMS can scan out. Where
11//! `drmkit-dumb` allocates plain linear memory the CPU writes,
12//! this asks the driver for memory its renderer can target — which on real
13//! hardware means tiled or compressed layouts, and a modifier saying which.
14//!
15//! On a driver with no render engine the `drm` backend falls back to dumb
16//! allocation, so this still works against vkms: linear, one plane, and a
17//! dma-buf that exports. That is what makes it testable without a GPU.
18//!
19//! # libgbm is opened, not linked
20//!
21//! The library is loaded on the first [`GbmDevice`], so building needs no
22//! libgbm at all and a machine without one gets [`GbmError::NotGbmCapable`]
23//! rather than a binary that will not start. Which modifier entry points it
24//! has is read there too, so one build runs against Mesa and against a
25//! vendor libgbm that predates `gbm_bo_create_with_modifiers2`.
26//!
27//! [`GbmDevice::from_fd`] takes any DRM descriptor. With the default
28//! `drmkit-core` feature off, that is the only way in, and this crate needs
29//! nothing of drmkit's.
30
31mod buffer;
32mod device;
33mod ffi;
34mod surface;
35
36#[cfg(test)]
37mod tests;
38
39pub use buffer::{GbmBuffer, MapAccess};
40pub use device::GbmDevice;
41pub use ffi::HIDE_ENV;
42pub use surface::GbmSurface;
43
44/// What went wrong allocating or exporting.
45#[derive(Debug, thiserror::Error)]
46#[non_exhaustive]
47pub enum GbmError {
48    /// The device could not be opened as a GBM device.
49    ///
50    /// Either libgbm could not be loaded -- not installed, or missing an
51    /// entry point this crate cannot do without -- or it would not open the
52    /// descriptor, which every DRM node that can allocate anything allows, so
53    /// in practice that means it is not a DRM node at all. The string says
54    /// which.
55    #[error("not a GBM-capable device: {0}")]
56    NotGbmCapable(String),
57
58    /// The driver refused the allocation.
59    ///
60    /// Usually the format, the modifier set, or the usage flags: a driver
61    /// advertises what it can scan out through `IN_FORMATS`, and asking for
62    /// anything else fails here rather than at commit time. Also returned when
63    /// a buffer cannot be exported as a dma-buf.
64    #[error("gbm allocation failed: {0}")]
65    Allocation(String),
66
67    /// The DRM descriptor could not be duplicated.
68    #[error("gbm operation failed: {0}")]
69    Io(#[from] rustix::io::Errno),
70}