Kernel Modesetting (KMS) is the part of DRM that controls display hardware. When you configure a monitor’s resolution, refresh rate, or which physical port it is connected to, you are using KMS. The word “modesetting” comes from the concept of a display mode — a specific combination of resolution, pixel clock, and sync timings that a display understands. Before KMS, this configuration happened entirely in userspace (typically the X server), which required direct hardware access and prevented multiple processes from safely sharing the display pipeline. KMS moved that responsibility into the kernel, so the kernel owns the hardware state, arbitrates access, and ensures clean handover between compositors. From a drm-rs perspective, KMS functionality is exposed through theDocumentation 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.
control::Device trait (found in drm::control), which extends the base drm::Device trait. Your device wrapper must implement both to use modesetting.
Why KMS Matters
KMS solves three problems that plagued earlier display server architectures:- Tear-free mode changes — The kernel can defer mode changes to a vblank boundary, preventing visible tearing when switching resolutions or refresh rates.
- VT switching — Because the kernel tracks hardware state, it can restore the display pipeline when you switch between virtual terminals without either session needing to reconfigure hardware from scratch.
- Multi-process safety — Multiple compositors can exist (though only one is DRM Master at a time), and the kernel ensures they don’t corrupt each other’s hardware state.
The Display Pipeline
Every frame that appears on a screen travels through a fixed pipeline of KMS objects. Understanding this pipeline is essential to using drm-rs effectively:Resource Types
Connector — control::connector
A connector represents a physical output port on the GPU or display controller. It corresponds directly to what you can physically plug a cable into: an HDMI port, a DisplayPort receptacle, a VGA socket, an eDP panel on a laptop. The connector::Interface enum lists all recognized output types:
State (one of Connected, Disconnected, or Unknown) and reports a list of Mode values that the attached display supports. You can enumerate connectors with device.resource_handles() and retrieve detailed information with device.get_connector(handle, force_probe).
force_probe flag asks the kernel to physically re-probe the connector (querying EDID from the display). This can be slow and may cause a brief flicker, so it should only be used on startup or in response to a hotplug event.
Encoder — control::encoder
An encoder is a piece of display controller hardware that converts the raw pixel stream coming out of a CRTC into a signal that a particular connector type can transmit. For example, a TMDS (Transition-Minimized Differential Signaling) encoder converts pixels into the electrical signals used by HDMI and DVI-D. A DAC (Digital-to-Analog Converter) encoder produces the analog signal used by VGA.
info.encoders()), and each encoder advertises which CRTCs can feed it (info.possible_crtcs()). When setting up a display pipeline you need to find a valid combination of CRTC → Encoder → Connector.
CRTC — control::crtc
CRTC stands for CRT Controller, a name inherited from the era of cathode-ray tube displays. Today it refers more generally to a scanout engine: a hardware block that reads pixel data from one or more planes and drives an encoder at a specific resolution and refresh rate. Each CRTC has at least one associated Primary Plane.
Mode carries all the timing information for a display configuration — resolution, pixel clock, horizontal and vertical sync parameters, and refresh rate. Modes come from the connector’s EDID data and can be queried with device.get_modes(connector_handle) or from connector::Info::modes().
Plane — control::plane
A plane is an attachment point for a framebuffer. Rather than the CRTC scanning out directly from a buffer, it scans from one or more planes that it owns. This indirection enables hardware compositing: the display controller can blend multiple planes together in fixed hardware, at zero CPU cost.
There are three plane types, defined in control::PlaneType:
| Type | Description |
|---|---|
| Primary | Every CRTC has exactly one primary plane. This is the main content layer. Attaching a framebuffer to a CRTC in legacy mode implicitly uses the primary plane. |
| Overlay | Additional content layers that can be positioned and scaled on top of (or behind) the primary plane using fast hardware compositing. |
| Cursor | A small plane optimized for displaying a mouse cursor. Hardware cursor planes avoid redrawing the entire framebuffer when the cursor moves. |
Framebuffer — control::framebuffer
A framebuffer wraps a GEM buffer and registers it with the KMS subsystem so it can be attached to a plane. The framebuffer holds metadata about the buffer’s dimensions, pixel format (as a DRM fourcc code), and pitch (bytes per row).
You create framebuffers with add_framebuffer (for single-plane, legacy formats) or add_planar_framebuffer (for YUV or tiled formats with modifiers). Framebuffers are per-process objects — they cannot be shared across open file descriptors.
Legacy vs. Atomic Modesetting
DRM supports two distinct APIs for committing display configuration changes. drm-rs exposes both.Legacy Modesetting
The legacy API, centered onset_crtc(), predates atomic modesetting. It configures one CRTC (and its connected outputs) at a time with a blocking call.
Atomic Modesetting
The atomic API,atomic_commit() with AtomicModeReq, treats the entire display pipeline as a property graph. Every KMS object (connector, CRTC, plane, framebuffer) exposes a set of properties, and an atomic commit changes any number of those properties at once — atomically. Either all changes are applied or none are.
AtomicCommitFlags control the commit behavior:
| Flag | Effect |
|---|---|
TEST_ONLY | Validate the request without applying changes. Use this to check feasibility. |
NONBLOCK | Return immediately rather than waiting for the next vblank. |
ALLOW_MODESET | Permit changes that require a full modeset (e.g., changing resolution). |
PAGE_FLIP_EVENT | Deliver a page-flip event on the DRM file descriptor when the flip completes. |
PAGE_FLIP_ASYNC | Request the page flip as soon as possible without waiting for vblank. |
Client Capabilities
Before using certain advanced features, you must declare your intent to the kernel by setting client capabilities withdevice.set_client_capability(). Two capabilities are particularly relevant for KMS:
UniversalPlanes, plane_handles() only returns primary planes. Without Atomic, atomic_commit() will fail.
Practical code examples for configuring a display using both the legacy and atomic APIs can be found in the guides section: see Legacy Modesetting and Atomic Modesetting.