DRM¶
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¶
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:
sudo apt-get install libdrm-dev
Configure DRM Driver¶
Enable the DRM driver support in
lv_conf.h
, by CMake compiler define, or by KConfig:#define LV_USE_LINUX_DRM 1
Link against
libdrm
when building.
Basic Usage¶
#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¶
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 codding the device card path, you can ask LVGL to find a connected one for you using lv_linux_drm_find_device_path()
.
It will return the first connected card it can find.
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¶
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.
Enable the following option in your
lv_conf.h
(or via Kconfig/CMake):
#define LV_USE_LINUX_DRM_GBM_BUFFERS 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¶
The DRM driver can also be combined with EGL for hardware-accelerated rendering via EGL/GLES.
To enable this, set the following options in your lv_conf.h
(or via Kconfig/CMake):
#define LV_USE_LINUX_DRM 1
#define LV_USE_LINUX_DRM_GBM_BUFFERS 1
#define LV_LINUX_DRM_USE_EGL 1
#define LV_USE_OPENGLES 1
#define LV_USE_DRAW_OPENGLES 1 /* optional but recommended for performance */
When LV_LINUX_DRM_USE_EGL
is enabled, the DRM driver will automatically initialize EGL.
No special setup is required beyond the basic DRM initialization shown in Basic Usage.
For a detailed overview of EGL usage and configuration, see EGL.
Selecting Display Mode¶
Note
Custom mode selection is currently only supported when using DRM with EGL
(LV_LINUX_DRM_USE_EGL
enabled). When using DRM without EGL, the driver
will always use the preferred display mode.
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¶
To implement custom mode selection logic, define a callback function and register it with lv_linux_drm_set_mode_cb()
:
#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¶
The following functions are available to query mode properties:
lv_linux_drm_mode_get_horizontal_resolution()
- Get width in pixelslv_linux_drm_mode_get_vertical_resolution()
- Get height in pixelslv_linux_drm_mode_get_refresh_rate()
- Get refresh rate in Hzlv_linux_drm_mode_is_preferred()
- Check if mode is the display's preferred/native mode
Example: Selecting Preferred Mode¶
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¶
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¶
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
lv_linux_drm_set_mode_cb()
withNULL
as the callback.