Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Smithay/drm-rs/llms.txt

Use this file to discover all available pages before exploring further.

The drm::Device trait is the foundational building block of drm-rs. Any type that wraps a DRM file descriptor and implements the standard AsFd trait can implement Device — all of its methods have default implementations that delegate directly to the appropriate ioctl calls via the drm-ffi crate. No extra state is required.

Minimal Implementation

Because every method has a default implementation, implementing the trait only requires satisfying the AsFd bound. Opening the device node with read and write permissions is sufficient for most operations.
use drm::Device;
use std::fs::{File, OpenOptions};
use std::os::unix::io::{AsFd, BorrowedFd};

struct Card(File);

impl AsFd for Card {
    fn as_fd(&self) -> BorrowedFd<'_> {
        self.0.as_fd()
    }
}

impl Device for Card {}

impl Card {
    fn open() -> Self {
        let mut options = OpenOptions::new();
        options.read(true);
        options.write(true);
        Card(options.open("/dev/dri/card0").unwrap())
    }
}
drm::control::Device extends this trait with full KMS modesetting capabilities — CRTCs, connectors, planes, framebuffers, and atomic commits. See the control::Device reference for details.

Methods

acquire_master_lock

fn acquire_master_lock(&self) -> io::Result<()>
Acquires the DRM Master lock for this process. The DRM Master is required for all modesetting operations on a primary node (/dev/dri/card*). Privileges: The calling process must have CAP_SYS_ADMIN (typically root) or already be the session’s DRM master. Most display servers acquire this automatically when they open the primary device node. Notes: When the primary device node is opened by a session manager (e.g. logind), the lock is usually handed to the process automatically. This method is needed only if you need to re-acquire after explicitly releasing the lock, or in setuid/privileged helper scenarios.
card.acquire_master_lock().expect("failed to acquire DRM master");

release_master_lock

fn release_master_lock(&self) -> io::Result<()>
Releases the DRM Master lock so that another process can acquire it. This is useful for cooperative handoff between a display server and a GPU-intensive client, or when implementing a compositor that suspends itself.
card.release_master_lock().expect("failed to release DRM master");

set_client_capability

fn set_client_capability(&self, cap: ClientCapability, enable: bool) -> io::Result<()>
Enables or disables an optional feature for the calling process. Client capabilities are per-process and per-file-descriptor — they do not affect other processes or other open file descriptors. This method must be called before using the features gated behind each capability. For example, Atomic modesetting requires enabling UniversalPlanes first, then Atomic.
ParameterTypeDescription
capClientCapabilityThe capability to enable or disable
enablebooltrue to enable, false to disable
Key capabilities:
  • ClientCapability::UniversalPlanes — exposes all plane types (overlay, cursor) beyond the default primary planes. Required for most KMS usage.
  • ClientCapability::Atomic — enables the atomic modesetting API. Requires UniversalPlanes to be set first.
  • ClientCapability::AspectRatio — includes aspect ratio data in mode information.
  • ClientCapability::WritebackConnectors — exposes writeback connectors for render-to-memory. Requires Atomic.
  • ClientCapability::CursorPlaneHotspot — tells the driver that the client handles cursor hotspot positioning correctly (needed for para-virtualised hardware). Requires Atomic.
// Enable atomic modesetting (the standard sequence)
card.set_client_capability(drm::ClientCapability::UniversalPlanes, true)
    .expect("UniversalPlanes not supported");
card.set_client_capability(drm::ClientCapability::Atomic, true)
    .expect("Atomic modesetting not supported");
See Capabilities for the full ClientCapability reference.

get_driver_capability

fn get_driver_capability(&self, cap: DriverCapability) -> io::Result<u64>
Returns the current value of a driver capability. A return value of 0 indicates that the capability is not supported or not enabled. Non-zero values are capability-specific — for boolean capabilities 1 means supported, while capabilities like CursorWidth and CursorHeight return the actual pixel dimension.
ParameterTypeDescription
capDriverCapabilityThe capability to query
Returns: io::Result<u64> — the capability value on success.
let cursor_w = card.get_driver_capability(drm::DriverCapability::CursorWidth).unwrap();
let cursor_h = card.get_driver_capability(drm::DriverCapability::CursorHeight).unwrap();
println!("Max cursor size: {}×{}", cursor_w, cursor_h);
See Capabilities for the full DriverCapability reference.

get_driver

fn get_driver(&self) -> io::Result<Driver>
Returns a Driver struct describing the kernel DRM driver that is powering this device. The struct exposes the driver name, version tuple, publication date, and a human-readable description.
let driver = card.get_driver().unwrap();
println!("Driver: {:?} v{}.{}.{}",
    driver.name(),
    driver.version.0,
    driver.version.1,
    driver.version.2,
);
Returns: io::Result<Driver>. May return EFAULT if the kernel cannot copy the version strings into userspace. See Driver for the full struct reference.

get_bus_id

fn get_bus_id(&self) -> io::Result<OsString>
Returns the PCI bus ID string that the kernel associates with this device (for example "PCI:0000:00:02.0"). This can be used to correlate a DRM device node with a PCI device from /sys/bus/pci/devices/.
let bus_id = card.get_bus_id().unwrap();
println!("Bus ID: {:?}", bus_id);

authenticated

fn authenticated(&self) -> io::Result<bool>
Returns true if the current process’s file descriptor has been authenticated by the DRM master. On the master fd itself this always returns true. On a secondary fd it returns true only after the master has called authenticate_auth_token with a token produced by generate_auth_token.
if card.authenticated().unwrap() {
    println!("We are authenticated");
}

generate_auth_token (deprecated)

fn generate_auth_token(&self) -> io::Result<AuthToken>
Generates an AuthToken for the current file descriptor. The token can be passed out-of-band (e.g. via a Unix socket) to a DRM master process, which can then call authenticate_auth_token to grant access.
This authentication mechanism is deprecated. Opening a render node (/dev/dri/renderD*) is the modern, privilege-free alternative for unprivileged GPU access. Use generate_auth_token only when interfacing with legacy software that requires it.

authenticate_auth_token

fn authenticate_auth_token(&self, token: AuthToken) -> io::Result<()>
Called by the DRM master to authenticate a token that was generated by another process via generate_auth_token. Once authenticated, the other process gains unprivileged access to the device.
ParameterTypeDescription
tokenAuthTokenThe token received from the client process
// On the master side — token received over IPC
card.authenticate_auth_token(received_token)
    .expect("authentication failed");

wait_vblank

fn wait_vblank(
    &self,
    target_sequence: VblankWaitTarget,
    flags: VblankWaitFlags,
    high_crtc: u32,
    user_data: usize,
) -> io::Result<VblankWaitReply>
Blocks until a specific vblank sequence occurs, or schedules an asynchronous vblank event. This is the low-level vblank synchronisation primitive. For most use cases, page flip events via page_flip() are simpler.
ParameterTypeDescription
target_sequenceVblankWaitTargetAbsolute(n) or Relative(n) frame target
flagsVblankWaitFlagsModifier flags (event mode, next-on-miss)
high_crtcu32CRTC index for hardware with many outputs; usually 0
user_datausizeArbitrary value echoed back in the reply/event
Returns: io::Result<VblankWaitReply> containing the frame number and timestamp.
use drm::{VblankWaitTarget, VblankWaitFlags};

let reply = card.wait_vblank(
    VblankWaitTarget::Relative(1),
    VblankWaitFlags::empty(),
    0,
    0,
).unwrap();

println!("Vblank frame {}, time {:?}", reply.frame(), reply.time());
See Vblank for full documentation of the types.

Build docs developers (and LLMs) love