Fundamentals 19 min read

Understanding DRM: From Application‑Level Programs to Kernel Drivers

This article explains the Linux DRM graphics framework, its three main components (libdrm, KMS, GEM), the essential elements for display pipelines, and provides step‑by‑step example programs for single‑buffer, double‑buffer, page‑flip, and plane‑based rendering, including complete source code and execution notes.

Linux Code Review Hub
Linux Code Review Hub
Linux Code Review Hub
Understanding DRM: From Application‑Level Programs to Kernel Drivers

DRM Overview

DRM (Direct Rendering Manager) is the mainstream Linux graphics display framework. Compared with the older FB architecture, DRM natively supports multi‑layer composition, VSYNC, DMA‑BUF, asynchronous updates, fence mechanisms, and provides unified management of GPU and display drivers.

Core Modules

DRM can be divided into three parts:

libdrm : wraps low‑level IOCTL interfaces and offers a common API to upper layers.

KMS (Kernel Mode Setting): updates the screen and sets display parameters such as resolution, refresh rate, and power state.

GEM (Graphics Execution Manager): allocates and releases display buffers; it is the only part directly used by the GPU.

Basic Elements

Key DRM objects include:

KMS: CRTC, ENCODER, CONNECTOR, PLANE, FB, VBLANK, property.

GEM: DUMB, PRIME, fence.

Mastering these elements enables smooth DRM driver development.

Single‑Buffer DRM Application

A minimal DRM program demonstrates opening /dev/dri/card0, obtaining resources, creating a dumb buffer, mapping it, and displaying a white screen.

int main(int argc, char **argv) {
  /* open the drm device */
  open("/dev/dri/card0");

  /* get crtc/encoder/connector id */
  drmModeGetResources(...);
  drmModeGetConnector(...);

  /* create a dumb‑buffer */
  drmIoctl(DRM_IOCTL_MODE_CREATE_DUMB);

  /* bind the dumb‑buffer to an FB object */
  drmModeAddFB(...);

  /* map the dumb buffer for userspace drawing */
  drmIoctl(DRM_IOCTL_MODE_MAP_DUMB);
  mmap(...);

  /* start display */
  drmModeSetCrtc(crtc_id, fb_id, connector_id, mode);
}

The crucial call is drmModeSetCrtc() , which initializes the entire display pipeline and shows the framebuffer content.

Prerequisites for this code to run: DRM driver supports MODESET. DRM driver supports dumb‑buffer. At least one CRTC, one ENCODER, and one CONNECTOR are available. The CONNECTOR provides a valid display mode.

Double‑Buffer DRM Application

Extending the single‑buffer example, two buffers are created (red and blue). The program alternates between them by calling drmModeSetCrtc() after each user key press, demonstrating how double buffering avoids visible buffer updates.

int main(void) {
  ...
  while (1) {
    drmModeSetCrtc(fb0);
    ...
    drmModeSetCrtc(fb1);
    ...
  }
}

Repeated calls to drmModeSetCrtc() do not re‑initialize hardware as long as the display mode and pipeline connections remain unchanged.

Page‑Flip DRM Application

The drmModePageFlip() interface updates the screen only after a VSYNC event, preventing tearing. It requires the driver to support VBLANK events and uses drmHandleEvent() to wait for the event.

void my_page_flip_handler(...){
  drmModePageFlip(DRM_MODE_PAGE_FLIP_EVENT);
  ...
}

int main(void) {
  drmEventContext ev = {};
  ev.version = DRM_EVENT_CONTEXT_VERSION;
  ev.page_flip_handler = my_page_flip_handler;
  ...
  drmModePageFlip(DRM_MODE_PAGE_FLIP_EVENT);
  while (!terminate) {
    drmHandleEvent(fd, &ev);
  }
}
Note: drmModePageFlip() may be called only once per VSYNC cycle; additional calls within the same cycle return -EBUSY .

Plane‑Test DRM Application

The drmModeSetPlane() function allows displaying only a portion of a framebuffer. A plane is a hardware layer that moves data from a framebuffer to a CRTC. The example shows cropping, translation, and scaling by setting source and CRTC coordinates.

int main(void) {
  ...
  drmSetClientCap(DRM_CLIENT_CAP_UNIVERSAL_PLANES);
  drmModeGetPlaneResources();
  drmModeSetPlane(plane_id, crtc_id, fb_id, 0,
    crtc_x, crtc_y, crtc_w, crtc_h,
    src_x<<16, src_y<<16, src_w<<16, src_h<<16);
  ...
}

Before calling drmModeSetPlane(), the display pipeline must be initialized with drmModeSetCrtc(), otherwise the plane setting has no effect.

Planes can be Primary, Overlay, or Cursor. Modern hardware often blurs the line between Primary and Overlay planes, supporting various formats including RGB, YUV, and compressed FBC.

Important Notes

Ensure no other process occupies /dev/dri/card0 before running the examples; otherwise a Permission Denied error occurs.

The sample code omits extensive error handling for brevity.

Running the single‑buffer program shows a full‑screen white image that waits for a key press before exiting.

The double‑buffer program alternates between red and blue screens on each key press.

The page‑flip example switches between red and blue frames synchronized with VSYNC.

The plane‑test program crops a 320×320 rectangle from (100,150) in the framebuffer and displays it at (50,50) on the screen.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

GraphicsC++DRMDisplay
Linux Code Review Hub
Written by

Linux Code Review Hub

A professional Linux technology community and learning platform covering the kernel, memory management, process management, file system and I/O, performance tuning, device drivers, virtualization, and cloud computing.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.