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.

Edit on GitHub

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:

SymbolBackendDefault
LV_WAYLAND_USE_SHMShared memory via wl_shmon, except with a GPU draw unit
LV_WAYLAND_USE_DMABUFSoftware frames presented as linear DMA-BUFsoff
LV_WAYLAND_USE_EGLOpenGL ES via EGLoff; on with a GPU draw unit
LV_WAYLAND_USE_G2DNXP i.MX G2D acceleratoroff

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:

BackendExtra libraries
LV_WAYLAND_USE_EGLwayland-egl
LV_WAYLAND_USE_G2Dg2d, libdrm
LV_WAYLAND_USE_DMABUFlibdrm, 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:

  1. G2D
  2. DMA-BUF
  3. EGL
  4. 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

EnableResult
SHMThe default. Works on any compositor, no hardware requirements.
SHM + DMA-BUFSoftware 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 + G2DHardware blits and rotation on i.MX parts, shared memory elsewhere or when DMA-BUF is unavailable.
SHM + EGLGPU 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.
EGLRequired when LV_USE_DRAW_OPENGLES or LV_USE_DRAW_NANOVG is enabled. No fallback is possible.

Other options

SymbolDefaultEffect
LV_WAYLAND_DIRECT_EXITonDeinitialize 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:

DeviceWayland sourceGetter
KEYPADkeyboardlv_wayland_get_keyboard
POINTERtouchlv_wayland_get_touchscreen
POINTERpointerlv_wayland_get_pointer
ENCODERpointer 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

FunctionPurpose
lv_wayland_window_set_fullscreenEnter or leave fullscreen
lv_wayland_window_set_maximizedMaximize or restore
lv_wayland_window_set_minimizedMinimize
lv_wayland_window_closeClose the window
lv_wayland_window_is_openTest 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:

FunctionPurpose
lv_wayland_get_output_countNumber of outputs the compositor advertises
lv_wayland_get_output_nameConnector name of an output, e.g. "HDMI-A-1"
lv_wayland_get_output_sizeSize of an output in pixels
lv_wayland_get_display_sizeLook 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

CapabilityDMA-BUFEGLG2DSHM
RotationSoftware (folded into the flush copy)Hardware (GPU)Hardware (G2D)Software (extra full-frame copy)
Runtime resolution changeYesYesYesYes
Runtime color format changeYesYesYesYes
Color formatsRGB565, XRGB8888, ARGB8888RGB565 or ARGB8888, from LV_COLOR_FORMAT_DEFAULTRGB565, XRGB8888, ARGB8888RGB565, XRGB8888, ARGB8888
Multiple displays / windowsYesYesYesYes
Hardware accelerationNone — presentation onlyOpenGL ESNXP G2DNone
Render modeDirect — fixedFull with NanoVG, otherwise Direct — fixedDirect — fixedDirect — fixed
InputBuilt in — keyboard, pointer, touch, encoder per windowBuilt inBuilt inBuilt 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:

sh
WAYLAND_DEBUG=1 ./path/to/executable > /tmp/debug 2>&1

Attach /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

On this page