DRM

The DRM display driver renders LVGL straight to a display through the Linux DRM/KMS subsystem, with no windowing system in between. It supports dumb buffers, GBM buffers and hardware-accelerated EGL rendering.

Edit on GitHub

Overview

The DRM (Direct Rendering Manager) display driver renders LVGL straight to a display through the Linux DRM/KMS subsystem, talking to the GPU or display controller through a /dev/dri/cardX node. No windowing system is involved, which makes it the recommended choice for production embedded targets: single-board computers, panels, and any direct-to-display application.

The driver offers three backends:

  1. Dumb buffers: software rendering into DRM/KMS dumb framebuffers
  2. GBM: (GPU-friendly DMA buffers)
  3. EGL (OpenGL ES rendering on the GPU).

Compared with the framebuffer driver, DRM gives you proper modesetting, atomic page flips, and a path to GPU acceleration.

Prerequisites

  • A kernel with DRM/KMS support.
  • A DRM device node, typically /dev/dri/card0.
  • Permission to open it, either run as root, or add the user to the video group.

Configuration

Enable LV_USE_LINUX_DRM, and set LV_COLOR_FORMAT_DEFAULT to LV_COLOR_FORMAT_XRGB8888 or LV_COLOR_FORMAT_RGB565.

Building

The driver always requires libdrm. The GBM and EGL backends additionally require libgbm.

LVGL's CMake integration resolves both. Make sure the required libraries are present on your system or in your sysroot.

See Dependency Management.

Selecting a rendering backend

Disable LV_LINUX_DRM_AUTO_BACKEND and set LV_LINUX_DRM_BACKEND to one of:

ValueBackend
LV_LINUX_DRM_BACKEND_FBDEVSoftware rendering into DRM/KMS dumb buffers
LV_LINUX_DRM_BACKEND_GBMBuffers allocated through Mesa GBM as DMA buffers
LV_LINUX_DRM_BACKEND_EGLHardware-accelerated rendering via OpenGL ES 2.0 and EGL

Turn off the legacy auto-backend first

LV_LINUX_DRM_AUTO_BACKEND infers the backend from LV_USE_OPENGLES, picking EGL when that is enabled and dumb buffers otherwise.

Set LV_LINUX_DRM_AUTO_BACKEND to 0 whenever you select a backend explicitly. Auto mode will be removed in LVGL v10.

For the GPU draw units that run on top of the EGL backend, see OpenGL Overview.

Usage

LVGL's linux port can be used to quickly get started with LVGL's DRM backend.

Create the display with lv_linux_drm_create, then bind it to a device node and connector with lv_linux_drm_set_file.

 
#include <lvgl/lvgl.h>
#include "lvgl/demos/lv_demos.h"

int main(void)
{
    lv_init();

    lv_display_t * disp = lv_linux_drm_create();

    /* 2nd argument: DRM device path
     * 3rd argument: connector id, or -1 to auto-select the first available one */
    lv_linux_drm_set_file(disp, "/dev/dri/card0", -1);

    lv_demo_widgets();

    while(1) {
        uint32_t time_until_next = lv_timer_handler();
        if(time_until_next == LV_NO_TIMER_READY) {
            time_until_next = LV_DEF_REFR_PERIOD;
        }
        lv_delay_ms(time_until_next);
    }

    return 0;
}

The connector id selects which output (HDMI, eDP, DP, ...) to drive. Passing -1 picks the first available one.

Rather than hard-coding the card path, ask LVGL to find a connected one with lv_linux_drm_find_device_path. It scans /sys/class/drm and returns the first connected card; free the result with lv_free.

 
lv_display_t * disp = lv_linux_drm_create();

char * device = lv_linux_drm_find_device_path();
lv_linux_drm_set_file(disp, device, -1);
lv_free(device);

Selecting a Display Mode

By default the driver uses the display's preferred mode. To choose differently, register a callback with lv_linux_drm_set_mode_cb before calling lv_linux_drm_set_file. It receives every mode the connector reports and returns the index of the one to use.

Custom mode selection only takes effect with the EGL backend. With dumb buffers or GBM the driver always uses the preferred mode.

 
static size_t my_mode_selector(lv_display_t * disp, const lv_linux_drm_mode_t * modes, size_t mode_count)
{
    /* Pick 1920x1080@60Hz if the display offers it */
    for(size_t i = 0; i < mode_count; i++) {
        if(lv_linux_drm_mode_get_horizontal_resolution(&modes[i]) == 1920 &&
           lv_linux_drm_mode_get_vertical_resolution(&modes[i]) == 1080 &&
           lv_linux_drm_mode_get_refresh_rate(&modes[i]) == 60) {
            return i;
        }
    }

    /* Fall back to the first mode */
    return 0;
}

int main(void)
{
    lv_init();

    lv_display_t * disp = lv_linux_drm_create();
    lv_linux_drm_set_mode_cb(disp, my_mode_selector);
    lv_linux_drm_set_file(disp, "/dev/dri/card0", -1);

    /* ... */
}

These functions query a mode:

FunctionReturns
lv_linux_drm_mode_get_horizontal_resolutionWidth in pixels
lv_linux_drm_mode_get_vertical_resolutionHeight in pixels
lv_linux_drm_mode_get_refresh_rateRefresh rate in Hz
lv_linux_drm_mode_is_preferredWhether this is the display's native mode
lv_linux_drm_mode_get_rawThe underlying mode info, for anything not covered above

The callback must always return a valid index in 0 .. mode_count - 1. Passing NULL to lv_linux_drm_set_mode_cb restores the default behaviour.

Support

CapabilityDumb buffersGBMEGL
RotationNoneNoneHardware (GPU)
Runtime resolution changeNoNoYes
Runtime color format changeNoNoNo
Color formatsRGB565 or XRGB8888, from LV_COLOR_FORMAT_DEFAULTXRGB8888, from LV_COLOR_FORMAT_DEFAULTRGB565 or ARGB8888, from LV_COLOR_FORMAT_DEFAULT
Multiple displays / windowsOne display per DRM deviceOne display per DRM deviceOne display per DRM device
Hardware accelerationNoneBuffer allocation onlyOpenGL ES
Render modeDirectDirectFull with NanoVG, otherwise Direct
InputNone built in. Pair with evdev or libinputSameSame
Custom mode selectionNoNoYes

See Also

Last updated on

On this page