This quickstart walks you through everything you need to go from a blank Rust project to a working program that opens a DRM device, queries the loaded GPU driver, and lists every connected display along with its supported video modes. By the end you will have a solid foundation for building Wayland compositors, display managers, kiosk applications, or any other software that needs direct access to Linux graphics hardware.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.
That single line is all you need for most use cases. The
drm crate re-exports everything required for device access and KMS modesetting. Run cargo build to download and compile the crate before moving on.drm-rs does not open device files for you. Instead, you provide any type that implements the standard
AsFd trait. The simplest approach is a thin newtype around std::fs::File:use std::fs::File;
use std::os::unix::io::{AsFd, BorrowedFd};
pub struct Card(File);
impl AsFd for Card {
fn as_fd(&self) -> BorrowedFd<'_> {
self.0.as_fd()
}
}
impl Card {
pub fn open(path: &str) -> Self {
let mut options = std::fs::OpenOptions::new();
options.read(true);
options.write(true);
Card(options.open(path).unwrap())
}
}
The
Card struct wraps a File that points to a DRM device node (e.g. /dev/dri/card0). Both read and write access are required — the kernel rejects ioctls on read-only file descriptors.That single line gives your
Card type access to driver queries, master-lock management, vblank waits, and capability inspection.fn main() {
let gpu = Card::open("/dev/dri/card0");
let driver = gpu.get_driver().unwrap();
println!("Driver name: {:?}", driver.name());
println!("Driver date: {:?}", driver.date());
println!("Driver desc: {:?}", driver.description());
println!("Driver version: {:?}", driver.version);
}
Driver name: "i915"
Driver date: "20080730"
Driver desc: "Intel Graphics"
Driver version: (1, 6, 0)
Now call
resource_handles() to get a snapshot of all modesetting objects, then iterate over the connectors and print their state and available modes:use drm::control::Device as ControlDevice;
fn main() {
let card = Card::open("/dev/dri/card0");
let resources = card.resource_handles().unwrap();
for &connector_handle in resources.connectors() {
let info = card.get_connector(connector_handle, false).unwrap();
println!(
"Connector {:?}-{}: {:?}",
info.interface(),
info.interface_id(),
info.state()
);
if info.state() == drm::control::connector::State::Connected {
println!(" Modes:");
for mode in info.modes() {
println!(" {:?}", mode);
}
}
}
}
Your process needs read and write access to
/dev/dri/card0. On most Linux distributions the device is owned by the video group — add your user to that group with sudo usermod -aG video $USER and log out/in. Alternatively, run the binary with sudo during development. Without the correct permissions, open() will panic and ioctl calls will return EACCES.Full Working Example
Putting all the steps together into a single self-contained file:src/main.rs in a project that has drm = "0.15" in its Cargo.toml, then run: