| Crates.io | easydrm |
| lib.rs | easydrm |
| version | 0.3.0 |
| created_at | 2025-11-10 21:52:20.353395+00 |
| updated_at | 2025-11-21 17:33:04.195099+00 |
| description | GLFW-inspired abstraction over DRM/KMS, GBM, and EGL/OpenGL that lets you build fullscreen Linux applications without a compositor (no X11, no Wayland). |
| homepage | |
| repository | https://github.com/hyprside/easydrm |
| max_upload_size | |
| id | 1926262 |
| size | 87,086 |
EasyDRM is a GLFW-inspired abstraction over DRM/KMS, GBM, and EGL/OpenGL that lets you build fullscreen Linux applications without a compositor (no X11, no Wayland). It owns the low-level plumbing—monitor discovery, events, page flips, fences, and atomic commits—so you can focus on your render loop while staying in total control of timing.
swap_buffers() walks the monitors you rendered and issues atomic commits in a predictable order.default_mode, requested_mode, and current_mode minimize expensive modesets and handle TTY focus loss.use easydrm::EasyDRM;
let mut easydrm = EasyDRM::init_empty().expect("GPU available");
loop {
for monitor in easydrm.monitors_mut() {
if monitor.can_render() { // 1) Draw only to ready monitors
monitor.make_current().unwrap();
render_frame(monitor);
}
}
easydrm.swap_buffers().unwrap(); // 2) Commit each monitor that was drawn
easydrm.poll_events().unwrap(); // 3) Block on DRM/input events
if easydrm.should_update() { // 4) Global logic tied to fastest refresh group
update_simulation();
}
}
EasyDRM feels like a game engine main loop: you control the cadence, EasyDRM keeps hardware state in sync.
poll_events() blocks on DRM, vblank, hotplug, and optional input fds via poll().can_render() turns true when the previous page flip + fence finished.make_current() activates the monitor’s GL/EGL context so you can issue draw calls.swap_buffers() iterates the monitors that were drawn and issues their atomic commits with the right fences.should_update() fires once every time the fastest refresh-rate group has committed, letting you run simulation at that cadence.| Field | Meaning | When it changes |
|---|---|---|
default_mode |
Optimal mode detected at init | Never after initialization |
requested_mode |
What the app wants (None = default) |
monitor.set_mode(...) |
current_mode |
What DRM is actually using | After successful atomic commit or clear_mode_state() |
A modeset runs when requested_mode != current_mode, covering first boot, TTY focus loss, and user-driven mode switches.
/dev/dri/card* (run as root or add the user to the video group).cargo build --release
⚠️ Run from a VT (outside X/Wayland) to avoid fighting the system compositor.
cargo run --example basic
The example prints detected monitors, animates a color wipe, and keeps running until you Ctrl+C.
EasyDRM::init_empty() – initialize without a custom per-monitor context.EasyDRM::init(|req| { /* create custom context using req.gl / req.get_proc_address */ }) – attach your own data per monitor.EasyDRM::monitors() / monitors_mut() – iterate over monitor handles.Monitor::make_current() – bind this monitor’s GL context and mark it as drawn.Monitor::gl() – access generated GLES2 bindings.Monitor::set_mode(Some(mode)) – request a specific DRM mode; None reverts to default_mode.EasyDRM::swap_buffers() – walks monitors that were drawn and calls their atomic swap path.EasyDRM::poll_events() – wait for page flips, hotplug, and optional input events.EasyDRM::should_update() – returns true once per cycle when the fastest refresh-rate group has committed.See examples/basic.rs and examples/custom_context.rs for end-to-end loops.
swap_buffers() call per loop orchestrates every commit that needs to happen.Monitor::swap_buffers() implementation