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.

drm::control::Device extends drm::Device with full Kernel Modesetting (KMS) capabilities. Any type that already implements drm::Device can also implement this trait with an empty impl body — all methods have default implementations backed by DRM ioctls.
use drm::control::Device as ControlDevice;

/// Assuming Card already implements drm::Device
impl ControlDevice for Card {}
The trait provides access to the complete KMS pipeline: resource enumeration, connector/CRTC/plane/encoder inspection, legacy and atomic modesetting, framebuffer management, property queries, dumb buffers, PRIME, gamma tables, sync objects, and DRM leasing.

Resource Enumeration

resource_handles

fn resource_handles(&self) -> io::Result<ResourceHandles>
Returns handles for all framebuffers, CRTCs, connectors, and encoders that this device controls. The returned ResourceHandles also reports the minimum and maximum supported framebuffer dimensions. ResourceHandles exposes the following accessors:
MethodReturn typeDescription
connectors()&[connector::Handle]All connector handles
encoders()&[encoder::Handle]All encoder handles
crtcs()&[crtc::Handle]All CRTC handles
framebuffers()&[framebuffer::Handle]All framebuffer handles
supported_fb_width()impl RangeBounds<u32>Minimum and maximum framebuffer width
supported_fb_height()impl RangeBounds<u32>Minimum and maximum framebuffer height
filter_crtcs(filter: CrtcListFilter)Vec<crtc::Handle>Filter CRTCs by encoder compatibility bitmask

plane_handles

fn plane_handles(&self) -> io::Result<Vec<plane::Handle>>
Returns handles for all hardware planes. Overlay and cursor planes are only visible after enabling ClientCapability::UniversalPlanes on the device.

Object Information

get_connector

fn get_connector(
    &self,
    handle: connector::Handle,
    force_probe: bool,
) -> io::Result<connector::Info>
Returns the current state of a connector. The force_probe flag instructs the kernel to perform a hardware-level probe, refreshing connection state, detected modes, and the EDID. Force-probing should be performed at startup and after receiving a hotplug udev event. It may be slow and cause momentary flickering; avoid it in steady-state render loops.

get_encoder

fn get_encoder(&self, handle: encoder::Handle) -> io::Result<encoder::Info>
Returns metadata about an encoder, including its kind, the CRTC it is currently attached to, and bitmasks indicating which CRTCs and clones it is compatible with.

get_crtc

fn get_crtc(&self, handle: crtc::Handle) -> io::Result<crtc::Info>
Returns the current state of a CRTC: position offset, the active Mode (or None if disabled), the currently displayed framebuffer, and the size of its gamma lookup table.

get_plane

fn get_plane(&self, handle: plane::Handle) -> io::Result<plane::Info>
Returns metadata about a plane: the CRTC and framebuffer it is currently attached to, the bitmask of compatible CRTCs, and the list of supported pixel format FourCC codes.

Modesetting

set_crtc

fn set_crtc(
    &self,
    handle: crtc::Handle,
    framebuffer: Option<framebuffer::Handle>,
    pos: (u32, u32),
    conns: &[connector::Handle],
    mode: Option<Mode>,
) -> io::Result<()>
Legacy (non-atomic) modeset. Attaches a framebuffer to a CRTC and drives the listed connectors at the specified mode. Passing None for framebuffer or mode disables the CRTC. Use atomic_commit for modern hardware and Wayland compositors.

set_plane

fn set_plane(
    &self,
    handle: plane::Handle,
    crtc: crtc::Handle,
    framebuffer: Option<framebuffer::Handle>,
    flags: u32,
    crtc_rect: (i32, i32, u32, u32),
    src_rect: (u32, u32, u32, u32),
) -> io::Result<()>
Configures a plane’s position and source crop. crtc_rect is (x, y, width, height) in screen coordinates. src_rect is (x, y, width, height) in the source framebuffer, specified in Q16.16 fixed-point units (multiply pixel values by 65536). Providing None for framebuffer clears the plane.

page_flip

fn page_flip(
    &self,
    handle: crtc::Handle,
    framebuffer: framebuffer::Handle,
    flags: PageFlipFlags,
    target_sequence: Option<PageFlipTarget>,
) -> io::Result<()>
Queues a framebuffer swap on the given CRTC. The swap is applied at the next vblank unless PageFlipFlags::ASYNC is set. When PageFlipFlags::EVENT is set, a PageFlipEvent is delivered via receive_events() once the flip completes. PageFlipTarget controls the specific vblank sequence:
VariantDescription
Absolute(n)Apply at absolute vblank sequence number n
Relative(n)Apply n vblanks from now

set_cursor (deprecated)

#[deprecated(note = "Usage of deprecated ioctl set_cursor: use a cursor plane instead")]
fn set_cursor<B>(&self, crtc: crtc::Handle, buffer: Option<&B>) -> io::Result<()>
where
    B: buffer::Buffer + ?Sized
Sets a hardware cursor image on the given CRTC. Passing None clears the cursor. Deprecated — use a cursor plane with atomic modesetting instead.

set_cursor2 (deprecated)

#[deprecated(note = "Usage of deprecated ioctl set_cursor2: use a cursor plane instead")]
fn set_cursor2<B>(
    &self,
    crtc: crtc::Handle,
    buffer: Option<&B>,
    hotspot: (i32, i32),
) -> io::Result<()>
where
    B: buffer::Buffer + ?Sized
Sets a hardware cursor image with a hotspot (x, y) that marks the click point. Passing None clears the cursor. Deprecated — use a cursor plane with atomic modesetting instead.

move_cursor (deprecated)

#[deprecated(note = "Usage of deprecated ioctl move_cursor: use a cursor plane instead")]
fn move_cursor(&self, crtc: crtc::Handle, pos: (i32, i32)) -> io::Result<()>
Moves the hardware cursor on a CRTC to the given (x, y) position without changing the cursor image. Deprecated — use a cursor plane with atomic modesetting instead.

atomic_commit

fn atomic_commit(
    &self,
    flags: AtomicCommitFlags,
    req: atomic::AtomicModeReq,
) -> io::Result<()>
Submits an atomic commit request. See AtomicModeReq for how to build the request and a full description of AtomicCommitFlags.

Framebuffer Management

add_framebuffer

fn add_framebuffer<B>(
    &self,
    buffer: &B,
    depth: u32,
    bpp: u32,
) -> io::Result<framebuffer::Handle>
where
    B: buffer::Buffer + ?Sized
Registers a GEM buffer as a scanout framebuffer. depth is the colour depth in bits (e.g. 24); bpp is the bits per pixel including padding (e.g. 32). Use this for single-plane packed formats such as XRGB8888.

add_planar_framebuffer

fn add_planar_framebuffer<B>(
    &self,
    planar_buffer: &B,
    flags: FbCmd2Flags,
) -> io::Result<framebuffer::Handle>
where
    B: buffer::PlanarBuffer + ?Sized
Registers a multi-plane or modifier-enabled framebuffer. Pass FbCmd2Flags::MODIFIERS to enable format modifier support for tiled/compressed formats. The buffer’s modifier() method must return a valid (non-Invalid) modifier when MODIFIERS is set.

get_framebuffer

fn get_framebuffer(&self, handle: framebuffer::Handle) -> io::Result<framebuffer::Info>
Returns legacy framebuffer metadata: size, pitch, bits-per-pixel, colour depth, and the underlying GEM buffer handle.

get_planar_framebuffer

fn get_planar_framebuffer(
    &self,
    handle: framebuffer::Handle,
) -> Result<framebuffer::PlanarInfo, GetPlanarFramebufferError>
Returns extended framebuffer metadata including pixel format (as DrmFourcc), per-plane pitches, offsets, buffer handles, and the optional format modifier. Returns GetPlanarFramebufferError::UnrecognizedFourcc if the kernel reports an unregistered FourCC code.

dirty_framebuffer

fn dirty_framebuffer(
    &self,
    handle: framebuffer::Handle,
    clips: &[ClipRect],
) -> io::Result<()>
Marks rectangular regions of a framebuffer as dirty. Used with shadow framebuffers or display controllers that require explicit cache-flush hints. ClipRect::new(x1, y1, x2, y2) constructs a dirty region.

destroy_framebuffer

fn destroy_framebuffer(&self, handle: framebuffer::Handle) -> io::Result<()>
Releases a framebuffer handle and frees the associated kernel resources. The underlying GEM buffer is not automatically freed.

Property Management

get_property

fn get_property(&self, handle: property::Handle) -> io::Result<property::Info>
Returns property metadata: name, value type, mutability, and whether it is atomic-only. See property for the full type reference.

set_property

fn set_property<T: ResourceHandle>(
    &self,
    handle: T,
    prop: property::Handle,
    value: property::RawValue,
) -> io::Result<()>
Sets a property on a KMS object using the legacy (non-atomic) property API. Prefer atomic_commit for modesetting-related properties.

create_property_blob

fn create_property_blob<T: ?Sized>(&self, data: &T) -> io::Result<property::Value<'static>>
Serialises an arbitrary data structure as a kernel-managed blob and returns a property::Value::Blob containing its blob ID. Blobs are the mechanism for passing structured data such as Mode timing structs to atomic commits.

get_property_blob

fn get_property_blob(&self, blob: u64) -> io::Result<Vec<u8>>
Retrieves the raw byte content of an existing property blob by its ID.

destroy_property_blob

fn destroy_property_blob(&self, blob: u64) -> io::Result<()>
Destroys a property blob and frees its kernel storage.

get_properties

fn get_properties<T: ResourceHandle>(&self, handle: T) -> io::Result<PropertyValueSet>
Returns the complete set of property handles and their current raw values for any KMS object (connector, CRTC, plane, or framebuffer). See PropertyValueSet for iteration methods.

get_modes

fn get_modes(&self, handle: connector::Handle) -> io::Result<Vec<Mode>>
Returns the list of Mode timing structures that the connector reports as supported. This does not force a kernel-side probe; call get_connector with force_probe: true first to refresh the list after hotplug.

Buffer Management

open_buffer

fn open_buffer(&self, name: buffer::Name) -> io::Result<buffer::Handle>
Opens a GEM buffer by its global Flink name, returning a process-local handle. Flink is a legacy inter-process sharing mechanism; prefer PRIME (prime_fd_to_buffer) for new code.

close_buffer

fn close_buffer(&self, handle: buffer::Handle) -> io::Result<()>
Closes a process-local GEM handle, decrementing the kernel reference count. Does not free the underlying buffer memory if other handles exist.

create_dumb_buffer

fn create_dumb_buffer(
    &self,
    size: (u32, u32),
    format: buffer::DrmFourcc,
    bpp: u32,
) -> io::Result<DumbBuffer>
Allocates a CPU-accessible dumb buffer through the generic DRM interface. Dumb buffers are backed by system memory, are not GPU-accelerated, and are suitable for simple rendering or cursor images. Returns a DumbBuffer describing the allocation.

map_dumb_buffer

fn map_dumb_buffer<'a>(&self, buffer: &'a mut DumbBuffer) -> io::Result<DumbMapping<'a>>
Memory-maps a dumb buffer into the current process’s address space. The returned DumbMapping<'a> dereferences to &mut [u8] and unmaps automatically on drop.

destroy_dumb_buffer

fn destroy_dumb_buffer(&self, buffer: DumbBuffer) -> io::Result<()>
Frees a dumb buffer and its system-memory backing store. Any active DumbMapping must be dropped first.

prime_fd_to_buffer

fn prime_fd_to_buffer(&self, fd: BorrowedFd<'_>) -> io::Result<buffer::Handle>
Imports a PRIME DMA-buf file descriptor into a process-local GEM buffer handle. PRIME is the standard cross-driver, cross-process buffer sharing mechanism.

buffer_to_prime_fd

fn buffer_to_prime_fd(&self, handle: buffer::Handle, flags: u32) -> io::Result<OwnedFd>
Exports a GEM buffer as a PRIME DMA-buf file descriptor that can be passed to other processes or DRM drivers.

Gamma Ramp

get_gamma

fn get_gamma(
    &self,
    crtc: crtc::Handle,
    red: &mut [u16],
    green: &mut [u16],
    blue: &mut [u16],
) -> io::Result<()>
Reads the currently programmed gamma lookup table for the given CRTC into the supplied slices. Each slice must be at least crtc_info.gamma_length() elements long.

set_gamma

fn set_gamma(
    &self,
    crtc: crtc::Handle,
    red: &[u16],
    green: &[u16],
    blue: &[u16],
) -> io::Result<()>
Programs a new gamma LUT for the given CRTC. Each slice must be at least crtc_info.gamma_length() elements long.

Sync Objects

DRM sync objects are fence binding points used to synchronise GPU work with page flips. See syncobj for full documentation of all sync object methods:
  • create_syncobj(signalled: bool) -> io::Result<syncobj::Handle>
  • destroy_syncobj(handle) -> io::Result<()>
  • syncobj_to_fd(handle, export_sync_file) -> io::Result<OwnedFd>
  • fd_to_syncobj(fd, import_sync_file) -> io::Result<syncobj::Handle>
  • syncobj_wait(handles, timeout_nsec, wait_all, wait_for_submit) -> io::Result<u32>
  • syncobj_reset(handles) -> io::Result<()>
  • syncobj_signal(handles) -> io::Result<()>
  • syncobj_timeline_wait(...), syncobj_timeline_query(...), syncobj_timeline_transfer(...), syncobj_timeline_signal(...), syncobj_eventfd(...)

DRM Leasing

DRM leasing allows a DRM master to delegate a subset of its KMS resources — CRTCs, connectors, and planes — to another process via a file descriptor. The lessee has full modesetting authority over the leased objects and cannot access resources outside the lease. Leasing is used by VR compositor frameworks (like VK_EXT_direct_mode_display), multi-seat configurations, and virtualisation.

create_lease

fn create_lease(
    &self,
    objects: &[RawResourceHandle],
    flags: u32,
) -> io::Result<(LeaseId, OwnedFd)>
Creates a new lease over the specified KMS object handles. Returns the LeaseId (a NonZeroU32) that identifies the lease and an OwnedFd that the lessee uses as its DRM device.

list_lessees

fn list_lessees(&self) -> io::Result<Vec<LeaseId>>
Returns the IDs of all active leases issued by this DRM master.

revoke_lease

fn revoke_lease(&self, lessee_id: LeaseId) -> io::Result<()>
Revokes a previously created lease. The lessee’s fd will start returning errors on modesetting calls.
get_lease is a free function (not a method), defined as drm::control::get_lease(lease: D) -> io::Result<LeaseResources>. It can be called on the lessee’s fd to enumerate which CRTCs, connectors, and planes were granted.

Events

receive_events

fn receive_events(&self) -> io::Result<Events>
where
    Self: Sized,
Reads pending DRM events from the device file descriptor. Returns an Events iterator over Event values. Call this after poll() or epoll() indicates the fd is readable.

Event

pub enum Event {
    Vblank(VblankEvent),
    PageFlip(PageFlipEvent),
    Unknown(Vec<u8>),
}

VblankEvent

Delivered when a vblank interrupt fires after wait_vblank is called.
FieldTypeDescription
frameu32Vblank sequence number
timeDurationTimestamp of the vblank
crtccrtc::HandleCRTC that generated the event
user_datausizeOpaque value passed to wait_vblank

PageFlipEvent

Delivered when a page flip completes (requires PageFlipFlags::EVENT).
FieldTypeDescription
frameu32Frame sequence number at flip completion
durationDurationTimestamp of the completed flip
crtccrtc::HandleCRTC that executed the page flip
// Typical event loop usage
let events = card.receive_events().unwrap();
for event in events {
    match event {
        drm::control::Event::PageFlip(ev) => {
            println!("Page flip complete on {:?}, frame {}", ev.crtc, ev.frame);
        }
        drm::control::Event::Vblank(ev) => {
            println!("Vblank on {:?} at {:?}", ev.crtc, ev.time);
        }
        drm::control::Event::Unknown(_) => {}
    }
}

Build docs developers (and LLMs) love