# DRM (/integration/embedded_linux/drivers/drm)



Overview [#overview]

The **DRM** (Direct Rendering Manager) display driver provides support for rendering
LVGL directly to Linux framebuffer devices through the DRM/KMS subsystem.\
It enables running LVGL without a windowing system such as X11 or Wayland,
making it suitable for embedded devices, single-board computers, and direct-to-display
applications.

The DRM driver interacts directly with the GPU or display controller through
`/dev/dri/cardX` nodes.

Getting Started with DRM [#getting-started-with-drm]

Prerequisites [#prerequisites]

The DRM driver requires:

* A Linux system with DRM/KMS support enabled in the kernel.
* Access to a DRM device node, typically `/dev/dri/card0`.
* Proper permissions to access DRM devices (e.g. running as root or adding the user
  to the `video` group).

On Debian/Ubuntu-based systems:

```bash title="bash" lineNumbers=1
sudo apt-get install libdrm-dev
```

Configure DRM Driver [#configure-drm-driver]

1. Enable the DRM driver support in `lv_conf.h`, by CMake compiler define, or by KConfig:

   .. code-block:: c

   \#define LV\_USE\_LINUX\_DRM   1
2. Link against `libdrm` when building.

Basic Usage [#basic-usage]

```c title=" " lineNumbers=1
#include "lvgl/lvgl.h"
#include "lvgl/demos/lv_demos.h"

int main(void)
{
    /* Initialize LVGL */
    lv_init();

    /* DRM device node */
    const char *device = "/dev/dri/card0";

    /* Create a DRM display */
    lv_display_t *disp = lv_linux_drm_create();

    /* Set DRM device file and connector */
    /* The 2nd argument is the DRM device path */
    /* The 3rd argument is the connector_id (-1 = auto-select first available) */
    lv_linux_drm_set_file(disp, device, -1);

    /* Create demo widgets */
    lv_demo_widgets();

    /* Handle LVGL tasks */
    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;
}
```

Notes [#notes]

* `connector_id` specifies which display output (HDMI, eDP, DP, etc.) should be used.\
  If `-1` is passed, the DRM driver will try to automatically pick the first available connector.
* DRM requires proper modesetting. By default, LVGL will select a preferred display mode.

In order to avoid hard coding the device card path, you can ask LVGL to find a connected one for you using <ApiLink name="lv_linux_drm_find_device_path" />.
It will return the first connected card it can find.

```c title=" " lineNumbers=1
lv_display_t * disp = lv_linux_drm_create();

/* Find the first connected card in /sys/class/drm */
char * device = lv_linux_drm_find_device_path();
lv_linux_drm_set_file(disp, device, -1);
/* Free the path pointer */
lv_free(device);
```

Using DRM with GBM [#using-drm-with-gbm]

The DRM driver can optionally use **GBM** (Generic Buffer Management) for buffer allocation.\
This allows the driver to use GPU-friendly buffer objects instead of simple dumb framebuffers.

1. Enable the following option in your `lv_conf.h` (or via Kconfig/CMake):

```c title=" " lineNumbers=1
#define LV_USE_LINUX_DRM_GBM_BUFFERS 1
```

1. Link against `libgbm` when building.

When this option is enabled:

* Buffers will be allocated using GBM.
* This can improve performance and compatibility on platforms where GBM is supported.

Using DRM with EGL [#using-drm-with-egl]

The DRM driver can also be combined with [EGL](/integration/embedded_linux/drivers/egl) for hardware-accelerated
rendering via EGL/GLES.

To enable this, set the following options in your `lv_conf.h` (or via Kconfig/CMake):

```c title=" " lineNumbers=1
#define LV_USE_LINUX_DRM             1
#define LV_USE_OPENGLES              1
#define LV_USE_DRAW_OPENGLES         1   /* optional but recommended for performance */
```

When <ApiLink name="LV_USE_OPENGLES" /> is enabled, the DRM driver will automatically initialize EGL.
No special setup is required beyond the basic DRM initialization shown in [Basic Usage](/integration/embedded_linux/drivers/drm).

For a detailed overview of EGL usage and configuration, see [EGL](/integration/embedded_linux/drivers/egl).

Selecting Display Mode [#selecting-display-mode]

<Callout type="info">
  Custom mode selection is currently only supported when using DRM with EGL
  (<ApiLink name="LV_USE_OPENGLES" /> enabled). When using DRM without EGL, the driver
  will always use the preferred display mode.
</Callout>

By default, the DRM driver automatically selects the preferred display mode for the connected display. However, you can customize this behavior by providing a mode selection callback.

Custom Mode Selection [#custom-mode-selection]

To implement custom mode selection logic, define a callback function and register it with <ApiLink name="lv_linux_drm_set_mode_cb" />:

```c title=" " lineNumbers=1
#include "lvgl/lvgl.h"

/* Custom mode selection callback */
size_t my_mode_selector(lv_display_t * disp, const lv_linux_drm_mode_t * modes, size_t mode_count)
{
    /* Example: Select the first 1920x1080@60Hz mode */
    for(size_t i = 0; i < mode_count; i++) {
        int32_t width = lv_linux_drm_mode_get_horizontal_resolution(&modes[i]);
        int32_t height = lv_linux_drm_mode_get_vertical_resolution(&modes[i]);
        int32_t refresh = lv_linux_drm_mode_get_refresh_rate(&modes[i]);

        if(width == 1920 && height == 1080 && refresh == 60) {
            return i;  /* Return the index of the selected mode */
        }
    }

    /* Fallback: return the first mode */
    return 0;
}

int main(void)
{
    lv_init();

    lv_display_t * disp = lv_linux_drm_create();

    /* Set custom mode selection callback */
    lv_linux_drm_set_mode_cb(disp, my_mode_selector);

    lv_linux_drm_set_file(disp, "/dev/dri/card0", -1);

    /* ... rest of your application ... */
}
```

The callback receives an array of available modes and must return the index of the desired mode.

Mode Information API [#mode-information-api]

The following functions are available to query mode properties:

* <ApiLink name="lv_linux_drm_mode_get_horizontal_resolution" /> - Get width in pixels
* <ApiLink name="lv_linux_drm_mode_get_vertical_resolution" /> - Get height in pixels
* <ApiLink name="lv_linux_drm_mode_get_refresh_rate" /> - Get refresh rate in Hz
* <ApiLink name="lv_linux_drm_mode_is_preferred" /> - Check if mode is the display's preferred/native mode

Example: Selecting Preferred Mode [#example-selecting-preferred-mode]

```c title=" " lineNumbers=1
size_t select_preferred_mode(lv_display_t * disp, const lv_linux_drm_mode_t * modes, size_t mode_count)
{
    /* Find and select the preferred mode */
    for(size_t i = 0; i < mode_count; i++) {
        if(lv_linux_drm_mode_is_preferred(&modes[i])) {
            return i;
        }
    }

    /* If no preferred mode found, return the first mode */
    return 0;
}
```

Example: Selecting Highest Resolution [#example-selecting-highest-resolution]

```c title=" " lineNumbers=1
size_t select_highest_resolution(lv_display_t * disp, const lv_linux_drm_mode_t * modes, size_t mode_count)
{
    size_t best_index = 0;
    int32_t max_pixels = 0;

    for(size_t i = 0; i < mode_count; i++) {
        int32_t width = lv_linux_drm_mode_get_horizontal_resolution(&modes[i]);
        int32_t height = lv_linux_drm_mode_get_vertical_resolution(&modes[i]);
        int32_t pixels = width * height;

        if(pixels > max_pixels) {
            max_pixels = pixels;
            best_index = i;
        }
    }

    return best_index;
}
```

Notes [#notes-1]

* The mode selection callback is called before the display is initialized.
* If no callback is set, the driver uses the preferred mode by default.
* Ensure the callback always returns a valid index (0 to `mode_count - 1`).
* To restore default behavior, call <ApiLink name="lv_linux_drm_set_mode_cb" /> with `NULL` as the callback.
