Wayland
The Wayland driver renders LVGL into a Wayland surface and reads keyboard, pointer and touch input from the compositor. It supports shared-memory, DMA-BUF, OpenGL ES and NXP G2D rendering backends, and picks between the ones you compile in at runtime.
Overview
The Wayland driver renders LVGL into a Wayland surface and reads keyboard, pointer and touch input from the compositor. It suits production deployments, kiosk interfaces, control panels, and other embedded GUIs on systems that already run a Wayland compositor. Additionally it can be useful for development on a Linux desktop, as an alternative to the X11 and SDL drivers.
The driver offers four rendering backends: SHM (shared memory, the default), DMA-BUF, EGL (OpenGL ES) and G2D (NXP i.MX 2D accelerator). Which one produces the frames determines how they reach the compositor and whether that work lands on the CPU or on hardware; everything else about the driver stays the same.
You do not have to commit to one at build time. Compile in as many as make sense for your target and the driver probes them when it opens a window, taking the first one that works.
Configuration
Enable LV_USE_WAYLAND, and set LV_COLOR_FORMAT_DEFAULT to
LV_COLOR_FORMAT_XRGB8888 or LV_COLOR_FORMAT_RGB565.
Enabling the driver is also what pulls the Wayland client libraries into the build, LVGL's CMake
integration resolves wayland-client, wayland-cursor and xkbcommon for you, so there is nothing to link
by hand. None of them can be built from source by LVGL, so they must already exist on the system or in your
sysroot. See Dependency Management for how resolution works and how to steer
it.
The driver also needs Wayland protocol bindings generated by wayland-scanner, which LVGL's CMake
integration runs for you: xdg-shell always, and linux-dmabuf-v1 when a backend needs it. The protocol
XML is looked up under $SDKTARGETSYSROOT/$SYSROOT//usr/share/wayland-protocols.
Enabling rendering backends
Turn on every one you want compiled into the binary:
| Symbol | Backend | Default |
|---|---|---|
LV_WAYLAND_USE_SHM | Shared memory via wl_shm | on, except with a GPU draw unit |
LV_WAYLAND_USE_DMABUF | Software frames presented as linear DMA-BUFs | off |
LV_WAYLAND_USE_EGL | OpenGL ES via EGL | off; on with a GPU draw unit |
LV_WAYLAND_USE_G2D | NXP i.MX G2D accelerator | off |
At least one has to be enabled; the build fails otherwise. Enabling several is the interesting case, see Runtime backend selection for how the driver chooses between them.
Some backends require some extra libraries:
| Backend | Extra libraries |
|---|---|
LV_WAYLAND_USE_EGL | wayland-egl |
LV_WAYLAND_USE_G2D | g2d, libdrm |
LV_WAYLAND_USE_DMABUF | libdrm, libgbm |
A GPU draw unit leaves EGL as the only option
SHM and G2D hand LVGL a CPU buffer, which the LV_USE_DRAW_OPENGLES and
LV_USE_DRAW_NANOVG draw units cannot render into.
There is no fallback in this configuration, so if EGL cannot start, window creation fails.
Runtime backend selection
Backend selection happens in two steps.
At driver init, which the first lv_wayland_window_create call performs, every
compiled-in backend is initialized and gets to bind the compositor globals it needs. A backend that fails
here is dropped for the rest of the process and is not considered again.
At window creation the surviving backends are tried in a fixed order of preference:
- G2D
- DMA-BUF
- EGL
- SHM
The first one that can set up a display for that window owns it. If none can,
lv_wayland_window_create returns NULL.
The probe runs per window, meaning that you can have a window driven by EGL and another one by SHM, for instance.
EGL only supports one window
At this time, the EGL backend can only drive one window. The work to support multiple windows is in progress.
Combinations that make sense
| Enable | Result |
|---|---|
| SHM | The default. Works on any compositor, no hardware requirements. |
| SHM + DMA-BUF | Software rendering either way, but the compositor scans the frames out directly where DMA-BUF works and copies them out of shared memory where it does not. One binary for both. |
| SHM + G2D | Hardware blits and rotation on i.MX parts, shared memory elsewhere or when DMA-BUF is unavailable. |
| SHM + EGL | GPU rendering where the GPU stack is usable, shared memory where it is not. Under a software renderer this also pulls in DMA-BUF, which is tried ahead of EGL. |
| EGL | Required when LV_USE_DRAW_OPENGLES or LV_USE_DRAW_NANOVG is enabled. No fallback is possible. |
Other options
| Symbol | Default | Effect |
|---|---|---|
LV_WAYLAND_DIRECT_EXIT | on | Deinitialize LVGL and exit once the last window closes. Turn it off to handle window closure yourself. |
Usage
lv_wayland_window_create opens a window and returns its display
#define H_RES 800
#define V_RES 480
lv_display_t * disp = lv_wayland_window_create(H_RES, V_RES, "Window Title", NULL);
if(disp == NULL) {
/* No enabled backend could set up a display */
}Call it again to open more windows; each gets its own display and its own set of input devices.
Input devices
Each window registers four input devices, wired to the corresponding Wayland events:
| Device | Wayland source | Getter |
|---|---|---|
| KEYPAD | keyboard | lv_wayland_get_keyboard |
| POINTER | touch | lv_wayland_get_touchscreen |
| POINTER | pointer | lv_wayland_get_pointer |
| ENCODER | pointer axis (scroll) | lv_wayland_get_pointeraxis |
Check the display before querying input devices
The getters return NULL if called before the display is fully initialised. Always check that the display
returned by lv_wayland_window_create is non-NULL first.
To enable keyboard and encoder navigation, put the relevant devices in a group:
/* Create a group and set it as default */
lv_group_t * g = lv_group_create();
lv_group_set_default(g);
/* Assign keyboard and encoder to the group */
lv_indev_set_group(lv_wayland_get_keyboard(disp), g);
lv_indev_set_group(lv_wayland_get_pointeraxis(disp), g);Once a group is the default, every focusable widget created afterwards joins it automatically, so arrow keys and encoder rotation move focus and Enter activates.
Window state
| Function | Purpose |
|---|---|
lv_wayland_window_set_fullscreen | Enter or leave fullscreen |
lv_wayland_window_set_maximized | Maximize or restore |
lv_wayland_window_set_minimized | Minimize |
lv_wayland_window_close | Close the window |
lv_wayland_window_is_open | Test whether it is still open |
With multiple physical displays, assign the window to one before going fullscreen so it appears where you want it:
/* Assign to physical display 0 and go fullscreen there */
lv_wayland_set_physical_display(disp, 0);
lv_wayland_window_set_fullscreen(disp, true);LV_WAYLAND_PHYSICAL_DISPLAY_ANY can be used to restore the default behaviour.
lv_wayland_set_physical_display(disp, LV_WAYLAND_PHYSICAL_DISPLAY_ANY);Physical outputs
To target a specific physical output, look it up by its connector name:
| Function | Purpose |
|---|---|
lv_wayland_get_output_count | Number of outputs the compositor advertises |
lv_wayland_get_output_name | Connector name of an output, e.g. "HDMI-A-1" |
lv_wayland_get_output_size | Size of an output in pixels |
lv_wayland_get_display_size | Look up an output by name and get its size |
/* Open a fullscreen window on the HDMI connector */
int32_t width, height;
int32_t output = lv_wayland_get_display_size("HDMI-A-1", &width, &height);
if(output >= 0) {
lv_display_t * disp = lv_wayland_window_create(width, height, "My window", NULL);
lv_wayland_set_physical_display(disp, output);
lv_wayland_window_set_fullscreen(disp, true);
}The names come from the xdg-output protocol, or from the wl_output v4 name event when the compositor doesn't support xdg-output.
If neither is available the name is empty and the lookup returns -1; the size falls back to the output's current mode.
Event loop
You can integrate LVGL into your own event loop, lv_wayland_get_fd gives you the
compositor's file descriptor to poll.
Rendering Backends
EGL
Renders through OpenGL ES 2.0 and EGL, and is the backend to use with LVGL's GPU draw units and 3D/glTF content. Rotation is done by the GPU at no extra copy.
Requires linking with wayland-egl and OpenGL ES 2.0 on the target.
G2D
Uses NXP's G2D 2D accelerator, available on i.MX 6 and i.MX 8 parts, for hardware-accelerated blits and
rotation, presenting frames through DMA-BUF. It needs the g2d library on the system and the
G2D draw unit enabled alongside the display path.
Requires linking with g2d and a compositor with zwp_linux_dmabuf_v1 support.
DMA-BUF
A software backend that changes how finished frames reach the compositor rather than how they are drawn.
LVGL renders on the CPU as usual; on flush the frame is copied into a linear DMA-BUF allocated through GBM
and posted with zwp_linux_dmabuf_v1. The compositor can scan that buffer out directly, which saves it the
copy out of shared memory that wl_shm costs, the win is on the compositor's side of the connection, not
in LVGL's rendering.
It needs no GPU API of any kind, only libdrm and libgbm to allocate the buffers, so it is available on
plenty of targets that cannot run the EGL backend. What it does need at runtime is a DRM primary node it
can open, which means the process must have permission to do so.
Rotation is handled in software, folded into that flush copy — unlike SHM there is no extra full-frame buffer and no additional pass.
Requires linking with libdrm and libgbm and a compositor with zwp_linux_dmabuf_v1 support.
SHM (default)
Renders into wl_shm shared-memory buffers.
No extra requirements.
Window Decorations
As of LVGL v9.5 the LV_WAYLAND_WINDOW_DECORATIONS option has been removed. Setting it produces a build
warning.
Title bars, borders and close buttons are now the application's responsibility. Build them from LVGL widgets. For fullscreen and kiosk applications, you can simply omit them.
Support
| Capability | DMA-BUF | EGL | G2D | SHM |
|---|---|---|---|---|
| Rotation | Software (folded into the flush copy) | Hardware (GPU) | Hardware (G2D) | Software (extra full-frame copy) |
| Runtime resolution change | Yes | Yes | Yes | Yes |
| Runtime color format change | Yes | Yes | Yes | Yes |
| Color formats | RGB565, XRGB8888, ARGB8888 | RGB565 or ARGB8888, from LV_COLOR_FORMAT_DEFAULT | RGB565, XRGB8888, ARGB8888 | RGB565, XRGB8888, ARGB8888 |
| Multiple displays / windows | Yes | Yes | Yes | Yes |
| Hardware acceleration | None — presentation only | OpenGL ES | NXP G2D | None |
| Render mode | Direct — fixed | Full with NanoVG, otherwise Direct — fixed | Direct — fixed | Direct — fixed |
| Input | Built in — keyboard, pointer, touch, encoder per window | Built in | Built in | Built in |
Reporting Bugs
The Wayland driver is under active development; bug reports and feedback are welcome. Detailed issues help
most, enable LV_USE_LOG and capture both LVGL's log and the Wayland message stream:
WAYLAND_DEBUG=1 ./path/to/executable > /tmp/debug 2>&1Attach /tmp/debug to the issue. Reproduce the problem quickly as the log file grows very quickly.
Say which LV_WAYLAND_USE_* backends you enabled, and which one the log reports as having taken the display.
See Also
- lv_port_linux - reference project with a working Wayland build
- Dependency Management - how LVGL resolves and links the Wayland libraries
- OpenGL Overview - the GPU rendering path used by the EGL backend
- EGL - the EGL layer underneath the EGL backend
- X11 - alternative for X-based desktops
- DRM - alternative when there is no compositor at all
Last updated on
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.
X11
The X11 driver opens a window on an X11 desktop and reads mouse, mousewheel and keyboard input, mainly for simulating an LVGL application on a Linux development machine.