From 63a714b1aa9afff2cb15d7b8fe96c07f9b0dd60d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Costa?= Date: Wed, 5 Aug 2026 10:00:14 +0200 Subject: [PATCH] docs(linux): standardize and update embedded linux docs --- .../embedded_linux/draw_units/draw_nanovg.mdx | 133 +++++---- .../embedded_linux/draw_units/draw_opengl.mdx | 65 ++--- .../embedded_linux/draw_units/draw_sdl.mdx | 56 ++-- .../embedded_linux/drivers/X11.mdx | 152 +++++----- .../embedded_linux/drivers/drm.mdx | 272 +++++++----------- .../embedded_linux/drivers/egl.mdx | 56 ++-- .../embedded_linux/drivers/evdev.mdx | 130 ++++++--- .../embedded_linux/drivers/fbdev.mdx | 117 +++++--- .../embedded_linux/drivers/glfw.mdx | 244 +++++++--------- .../embedded_linux/drivers/index.mdx | 78 +++++ .../embedded_linux/drivers/libinput.mdx | 132 ++++++--- .../embedded_linux/drivers/meta.json | 6 +- .../embedded_linux/drivers/opengl_driver.mdx | 174 ++++++----- .../embedded_linux/drivers/wayland.mdx | 2 +- docs/src/integration/embedded_linux/index.mdx | 45 ++- .../src/integration/embedded_linux/opengl.mdx | 79 ++--- 16 files changed, 981 insertions(+), 760 deletions(-) diff --git a/docs/src/integration/embedded_linux/draw_units/draw_nanovg.mdx b/docs/src/integration/embedded_linux/draw_units/draw_nanovg.mdx index ef1140d219..d5ea966d2a 100644 --- a/docs/src/integration/embedded_linux/draw_units/draw_nanovg.mdx +++ b/docs/src/integration/embedded_linux/draw_units/draw_nanovg.mdx @@ -1,92 +1,107 @@ --- title: NanoVG Draw Unit -description: "NanoVG is a lightweight, antialiased 2D vector graphics library built on top of OpenGL/OpenGL ES. The NanoVG draw unit integrates NanoVG as a hardware-accelerated rendering backend for LVGL, provide..." +description: "The NanoVG draw unit renders LVGL on the GPU through NanoVG, a lightweight antialiased 2D vector graphics library built on OpenGL ES. It is the recommended GPU renderer on Linux." --- -## Introduction +## Overview -NanoVG is a lightweight, antialiased 2D vector graphics library built on top of OpenGL/OpenGL ES. -The NanoVG draw unit integrates NanoVG as a hardware-accelerated rendering backend for LVGL, -providing GPU-accelerated drawing for all standard LVGL widgets and graphics primitives. +NanoVG is a lightweight, antialiased 2D vector graphics library built on OpenGL / OpenGL ES. The NanoVG draw +unit uses it as LVGL's renderer, so widgets and primitives are drawn by the GPU instead of the CPU. -Unlike the software renderer, NanoVG leverages the GPU for: +It is the **recommended** GPU renderer on Linux: compared with the +[OpenGL ES draw unit](/integration/embedded_linux/draw_units/draw_opengl) it makes better use of the GPU and +covers more LVGL features. Where the software renderer rasterizes every pixel on the CPU, NanoVG gives you: - Antialiased path rendering (rectangles, arcs, lines, triangles) -- Hardware-accelerated image compositing with rotation and scaling -- Efficient text rendering with font texture caching +- Image compositing with rotation and scaling +- Text rendering with a font texture atlas - Box shadows and gradients -- Vector graphics support +- Vector graphics, and 3D rendering -## Requirements +### Requirements -- OpenGL 2.0+ / OpenGL ES 2.0+ / OpenGL ES 3.0+ -- An initialized OpenGL context (via GLFW, EGL, or custom setup) -- Stencil buffer support (8-bit recommended) +- OpenGL 2.0+, OpenGL ES 2.0+, or OpenGL ES 3.0+ +- An OpenGL context, created by one of the display drivers listed in + [OpenGL Overview](/integration/embedded_linux/opengl) or by your own code +- A config with an 8-bit stencil buffer. LVGL's EGL backends require stencil 8 and 4× multisampling when + choosing a config for NanoVG, so a config lacking them will not be selected. ## Configuration -Enable the NanoVG draw unit in `lv_conf.h`: +Enable . -```c -/* Enable NanoVG library */ -#define LV_USE_NANOVG 1 +### Options -/* Enable NanoVG draw unit */ -#define LV_USE_DRAW_NANOVG 1 +| Symbol | Default | Meaning | +|---|---|---| +| `LV_NANOVG_BACKEND` | `LV_NANOVG_BACKEND_GLES2` | Which shader flavour to compile. Must match the context the display driver creates. | +| `LV_NANOVG_IMAGE_CACHE_CNT` | `128` | Number of decoded images kept as GPU textures. | +| `LV_NANOVG_LETTER_CACHE_CNT` | `512` | Number of rendered glyphs kept for text drawing. | -/* Select OpenGL backend (choose one): - * - LV_NANOVG_BACKEND_GL2: OpenGL 2.0 - * - LV_NANOVG_BACKEND_GL3: OpenGL 3.0+ - * - LV_NANOVG_BACKEND_GLES2: OpenGL ES 2.0 - * - LV_NANOVG_BACKEND_GLES3: OpenGL ES 3.0+ - */ -#define LV_NANOVG_BACKEND LV_NANOVG_BACKEND_GLES2 +`LV_NANOVG_BACKEND` accepts: -/* Optional: Adjust cache sizes */ -#define LV_NANOVG_IMAGE_CACHE_CNT 32 /* Image texture cache entries */ -#define LV_NANOVG_FBO_CACHE_CNT 8 /* Framebuffer object cache entries */ -``` +| Value | Context | +|---|---| +| `LV_NANOVG_BACKEND_GL2` | OpenGL 2.0 | +| `LV_NANOVG_BACKEND_GL3` | OpenGL 3.0+ | +| `LV_NANOVG_BACKEND_GLES2` | OpenGL ES 2.0 | +| `LV_NANOVG_BACKEND_GLES3` | OpenGL ES 3.0+ | + + +`LV_NANOVG_BACKEND` selects which shaders are compiled; it does not create or negotiate a context. Setting a +flavour the driver's context does not provide gives you shader compilation failures at run time, not a build +error. The EGL-based drivers request OpenGL ES 3 and fall back to ES 2, so `LV_NANOVG_BACKEND_GLES2` is the +safe default. + ## Supported Features -The NanoVG draw unit supports all standard LVGL drawing operations: - -| Feature | Description | -| --- | --- | -| Fill | Solid colors, gradients (linear/radial) | -| Border | Rounded rectangles with customizable width | -| Box Shadow | Hardware-accelerated shadow rendering | +| Feature | Notes | +|---|---| +| Fill | Solid colors, linear and radial gradients | +| Border | Rounded rectangles with configurable width | +| Box Shadow | Hardware-accelerated | | Images | Rotation, scaling, tiling, recoloring | -| Labels | Font rendering with texture atlas caching | -| Lines | Antialiased lines with configurable width | +| Labels | Font rendering with a texture atlas | +| Lines | Antialiased, configurable width | | Arcs | Antialiased arc segments | -| Triangles | Filled triangles | +| Triangles | Filled | | Masks | Rectangle masks for clipping | -| Layers | Off-screen rendering with FBO | -| Canvas | Direct drawing to canvas buffers | -| Vector Graphics | SVG-style path rendering (requires `LV_USE_VECTOR_GRAPHIC`) | +| Layers | Off-screen rendering into an FBO | +| Canvas | Direct drawing into canvas buffers | +| Vector Graphics | Path rendering — requires | +| 3D | glTF models, see [glTF](/libs/gltf) | -## Supported Image Formats +### Image formats uploaded without conversion -NanoVG supports zero-copy texture upload for these LVGL color formats: +| LVGL format | GL handling | Notes | +|---|---|---| +| | Alpha texture | Tinted in the shader | +| | BGR→RGB swizzle | Premultiplication handled in the shader | +| | BGR→RGB, alpha forced to 1 | X channel ignored | +| | BGR→RGB swizzle | No alpha | +| | Direct upload | LVGL uses a BGR565 layout | -| LVGL Format | GL Processing | Notes | -| --- | --- | --- | -| `LV_COLOR_FORMAT_A8` | Alpha texture | Color tinting via shader | -| `LV_COLOR_FORMAT_ARGB8888` | BGR→RGB swizzle | Premultiplication handled in shader | -| `LV_COLOR_FORMAT_XRGB8888` | BGR→RGB + alpha=1 | X channel ignored | -| `LV_COLOR_FORMAT_RGB888` | BGR→RGB swizzle | No alpha channel | -| `LV_COLOR_FORMAT_RGB565` | Direct upload | Note: LVGL uses BGR565 layout | +Anything else is converted before upload, which costs CPU time per image. Prefer one of the formats above for +assets you draw often. ## Performance Tips -1. **Minimize Layer Usage**: Each layer requires a framebuffer object (FBO) switch -2. **Use Premultiplied Alpha**: Set `LV_IMAGE_FLAGS_PREMULTIPLIED` for pre-processed images -3. **Cache Static Content**: NanoVG caches textures automatically; avoid recreating images -4. **Batch Similar Operations**: Group widgets with similar styles for better GPU batching +- **Minimize layer usage.** Each layer means a framebuffer object switch. +- **Use premultiplied alpha.** Set `LV_IMAGE_FLAGS_PREMULTIPLIED` on images you have pre-processed. +- **Let the caches work.** Textures and glyphs are cached automatically; recreating images defeats that. + Raise `LV_NANOVG_IMAGE_CACHE_CNT` or `LV_NANOVG_LETTER_CACHE_CNT` if your UI requires more than the default value. +- **Batch similar styles.** Widgets with matching styles batch better on the GPU. ## Limitations -- **Blur**: Not natively supported; Using this style will not affect the rendering results. -- **Complex Gradients**: Limited to 2-color gradients (LVGL supports multi-stop) -- **Layer Readback**: `glReadPixels` for canvas/layer is relatively slow +- **Gradients** are limited to two colors; LVGL's API allows more stops. +- **Layer and canvas readback** goes through `glReadPixels`, which is slow. Avoid it per frame. + +## See Also + +- [OpenGL Overview](/integration/embedded_linux/opengl) - how drivers and draw units fit together +- [OpenGL ES Draw Unit](/integration/embedded_linux/draw_units/draw_opengl) - the texture-caching alternative +- [glTF](/libs/gltf) - 3D model rendering, which requires a GPU renderer +- [EGL](/integration/embedded_linux/drivers/egl) - context creation, including headless off-screen rendering +- [DRM](/integration/embedded_linux/drivers/drm) - production display driver with an EGL backend diff --git a/docs/src/integration/embedded_linux/draw_units/draw_opengl.mdx b/docs/src/integration/embedded_linux/draw_units/draw_opengl.mdx index 267bc4e430..f3f95a0edc 100644 --- a/docs/src/integration/embedded_linux/draw_units/draw_opengl.mdx +++ b/docs/src/integration/embedded_linux/draw_units/draw_opengl.mdx @@ -1,51 +1,52 @@ --- title: OpenGL ES Draw Unit -description: "The OpenGL ES Draw Unit provides a hardware-accelerated rendering backend for LVGL that leverages OpenGL ES capabilities." +description: "The OpenGL ES draw unit caches software-rendered areas as GPU textures and composites them with OpenGL ES, avoiding redraws of content that has not changed." --- ## Overview -The OpenGL ES Draw Unit provides a hardware-accelerated rendering backend for LVGL that leverages OpenGL ES capabilities. +The OpenGL ES draw unit renders widgets in software, caches the result as an OpenGL texture, and composites +those textures on the GPU. Whenever a later frame asks for something already in the cache, the texture is +reused instead of redrawn, which is most of the screen, most of the time, in a typical UI. -OpenGL ES (OpenGL for Embedded Systems) is a subset of OpenGL designed for embedded devices, mobile phones, and other resource-constrained platforms. -The OpenGL ES Draw Unit brings GPU-accelerated rendering to LVGL applications on these platforms. +That makes it fast for static and slowly-changing content, and slower than software rendering for content +that changes every frame. -### Key Features + +[NanoVG](/integration/embedded_linux/draw_units/draw_nanovg) is the recommended GPU renderer on Linux: it +performs better and supports more LVGL features. Reach for this draw unit when you specifically want the +texture cache, or when NanoVG's limitations do not suit you. + -- **Hardware Acceleration**: Direct GPU acceleration via OpenGL ES 2.0+ -- **Texture Caching**: Rendered elements are cached as OpenGL textures for efficient reuse -- **GPU Blending**: Hardware-accelerated texture composition and blending -- **Embedded-Friendly**: Optimized for resource-constrained embedded systems -- **Wide Platform Support**: Works on mobile, embedded Linux, and other OpenGL ES-compatible platforms +### Requirements -### Performance Characteristics - -The OpenGL ES Draw Unit provides excellent performance for: - -- **Best Performance**: Static UI elements that benefit from texture caching -- **Good Performance**: UIs with moderate animation and dynamic content -- **Embedded Optimization**: Efficient memory usage suitable for embedded systems - -## Prerequisites - -- OpenGL ES 2.0 or higher support on your platform -- A driver which supports OpenGL configured (see [OpenGL Overview](/integration/embedded_linux/opengl)) +- OpenGL ES 2.0 or newer +- An OpenGL context, created by one of the display drivers listed in + [OpenGL Overview](/integration/embedded_linux/opengl) or by your own code ## Configuration -Enable the OpenGL ES draw unit in `lv_conf.h`: +Enable -```c -#define LV_USE_OPENGLES 1 +### Options -#define LV_USE_DRAW_OPENGLES 1 +| Symbol | Default | Meaning | +|---|---|---| +| `LV_DRAW_OPENGLES_TEXTURE_CACHE_COUNT` | `64` | Number of textures kept in the cache. More entries mean fewer redraws but more GPU memory. | -/* Configurable cache count. Bigger cache will improve performance */ -#define LV_DRAW_OPENGLES_TEXTURE_CACHE_COUNT 64 -``` +## Limitations + +- **No gain without cache hits.** Performance is worse when drawn areas are never found + in the cache, e.g. widgets whose color or shape changes every frame +- **Layer transparency.** Layers that have both transparent pixels and an overall layer opacity do not blend + correctly +- **No layer rotation.** Rotated layers are unsupported. Rotated *images* are fine. + +[NanoVG](/integration/embedded_linux/draw_units/draw_nanovg) has none of these limitations. ## See Also -- [OpenGL Overview](/integration/embedded_linux/opengl) - Complete OpenGL integration overview -- [EGL](/integration/embedded_linux/drivers/egl) - EGL Display Driver documentation -- [NanoVG Draw Unit](/integration/embedded_linux/draw_units/draw_nanovg) - Vector graphics rendering option +- [NanoVG Draw Unit](/integration/embedded_linux/draw_units/draw_nanovg) - the recommended GPU renderer +- [OpenGL Overview](/integration/embedded_linux/opengl) - how drivers and draw units fit together +- [OpenGL Driver](/integration/embedded_linux/drivers/opengl_driver) - texture-only driver for an existing context +- [EGL](/integration/embedded_linux/drivers/egl) - context creation on embedded targets diff --git a/docs/src/integration/embedded_linux/draw_units/draw_sdl.mdx b/docs/src/integration/embedded_linux/draw_units/draw_sdl.mdx index 18e63a97a5..1a0f5c0ca9 100644 --- a/docs/src/integration/embedded_linux/draw_units/draw_sdl.mdx +++ b/docs/src/integration/embedded_linux/draw_units/draw_sdl.mdx @@ -1,42 +1,40 @@ --- title: SDL Draw Unit -description: "The SDL Draw Unit provides a hardware-accelerated rendering backend for LVGL that leverages SDL2's texture system. It uses software rendering to create SDL textures which are then cached and effici..." +description: "The SDL draw unit renders widgets in software, caches them as SDL textures, and lets SDL's renderer composite them on the GPU." --- ## Overview -The SDL Draw Unit provides a hardware-accelerated rendering backend for LVGL that leverages SDL2's texture system. -It uses software rendering to create SDL textures which are then cached and efficiently blended together by the GPU to compose the final UI. -This approach combines the flexibility of software rendering with the performance benefits of hardware-accelerated texture blending. +The SDL draw unit renders widgets in software, caches the result as an SDL texture, and lets SDL's own +renderer blend those textures into the final frame. It is a hybrid: software rasterization, +hardware compositing. -### Key Features +It is the natural choice when your application already uses SDL and you want cheap acceleration without +introducing an OpenGL dependency. It works best with static or slowly-changing UIs, where most textures are +reused between frames, and offers little for content that changes every frame. -- **Texture Caching**: Rendered elements are cached as SDL textures, reducing redundant rendering operations -- **Hardware Blending**: SDL's GPU-accelerated texture blending provides smooth compositing -- **Cross-Platform**: Works on any platform that supports SDL2 -- **Easy Integration**: Seamless integration with SDL-based LVGL applications - -### Performance Characteristics - -The SDL Draw Unit excels in scenarios with: - -- **Best Performance**: Static or infrequently changing UI elements that benefit from texture caching -- **Good Performance**: UIs with moderate animation and updates -- **Consider Alternatives**: Heavily dynamic content that changes every frame may not benefit as much from caching - -## Prerequisites - -- SDL2 library installed (see [SDL Driver](/integration/pc/sdl) for installation instructions) -- LVGL configured with SDL support (`LV_USE_SDL 1`) +For genuinely GPU-accelerated rendering, use [NanoVG](/integration/embedded_linux/draw_units/draw_nanovg) +through the SDL driver's EGL backend instead. It rasterizes on the GPU rather than only compositing there. ## Configuration -Enable the SDL draw unit in `lv_conf.h`: +Enable and . It has no options of its +Select `LV_SDL_BACKEND_TEXTURE` as your -```c -#define LV_USE_SDL 1 -#define LV_USE_DRAW_SDL 1 -#define LV_USE_DRAW_SW 1 -``` +## Building -The SDL Draw Unit automatically integrates with the SDL display driver when both are enabled. +The renderer requires `sdl2_image`. + + +LVGL's CMake integration resolves it for you. +It can be fetched at compile time by LVGL so it doesn't have to be present on your system. + +See [Dependency Management](/integration/building/cmake). + + +## See Also + +- [SDL Driver](/integration/pc/sdl) - the display driver this draw unit pairs with +- [NanoVG Draw Unit](/integration/embedded_linux/draw_units/draw_nanovg) - true GPU rasterization, via SDL's EGL backend +- [OpenGL Overview](/integration/embedded_linux/opengl) - how drivers and draw units fit together +- [Dependency Management](/integration/building/cmake) - how LVGL resolves or fetches SDL2_image diff --git a/docs/src/integration/embedded_linux/drivers/X11.mdx b/docs/src/integration/embedded_linux/drivers/X11.mdx index 42af11b4bf..87f80d82d2 100644 --- a/docs/src/integration/embedded_linux/drivers/X11.mdx +++ b/docs/src/integration/embedded_linux/drivers/X11.mdx @@ -1,129 +1,121 @@ --- title: X11 -description: The X11 display/input driver offers support for simulating the LVGL display and keyboard/mouse inputs in an X11 desktop window. +description: 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. --- ## Overview -The **X11** display/input [driver](https://github.com/lvgl/lvgl/tree/master/src/drivers/x11) -offers support for simulating the LVGL display and keyboard/mouse inputs in an X11 -desktop window. +The [**X11** display/input driver](https://en.wikipedia.org/wiki/X_Window_System) opens a window +on an X11 desktop through Xlib and reads mouse, mousewheel and keyboard input. -It is an alternative to **Wayland**, **XCB**, **SDL** or **Qt**. +X11 is a CPU-blit driver with no GPU path. For production embedded targets prefer +[DRM](/integration/embedded_linux/drivers/drm) or [Wayland](/integration/embedded_linux/drivers/wayland). -The main purpose for this driver is for testing/debugging the LVGL application in a -**Linux** simulation window. +## Configuration -## Prerequisites +Enable . -The X11 driver uses XLib to access the linux window manager. + must be `16`, `24` or `32`. -1. Install XLib: `sudo apt-get install libx11-6` (should be installed already) -2. Install XLib development package: `sudo apt-get install libx11-dev` +### Options -## Configure X11 driver +| Symbol | Default | Effect | +|---|---|---| +| `LV_X11_RENDER_MODE` | `LV_DISPLAY_RENDER_MODE_PARTIAL` | Render mode | +| `LV_X11_DOUBLE_BUFFER` | on | Use two buffers | +| `LV_X11_DIRECT_EXIT` | on | Exit the application once all windows are closed | -1. Enable the X11 driver support in lv_conf.h, by cmake compiler define or by KConfig +## Building - ```c - #define LV_USE_X11 1 - ``` +The driver always requires `xlib`. -2. Optional configuration options: - - Direct Exit + +LVGL's CMake integration resolves it for you. +Make sure the required libraries are present on your system or in your sysroot. - ```c - #define LV_X11_DIRECT_EXIT 1 /* preferred default - ends the application automatically if last window has been closed */ - // or - #define LV_X11_DIRECT_EXIT 0 /* application is responsible for ending the application (e.g. by own LV_EVENT_DELETE handler) */ - ``` - - - Double buffering - - ```c - #define LV_X11_DOUBLE_BUFFER 1 /* preferred default */ - // or - #define LV_X11_DOUBLE_BUFFER 0 /* not recommended */ - ``` - - - Render mode - - ```c - #define LV_X11_RENDER_MODE_PARTIAL 1 /* LV_DISPLAY_RENDER_MODE_PARTIAL, preferred default */ - // or - #define LV_X11_RENDER_MODE_DIRECT 1 /* LV_DISPLAY_RENDER_MODE_DIRECT, not recommended for X11 driver */ - // or - #define LV_X11_RENDER_MODE_FULL 1 /* LV_DISPLAY_RENDER_MODE_FULL, not recommended for X11 driver */ - ``` +See [Dependency Management](/integration/building/cmake). + ## Usage -The minimal initialisation opening a window and enabling keyboard/mouse support -(e.g. in main.c, LV_X11_DIRECT_EXIT must be 1): +Create the window with , then attach input with +. The second argument is an optional cursor image; pass `NULL` for +none. ```c int main(int argc, char ** argv) { - ... + lv_init(); - /* initialize X11 display driver */ - lv_display_t * disp = lv_x11_window_create("LVGL X11 Simulation", monitor_hor_res, monitor_ver_res); + lv_display_t * disp = lv_x11_window_create("LVGL X11 Simulation", 800, 480); - /* initialize X11 input drivers (for keyboard, mouse & mousewheel) */ + /* Keyboard, mouse and mousewheel */ lv_x11_inputs_create(disp, NULL); - ... + lv_demo_widgets(); - while(true) - { - ... - - /* Periodically call the lv_timer handler */ - lv_timer_handler(); + 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); } } ``` -Full initialisation with mouse pointer symbol and own application exit handling -(dependent on LV_X11_DIRECT_EXIT (can be 1 or 0)) +Call again to open more windows; each returns its own display. + +### Handling window closure yourself + +With `LV_X11_DIRECT_EXIT` off, the application decides what happens when a window closes. Register an + handler on the display and run your own loop condition: ```c -bool terminated = false; +static bool terminated = false; -#if !LV_X11_DIRECT_EXIT static void on_close_cb(lv_event_t * e) { - ... - + LV_UNUSED(e); terminated = true; } -#endif int main(int argc, char ** argv) { - ... + lv_init(); - /* initialize X11 display driver */ - lv_display_t * disp = lv_x11_window_create("LVGL X11 Simulation", monitor_hor_res, monitor_ver_res); + lv_display_t * disp = lv_x11_window_create("LVGL X11 Simulation", 800, 480); lv_display_add_event_cb(disp, on_close_cb, LV_EVENT_DELETE, disp); - /* initialize X11 input drivers (for keyboard, mouse & mousewheel) */ - LV_IMAGE_DECLARE(my_mouse_cursor_icon); - lv_x11_inputs_create(disp, &my_mouse_cursor_icon); + /* Attach inputs, optionally with a cursor image */ + LV_IMAGE_DECLARE(mouse_cursor_icon); + lv_x11_inputs_create(disp, &mouse_cursor_icon); - #if !LV_X11_DIRECT_EXIT - /* set optional window close callback to enable application cleanup and exit */ - lv_x11_window_set_close_cb(disp, on_close_cb, disp); - #endif - - ... - - while(!terminated) - { - ... - - /* Periodically call the lv_timer handler */ - lv_timer_handler(); + while(!terminated) { + 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); } + + /* Clean up here */ } ``` + +## Support + +| Capability | Value | +|---|---| +| Rotation | None | +| Runtime resolution change | Yes | +| Runtime color format change | No | +| Color formats | Derived from (`16`, `24` or `32`) | +| Multiple displays / windows | Yes, one display per window | +| Hardware acceleration | None | +| Render mode | Configurable via `LV_X11_RENDER_MODE` | +| Input | Built in. Mouse, mousewheel and keyboard via | + +## See Also + +- [Dependency Management](/integration/building/cmake) - how LVGL resolves Xlib +- [Wayland](/integration/embedded_linux/drivers/wayland) - the modern alternative on Linux desktops +- [SDL Driver](/integration/pc/sdl) - cross-platform alternative for development +- [GLFW](/integration/embedded_linux/drivers/glfw) - development driver with an OpenGL context +- [DRM](/integration/embedded_linux/drivers/drm) - production alternative with no display server diff --git a/docs/src/integration/embedded_linux/drivers/drm.mdx b/docs/src/integration/embedded_linux/drivers/drm.mdx index 948f811211..d0ddec00db 100644 --- a/docs/src/integration/embedded_linux/drivers/drm.mdx +++ b/docs/src/integration/embedded_linux/drivers/drm.mdx @@ -1,73 +1,92 @@ --- title: DRM -description: "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 windowin..." +description: "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." --- ## 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** (Direct Rendering Manager) display driver renders LVGL straight to a display through the Linux +[DRM/KMS subsystem](https://en.wikipedia.org/wiki/Direct_Rendering_Manager), 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 DRM driver interacts directly with the GPU or display controller through -`/dev/dri/cardX` nodes. +The driver offers three backends: -## Getting Started with DRM +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](/integration/embedded_linux/drivers/fbdev), DRM gives you proper +modesetting, atomic page flips, and a path to GPU acceleration. ### Prerequisites -The DRM driver requires: +- 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. -- 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). +## Configuration -On Debian/Ubuntu-based systems: +Enable , and set to `32` or `16`. -```bash -sudo apt-get install libdrm-dev -``` +## Building -### Configure DRM Driver +The driver always requires `libdrm`. +The GBM and EGL backends additionally require `libgbm`. -1. Enable the DRM driver support in `lv_conf.h`, by CMake compiler define, or by KConfig: + +LVGL's CMake integration resolves both. +Make sure the required libraries are present on your system or in your sysroot. + +See [Dependency Management](/integration/building/cmake). + + +## Selecting a rendering backend + +Disable `LV_LINUX_DRM_AUTO_BACKEND` and set `LV_LINUX_DRM_BACKEND` to one of: + +| Value | Backend | +|---|---| +| `LV_LINUX_DRM_BACKEND_FBDEV` | Software rendering into DRM/KMS dumb buffers | +| `LV_LINUX_DRM_BACKEND_GBM` | Buffers allocated through Mesa GBM as DMA buffers | +| `LV_LINUX_DRM_BACKEND_EGL` | Hardware-accelerated rendering via OpenGL ES 2.0 and EGL | + + +`LV_LINUX_DRM_AUTO_BACKEND` infers the backend from , +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](/integration/embedded_linux/opengl). + +## Usage + + +[LVGL's linux port](https://github.com/lvgl/lv_port_linux) can be used to quickly get started with LVGL's DRM backend. + + +Create the display with , then bind it to a device node and connector +with . ```c -#define LV_USE_LINUX_DRM 1 -``` - -2. Link against `libdrm` when building. - -### Basic Usage - -```c -#include "lvgl/lvgl.h" +#include #include "lvgl/demos/lv_demos.h" int main(void) { - /* Initialize LVGL */ lv_init(); - /* DRM device node */ - const char *device = "/dev/dri/card0"; + lv_display_t * disp = lv_linux_drm_create(); - /* Create a DRM display */ - 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); - /* 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) { + 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; @@ -79,93 +98,45 @@ int main(void) } ``` -### Notes +The connector id selects which output (HDMI, eDP, DP, ...) to drive. Passing `-1` picks the first available +one. -- `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 . -It will return the first connected card it can find. +Rather than hard-coding the card path, ask LVGL to find a connected one with +. It scans `/sys/class/drm` and returns the first connected +card; free the result with `lv_free`. ```c 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 +## Selecting a Display Mode -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 -#define LV_USE_LINUX_DRM_GBM_BUFFERS 1 -``` - -2. 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](/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 -#define LV_USE_LINUX_DRM 1 -#define LV_USE_OPENGLES 1 -#define LV_USE_DRAW_OPENGLES 1 /* optional but recommended for performance */ -``` - -When 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 +By default the driver uses the display's preferred mode. To choose differently, register a callback with + before calling . It +receives every mode the connector reports and returns the index of the one to use. -Custom mode selection is currently only supported when using DRM with EGL -( enabled). When using DRM without EGL, the driver -will always use the preferred display mode. +Custom mode selection only takes effect with the EGL backend. With dumb buffers or GBM the driver always +uses the preferred 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 : - ```c -#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) +static 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 */ + /* Pick 1920x1080@60Hz if the display offers it */ 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 */ + 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; } } - /* Fallback: return the first mode */ + /* Fall back to the first mode */ return 0; } @@ -174,70 +145,45 @@ 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. +These functions query a mode: -### Mode Information API +| Function | Returns | +|---|---| +| | Width in pixels | +| | Height in pixels | +| | Refresh rate in Hz | +| | Whether this is the display's native mode | +| | The underlying mode info, for anything not covered above | -The following functions are available to query mode properties: +The callback must always return a valid index in `0 .. mode_count - 1`. Passing `NULL` to + restores the default behaviour. -- - Get width in pixels -- - Get height in pixels -- - Get refresh rate in Hz -- - Check if mode is the display's preferred/native mode +## Support -### Example: Selecting Preferred Mode +| Capability | Dumb buffers | GBM | EGL | +|---|---|---|---| +| Rotation | None | None | Hardware (GPU) | +| Runtime resolution change | No | No | Yes | +| Runtime color format change | No | No | No | +| Color formats | RGB565 or XRGB8888, from | RGB565 or XRGB8888, from | RGB565 or ARGB8888, from | +| Multiple displays / windows | One display per DRM device | One display per DRM device | One display per DRM device | +| Hardware acceleration | None | Buffer allocation only | OpenGL ES | +| Render mode | Direct | Direct | Full with NanoVG, otherwise Direct | +| Input | None built in. Pair with [evdev](/integration/embedded_linux/drivers/evdev) or [libinput](/integration/embedded_linux/drivers/libinput) | Same | Same | +| Custom mode selection | No | No | Yes | -```c -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; - } - } +## See Also - /* If no preferred mode found, return the first mode */ - return 0; -} -``` - -### Example: Selecting Highest Resolution - -```c -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 with `NULL` as the callback. +- [lv_port_linux](https://github.com/lvgl/lv_port_linux): reference project with a working DRM build +- [Dependency Management](/integration/building/cmake): how LVGL resolves `libdrm` and `libgbm` +- [EGL](/integration/embedded_linux/drivers/egl): the EGL layer underneath the EGL backend +- [OpenGL Overview](/integration/embedded_linux/opengl): GPU draw units usable with the EGL backend +- [Linux Framebuffer](/integration/embedded_linux/drivers/fbdev): simpler alternative when only `/dev/fb` exists +- [evdev](/integration/embedded_linux/drivers/evdev): input to pair with this driver diff --git a/docs/src/integration/embedded_linux/drivers/egl.mdx b/docs/src/integration/embedded_linux/drivers/egl.mdx index 000fdbad98..0011c6f6e7 100644 --- a/docs/src/integration/embedded_linux/drivers/egl.mdx +++ b/docs/src/integration/embedded_linux/drivers/egl.mdx @@ -1,45 +1,45 @@ --- title: EGL -description: "The EGL driver provides support for creating LVGL displays using the EGL (Embedded-System Graphics Library) API. EGL is a lower-level API that is more closely tied to the underlying drivers of the ..." +description: "EGL is the platform layer that binds OpenGL ES to a native windowing system. In LVGL it underpins the hardware-accelerated backends of the DRM, Wayland and SDL drivers, and can also render off-screen with no display server at all." --- ## Overview -The **EGL** driver provides support for creating LVGL displays using the EGL (Embedded-System Graphics Library) API. -EGL is a lower-level API that is more closely tied to the underlying drivers of the platform. -The OpenGL support in LVGL is intended to be portable between different APIs. Currently, there is support for GLFW and EGL. -Using EGL requires some additional platform integration. +[**EGL**](https://en.wikipedia.org/wiki/EGL_(API)) (Embedded-System Graphics Library) is the platform layer that binds OpenGL ES to a native windowing +system. It sits lower than GLFW and is more closely tied to the platform's own drivers, which is why it is +the path LVGL uses for GPU rendering on embedded Linux. -`lv_opengles_egl_window_create` can be used to create a -which can be used with the same generic LVGL OpenGL APIs as a GLFW window. +You rarely enable EGL on its own. It underpins the hardware-accelerated backends of the other drivers: -## EGL with DRM +- [DRM](/integration/embedded_linux/drivers/drm) with `LV_LINUX_DRM_BACKEND_EGL` +- [Wayland](/integration/embedded_linux/drivers/wayland) with `LV_WAYLAND_BACKEND_EGL` +- [SDL](/integration/pc/sdl) with `LV_SDL_BACKEND_EGL` -EGL can be used together with the DRM driver for hardware-accelerated rendering. +Selecting any of those backends turns EGL on for you and sets up the context during normal driver +initialization. Beyond that, EGL offers two things the other drivers do +not: a standalone window path for platforms LVGL does not otherwise cover, and off-screen rendering with no +display server at all. -When is enabled, the DRM driver will automatically set up EGL. -No additional initialization is required beyond the normal DRM setup. +## Building -See [DRM](/integration/embedded_linux/drivers/drm) for configuration and a basic usage example. +LVGL loads `libEGL.so` and `libGLESv2.so` at runtime with `dlopen`, so EGL doesn't have any build-time dependencies. -## EGL without DRM (Experimental) - - -This feature is experimental and the API is private. Expect breaking changes. + + cannot be combined with +each wants to own context creation. -If you want to use EGL without being tied to DRM, you can enable using a compiler definition. -This API is currently private and experimental, and people should expect breaking changes. +## Usage -```bash -# Enable standalone EGL (experimental) --DLV_USE_EGL=1 -``` +With a driver backend, EGL is invisible: configure the driver as its own page describes and it initializes +EGL during setup. See [DRM](/integration/embedded_linux/drivers/drm) or +[Wayland](/integration/embedded_linux/drivers/wayland) for working examples. -This allows you to use EGL with your own context management or other platforms, but the API may change -without notice in future versions. +## See Also -## Improving Performance - -There is a renderer in LVGL which caches software-rendered areas as OpenGL textures. -See [OpenGL Texture Caching Renderer](/integration/embedded_linux/drivers/opengl_driver) to learn more about it. +- [DRM](/integration/embedded_linux/drivers/drm) - EGL backend for direct-to-display rendering +- [Wayland](/integration/embedded_linux/drivers/wayland) - EGL backend under a compositor +- [OpenGL Driver](/integration/embedded_linux/drivers/opengl_driver) - use when you already own the context +- [OpenGL Overview](/integration/embedded_linux/opengl) - how the drivers and draw units fit together +- [NanoVG Draw Unit](/integration/embedded_linux/draw_units/draw_nanovg) - the renderer used for off-screen rendering +- [glTF](/libs/gltf) - 3D content, the strongest case for headless GPU rendering diff --git a/docs/src/integration/embedded_linux/drivers/evdev.mdx b/docs/src/integration/embedded_linux/drivers/evdev.mdx index d43b63dc71..38c4ad7c84 100644 --- a/docs/src/integration/embedded_linux/drivers/evdev.mdx +++ b/docs/src/integration/embedded_linux/drivers/evdev.mdx @@ -1,63 +1,91 @@ --- title: evdev -description: "The Linux event device (evdev) is a hardware-independent API that gives access to input events from, for example, a mouse or touchscreen. It is exposed via the Linux device file system interface." +description: "The evdev driver reads touchscreen, mouse and keyboard input straight from Linux /dev/input event devices, with no user-space input library required." --- ## Overview -The Linux event device (evdev) is a hardware-independent API that gives access to input events from, -for example, a mouse or touchscreen. It is exposed via the Linux device file system interface. +The [Linux event device](https://en.wikipedia.org/wiki/Evdev) (evdev) interface exposes input events from a touchscreen, +mouse, keyboard or anything else the kernel recognizes, through device files under `/dev/input/`. +The evdev driver reads them directly, so it needs no user-space input library at all. -## Prerequisites +That makes it the lightest input option on Linux and the natural pairing for the +[framebuffer](/integration/embedded_linux/drivers/fbdev) and [DRM](/integration/embedded_linux/drivers/drm) +display drivers, neither of which brings its own input. -Your system has an input device configured (usually under `/dev/input/` such as `/dev/input/event0`). +### Prerequisites -## Configuring the driver +An input device under `/dev/input/`, typically `/dev/input/event0`, and permission to read it. -Enable the Linux LVGL evdev driver support in `lv_conf.h`. +## Configuration -```c -#define LV_USE_EVDEV 1 -``` +Enable . + +## Building + +The driver always requires `libevdev`. + + +LVGL's CMake integration resolves both. +Make sure the required libraries are present on your system or in your sysroot. + +See [Dependency Management](/integration/building/cmake). + ## Usage -To set up an event input, first create an input device with , setting it to the correct Linux event device. -Then link this to the LVGL display with . - -```c -lv_indev_t *touch = lv_evdev_create(LV_INDEV_TYPE_POINTER, "/dev/input/event0"); -lv_indev_set_display(touch, disp); -``` - -Ensure that an object is already created for `disp`. An example for this is shown below, using the [Linux framebuffer](/integration/embedded_linux/drivers/fbdev) driver. +Create an input device with , giving it the device type and node path, then +attach it to a display with . ```c lv_display_t * disp = lv_linux_fbdev_create(); lv_linux_fbdev_set_file(disp, "/dev/fb0"); + +lv_indev_t * touch = lv_evdev_create(LV_INDEV_TYPE_POINTER, "/dev/input/event0"); +lv_indev_set_display(touch, disp); ``` -## Locating your input device +The type is for mice and touchscreens, or + for keyboards. takes an already +open file descriptor instead of a path, and removes a device. -If you can't determine your input device, first run +### Finding your input device -```$cat /proc/bus/input/devices``` +List what the kernel sees: -This should show input devices and there will be entries with the word `event` which give a clue as to the device to use eg. `event1` would be `/dev/input/event1`. +```sh +cat /proc/bus/input/devices +``` -You can use `evtest` to show data from that event source to see if it is actually the one you want. +Entries mention an `event` handler. `event1` corresponds to `/dev/input/event1`. Confirm you picked the +right one by watching its events: -Try: +```sh +evtest /dev/input/event1 +``` -`$evtest /dev/input/event1` replacing `eventX` with your event device from above. +### Calibrating a touchscreen -## Automatic input device discovery +Raw touchscreens report device coordinates, not screen coordinates. Map them with +, and correct a transposed panel with +. -There is support for automatically finding and adding input devices in `/dev/input/`. New devices will automatically be added -when they are connected. To enable this feature, you can simply call . +```c +lv_evdev_set_swap_axes(touch, true); +lv_evdev_set_calibration(touch, min_x, min_y, max_x, max_y); +``` -You may want to react to a new device being added so that a cursor image can be applied, for example. You can provide a callback -function which will be called when a new device is added. +### Automatic device discovery + +Rather than naming device nodes, let the driver find them. scans +`/dev/input/` and keeps watching it, so devices plugged in later are added automatically. +Passing `NULL` for both arguments is enough to enable it: + +```c +lv_evdev_discovery_start(NULL, NULL); +``` + +Supply a callback when you need to react to a new device — to attach a cursor image to a mouse, for example: ```c #include "lvgl/src/core/lv_global.h" @@ -72,9 +100,9 @@ static void indev_deleted_cb(lv_event_t * e) static void discovery_cb(lv_indev_t * indev, lv_evdev_type_t type, void * user_data) { LV_LOG_USER("new '%s' device discovered", type == LV_EVDEV_TYPE_REL ? "REL" : - type == LV_EVDEV_TYPE_ABS ? "ABS" : - type == LV_EVDEV_TYPE_KEY ? "KEY" : - "unknown"); + type == LV_EVDEV_TYPE_ABS ? "ABS" : + type == LV_EVDEV_TYPE_KEY ? "KEY" : + "unknown"); if(type == LV_EVDEV_TYPE_REL) { LV_IMAGE_DECLARE(mouse_cursor_icon); @@ -85,7 +113,7 @@ static void discovery_cb(lv_indev_t * indev, lv_evdev_type_t type, void * user_d } } -int main() +int main(void) { /* ... */ lv_evdev_discovery_start(discovery_cb, NULL); @@ -93,4 +121,34 @@ int main() } ``` -At the time of writing, this feature is not supported in BSD. + turns it off again. + + +Discovery relies on `inotify` and is not available on BSD. Create devices explicitly there. + + +### Raw key codes + +For keys LVGL does not map to one of its own, tells you an event +carries a raw code and returns it. Use these when you need keys +outside LVGL's navigation set. + +## Support + +| Capability | Value | +|---|---| +| Device types | Pointer (mouse, touchscreen) and keypad | +| Automatic discovery | Yes — | +| Hotplug | Yes — devices connected later are added automatically | +| Full keyboard (layouts, modifiers) | No — use [libinput](/integration/embedded_linux/drivers/libinput) with XKB | +| Touch calibration | Yes — | +| Axis swap | Yes — | +| Find device by capability | No — pass a node path, or use discovery | +| BSD | Yes, except discovery and hotplug | + +## See Also + +- [libinput](/integration/embedded_linux/drivers/libinput) - richer input stack, with XKB keyboard support +- [Linux Framebuffer](/integration/embedded_linux/drivers/fbdev) - display driver commonly paired with evdev +- [DRM](/integration/embedded_linux/drivers/drm) - display driver commonly paired with evdev +- [Dependency Management](/integration/building/cmake) - how LVGL resolves the evdev library diff --git a/docs/src/integration/embedded_linux/drivers/fbdev.mdx b/docs/src/integration/embedded_linux/drivers/fbdev.mdx index e10a3625ed..be31cb9de7 100644 --- a/docs/src/integration/embedded_linux/drivers/fbdev.mdx +++ b/docs/src/integration/embedded_linux/drivers/fbdev.mdx @@ -1,76 +1,101 @@ --- title: Linux Framebuffer -description: "The Linux framebuffer (fbdev) is a linux subsystem used to display graphics. It is a hardware-independent API that gives user space software access to the framebuffer (the part of a computer's vide..." +description: "The Linux framebuffer (fbdev) driver renders LVGL into /dev/fb through the kernel's framebuffer interface, with no libraries and no display server required." --- ## Overview -The Linux framebuffer (fbdev) is a linux subsystem used to display graphics. It is a hardware-independent API that gives user space software -access to the framebuffer (the part of a computer's video memory containing a current video frame) using only the Linux kernel's own basic -facilities and its device file system interface, avoiding the need for libraries that implement video drivers in user space. +The [Linux framebuffer (fbdev)](https://en.wikipedia.org/wiki/Linux_framebuffer) is a kernel subsystem that +exposes a video framebuffer to user space through a device file, typically `/dev/fb0`. It is hardware-independent +and needs no user-space graphics libraries at all, which makes this the simplest way to put LVGL on a screen: +open the device, write pixels. -## Prerequisites +That simplicity is also its limit. fbdev has no modesetting, no GPU path and no page-flip guarantees. It is +the right choice for minimal systems and for kernels that expose nothing else; on anything modern prefer +[DRM/KMS](/integration/embedded_linux/drivers/drm), which supersedes fbdev and can reach the GPU. -Your system has a framebuffer device configured (usually under `/dev/fb0`). +### Prerequisites -## Configuring the driver +A framebuffer device, usually `/dev/fb0`, and permission to open it. -Enable the framebuffer driver support in lv_conf.h, by cmake compiler define or by KConfig. Additionally you may configure the rendering -mode. +## Configuration -```c -#define LV_USE_LINUX_FBDEV 1 -#define LV_LINUX_FBDEV_RENDER_MODE LV_DISPLAY_RENDER_MODE_PARTIAL -``` +Enable . + +### Options + +| Symbol | Default | Effect | +|---|---|---| +| `LV_LINUX_FBDEV_RENDER_MODE` | `LV_DISPLAY_RENDER_MODE_PARTIAL` | Render mode; see below. | +| `LV_LINUX_FBDEV_BUFFER_COUNT` | `1` | `1` or `2` screen-sized buffers, or `0` for a custom-sized partial buffer. | +| `LV_LINUX_FBDEV_BUFFER_SIZE` | `60` | Height in rows of the partial buffer. Only used when the buffer count is `0`. | +| `LV_LINUX_FBDEV_MMAP` | on | Access the framebuffer via `mmap()` instead of `write()` calls. | +| `LV_LINUX_FBDEV_BSD` | off | Use the BSD flavour of the framebuffer device. | + +`LV_LINUX_FBDEV_RENDER_MODE` accepts , + or . + +The buffer count and the render mode constrain each other: two screen-sized buffers require a non-partial +render mode, and a custom-sized buffer requires the partial one. ## Usage -To set up a framebuffer-based display, first create a display with . Afterwards set the framebuffer device -node on the display with (usually this is `/dev/fb0`). + +[LVGL's linux port](https://github.com/lvgl/lv_port_linux) can be used to quickly get started with LVGL's FBDEV backend. + + +Create the display with , then point it at a device node with +. ```c -lv_display_t *disp = lv_linux_fbdev_create(); +lv_display_t * disp = lv_linux_fbdev_create(); lv_linux_fbdev_set_file(disp, "/dev/fb0"); ``` -If your screen stays black or only draws partially, you can try enabling direct -rendering via . Additionally, you can -activate a force refresh mode with . This -usually has a performance impact though and shouldn't be enabled unless really needed. +The resolution and color format come from the device, the driver reads them from the framebuffer's +`ioctl` info, so there is nothing to configure. -## Hide the cursor +### If the screen stays black or draws partially -You may encounter a blinking cursor on the screen. The method to hide it -varies depending on the platform. For instance, here is how it can be done -on a Raspberry Pi: +Try first. If that does not help, force a refresh of the +whole screen on every flush with . This costs performance, +so only enable it when it is genuinely needed. -1. Edit `/boot/cmdline.txt` file. -2. Add `vt.global_cursor_default=0`. +### Hide the blinking cursor -## Common mistakes +The kernel console leaves a blinking cursor on the framebuffer. How to disable it depends on the platform; +on a Raspberry Pi, add `vt.global_cursor_default=0` to `/boot/cmdline.txt`. -### Default resolution issue +### Wrong resolution after boot -When the Linux kernel initializes, it sets up subsystems like the framebuffer -(fbdev) to manage display output. If an HDMI display is connected, the kernel -detects it and allocates a portion of RAM as the framebuffer, which holds the -pixel data for rendering images. +The kernel sizes the framebuffer when it initializes, based on what the display reports. If the board powers +up before the screen (common with HDMI) the kernel may pick the wrong resolution, leaving both the visible +and virtual resolutions incorrect. -However, a common issue arises when the display is not powered on during the -boot process. If the board is powered on before the screen, the kernel may -incorrectly configure the framebuffer resolution. As a result, both the visible -and virtual resolutions can be incorrect, leading to display problems. +Check what the kernel actually chose: -This issue often occurs with HDMI connections where the display is powered up -after the system has already booted. - -The following command outputs the current settings of the specified framebuffer -device, such as resolution, pixel depth, and timings. - -```c +```sh fbset -fb /dev/fb0 ``` -To prevent display-related issues, it is recommended to ensure all devices, -including the HDMI display, are connected and powered on before powering up -the board. +The fix is procedural: make sure the display is connected and powered before the board boots. + +## Support + +| Capability | Value | +|---|---| +| Rotation | Software | +| Runtime resolution change | No | +| Runtime color format change | No | +| Color formats | RGB565, RGB888 or XRGB8888, chosen from the framebuffer's bit depth (16, 24 or 32) | +| Multiple displays / windows | Yes | +| Hardware acceleration | None | +| Render mode | Partial (default) — configurable via `LV_LINUX_FBDEV_RENDER_MODE` | +| Input | None built in. Pair with [evdev](/integration/embedded_linux/drivers/evdev) or [libinput](/integration/embedded_linux/drivers/libinput) | + +## See Also + +- [DRM](/integration/embedded_linux/drivers/drm) - the modern replacement, with modesetting and a GPU path +- [evdev](/integration/embedded_linux/drivers/evdev) - simplest input pairing for this driver +- [libinput](/integration/embedded_linux/drivers/libinput) - input with device quirks and full keyboard support +- [lv_port_linux](https://github.com/lvgl/lv_port_linux) - reference project diff --git a/docs/src/integration/embedded_linux/drivers/glfw.mdx b/docs/src/integration/embedded_linux/drivers/glfw.mdx index 24a3dad835..21d27f8172 100644 --- a/docs/src/integration/embedded_linux/drivers/glfw.mdx +++ b/docs/src/integration/embedded_linux/drivers/glfw.mdx @@ -1,74 +1,86 @@ --- title: GLFW -description: "The GLFW display/input driver offers support for creating LVGL displays and keyboard/mouse inputs that can be used in an OpenGL context. It can be used like Wayland, XCB, SDL or Qt or it can be use..." +description: "The GLFW driver opens a window with an OpenGL context and reads mouse and keyboard input. It is the quickest way to get LVGL running with GPU rendering on a PC-like platform." --- ## Overview -The **GLFW** display/input driver offers support for creating -LVGL displays and keyboard/mouse inputs that can be used in an OpenGL context. -It can be used like **Wayland**, **XCB**, **SDL** or **Qt** or it can be used for more embedded applications. +The **GLFW** display/input driver opens a window with an OpenGL context and reads mouse and keyboard input. -The GLFW driver is a quick way to get started on PC-like platforms. +## Configuration -## Getting Started with GLFW +Enable . -### Prerequisites + + cannot be combined with `EGL`. +GLFW manages the context itself, so the two window-system layers would collide. + -Install GLFW: `sudo apt-get install libglfw3-dev` -### Configure GLFW Driver +## Building -1. Required linked libraries: -lglfw -2. Enable the GLFW driver and Opengles support in `lv_conf.h`, via cmake compiler define or via KConfig +The driver always requires `GLFW`. -```c -#define LV_USE_GLFW 1 -#define LV_USE_OPENGLES 1 -``` + +LVGL's CMake integration resolves it for you. +It can be fetched at compile time by LVGL so it doesn't have to be present on your system. -### Basic Usage +See [Dependency Management](/integration/building/cmake). + + +## GPU Rendering + +To render on the GPU rather than blitting software-rendered pixels, also enable one of the draw units: + +| Symbol | Effect | +|---|---| +| | Vector rendering on the GPU. Recommended — best performance and feature coverage. | +| | Caches software-rendered areas as GPU textures. | + +Neither is required: with no draw unit enabled the driver still works, rendering in software and uploading +the result to the window. + +## Usage + + +[LVGL's linux port](https://github.com/lvgl/lv_port_linux) can be used to quickly get started with LVGL's GLFW backend. + + + opens the window and initializes OpenGL. The third +argument enables the mouse input device. then gives you +a display that renders into that window. ```c #include "lvgl/lvgl.h" -#include "lvgl/examples/lv_examples.h" #include "lvgl/demos/lv_demos.h" -#define WIDTH 640 +#define WIDTH 640 #define HEIGHT 480 -int main() +int main(void) { - /* initialize lvgl */ lv_init(); - /* create a window and initialize OpenGL */ + /* Create a window and initialize OpenGL */ lv_opengles_window_t * window = lv_opengles_glfw_window_create(WIDTH, HEIGHT, true); - /* create a display that flushes to a texture */ - lv_display_t * texture = lv_opengles_texture_create(WIDTH, HEIGHT); - lv_display_set_default(texture); + /* Create a display that renders into the window */ + lv_display_t * disp = lv_opengles_window_display_create(window, WIDTH, HEIGHT); + lv_display_set_default(disp); - /* add the texture to the window */ - unsigned int texture_id = lv_opengles_texture_get_texture_id(texture); - lv_opengles_window_texture_t * window_texture = lv_opengles_window_add_texture(window, texture_id, WIDTH, HEIGHT); - - /* get the mouse indev of the window texture */ - lv_indev_t * mouse = lv_opengles_window_texture_get_mouse_indev(window_texture); - - /* add a cursor to the mouse indev */ + /* Add a cursor to the window's mouse indev */ + lv_opengles_window_texture_t * wt = lv_opengles_window_display_get_window_texture(disp); + lv_indev_t * mouse = lv_opengles_window_texture_get_mouse_indev(wt); LV_IMAGE_DECLARE(mouse_cursor_icon); lv_obj_t * cursor_obj = lv_image_create(lv_screen_active()); lv_image_set_src(cursor_obj, &mouse_cursor_icon); lv_indev_set_cursor(mouse, cursor_obj); - /* create Widgets on the screen */ lv_demo_widgets(); - while (1) - { + 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; /*handle LV_NO_TIMER_READY. Another option is to `sleep` for longer*/ + if(time_until_next == LV_NO_TIMER_READY) time_until_next = LV_DEF_REFR_PERIOD; lv_delay_ms(time_until_next); } @@ -76,125 +88,75 @@ int main() } ``` -### Advanced Usage +Multiple windows can be created, each with its own displays. -The GLFW driver can draw textures from the user. A third-party library could be -used to add content to a texture and the driver will draw the texture in the window. +## Compositing Textures in a Window + +A GLFW window can draw any number of OpenGL textures, positioned and blended independently. That covers two +cases: several LVGL displays in one window, and LVGL displaying textures produced by another library. + +Use for an LVGL display that renders into its own texture, and + to place any texture id in the window. ```c #include "lvgl/lvgl.h" -#include -#define WIDTH 640 +#define WIDTH 640 #define HEIGHT 480 -void custom_texture_example(void) +void composite_example(lv_opengles_window_t * window) { - /***************** - * MAIN WINDOW - *****************/ + /* A second LVGL display, rendering into its own texture */ + const int32_t sub_w = 300, sub_h = 300; + lv_display_t * sub = lv_opengles_texture_create(sub_w, sub_h); + unsigned int sub_id = lv_opengles_texture_get_texture_id(sub); + lv_opengles_window_texture_t * sub_wt = + lv_opengles_window_add_texture(window, sub_id, sub_w, sub_h); - /* create a window and initialize OpenGL */ - /* multiple windows can be created */ - lv_opengles_window_t * window = lv_opengles_glfw_window_create(WIDTH, HEIGHT, true); - - /**************************** - * OPTIONAL MAIN TEXTURE - ****************************/ - - /* create a main display that flushes to a texture */ - lv_display_t * main_texture = lv_opengles_texture_create(WIDTH, HEIGHT); - lv_display_set_default(main_texture); - - /* add the main texture to the window */ - unsigned int main_texture_id = lv_opengles_texture_get_texture_id(main_texture); - lv_opengles_window_texture_t * window_main_texture = lv_opengles_window_add_texture(window, main_texture_id, WIDTH, HEIGHT); - - /* get the mouse indev of this main texture */ - lv_indev_t * main_texture_mouse = lv_opengles_window_texture_get_mouse_indev(window_main_texture); - - /* add a cursor to the mouse indev */ - LV_IMAGE_DECLARE(mouse_cursor_icon); - lv_obj_t * cursor_obj = lv_image_create(lv_screen_active()); - lv_image_set_src(cursor_obj, &mouse_cursor_icon); - lv_indev_set_cursor(main_texture_mouse, cursor_obj); - - /* create Widgets on the screen of the main texture */ - lv_demo_widgets(); - - /********************** - * ANOTHER TEXTURE - **********************/ - - /* create a sub display that flushes to a texture */ - const int32_t sub_texture_w = 300; - const int32_t sub_texture_h = 300; - lv_display_t * sub_texture = lv_opengles_texture_create(sub_texture_w, sub_texture_h); - - /* add the sub texture to the window */ - unsigned int sub_texture_id = lv_opengles_texture_get_texture_id(sub_texture); - lv_opengles_window_texture_t * window_sub_texture = lv_opengles_window_add_texture(window, sub_texture_id, sub_texture_w, sub_texture_h); - - /* create Widgets on the screen of the sub texture */ - lv_display_set_default(sub_texture); + /* Build its UI */ + lv_display_t * saved = lv_display_get_default(); + lv_display_set_default(sub); lv_example_keyboard_2(); - lv_display_set_default(main_texture); + lv_display_set_default(saved); - /* position the sub texture within the window */ - lv_opengles_window_texture_set_x(window_sub_texture, 250); - lv_opengles_window_texture_set_y(window_sub_texture, 150); + /* Position it in the window and make it translucent */ + lv_opengles_window_texture_set_x(sub_wt, 250); + lv_opengles_window_texture_set_y(sub_wt, 150); + lv_opengles_window_texture_set_opa(sub_wt, LV_OPA_80); - /* optionally change the opacity of the sub texture */ - lv_opengles_window_texture_set_opa(window_sub_texture, LV_OPA_80); + /* A texture owned by some other library can be added the same way */ + lv_opengles_window_add_texture(window, external_texture_id, ext_w, ext_h); - /********************************************* - * USE AN EXTERNAL OPENGL TEXTURE IN LVGL - *********************************************/ - - unsigned int external_texture_id; - glGenTextures(1, &external_texture_id); - glBindTexture(GL_TEXTURE_2D, external_texture_id); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - LV_IMAGE_DECLARE(img_cogwheel_argb); -#if LV_COLOR_DEPTH == 8 - const int texture_format = GL_R8; -#elif LV_COLOR_DEPTH == 16 - const int texture_format = GL_RGB565; -#elif LV_COLOR_DEPTH == 24 - const int texture_format = GL_RGB; -#elif LV_COLOR_DEPTH == 32 - const int texture_format = GL_RGBA; -#else -#error("Unsupported color format") -#endif - glTexImage2D(GL_TEXTURE_2D, 0, texture_format, img_cogwheel_argb.header.w, img_cogwheel_argb.header.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_cogwheel_argb.data); - glGenerateMipmap(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); - - /* add the external texture to the window */ - lv_opengles_window_texture_t * window_external_texture = lv_opengles_window_add_texture(window, external_texture_id, img_cogwheel_argb.header.w, img_cogwheel_argb.header.h); - - /* set the position and opacity of the external texture within the window */ - lv_opengles_window_texture_set_x(window_external_texture, 20); - lv_opengles_window_texture_set_y(window_external_texture, 20); - lv_opengles_window_texture_set_opa(window_external_texture, LV_OPA_70); - - /********************************************* - * USE AN LVGL TEXTURE IN ANOTHER LIBRARY - *********************************************/ - - lv_refr_now(sub_texture); - - /* the texture is drawn on by LVGL and can be used by anything that uses OpenGL textures */ - third_party_lib_use_texture(sub_texture_id); + /* Going the other way: render the LVGL texture, then hand it to another library */ + lv_refr_now(sub); + third_party_lib_use_texture(sub_id); } ``` -## Improving Performance + takes a texture back out of the window. -There is a renderer in LVGL which caches software-rendered areas as OpenGL textures. -See [OpenGL Texture Caching Renderer](/integration/embedded_linux/drivers/opengl_driver) to learn more about it. +To wrap a texture your own code allocated in an LVGL display instead, use +. See +[OpenGL Driver](/integration/embedded_linux/drivers/opengl_driver) for the texture-only driver, which +assumes you manage the context and the window yourself. + +## Support + +| Capability | Value | +|---|---| +| Rotation | Hardware (GPU) | +| Runtime resolution change | No | +| Runtime color format change | No | +| Color formats | Derived from | +| Multiple displays / windows | Yes | +| Hardware acceleration | OpenGL ES, via or | +| Render mode | Full with , otherwise Direct | +| Input | Built in, mouse per window, keyboard | + +## See Also + +- [Dependency Management](/integration/building/cmake) - how LVGL resolves or fetches GLFW +- [OpenGL Driver](/integration/embedded_linux/drivers/opengl_driver) - texture-only driver for an existing context +- [OpenGL Overview](/integration/embedded_linux/opengl) - how the drivers and draw units fit together +- [NanoVG Draw Unit](/integration/embedded_linux/draw_units/draw_nanovg) - the recommended GPU renderer +- [EGL](/integration/embedded_linux/drivers/egl) - use instead of GLFW when you need EGL diff --git a/docs/src/integration/embedded_linux/drivers/index.mdx b/docs/src/integration/embedded_linux/drivers/index.mdx index a51597fe1a..950459fd26 100644 --- a/docs/src/integration/embedded_linux/drivers/index.mdx +++ b/docs/src/integration/embedded_linux/drivers/index.mdx @@ -1,6 +1,84 @@ --- title: Drivers +description: "LVGL's Linux drivers come in two kinds: display drivers that put pixels on a screen, and input drivers that read touch, mouse and keyboard events. Most setups need one of each." --- +## Overview + +LVGL's Linux drivers come in two kinds, and most setups need one of each: + +- **Display drivers** get rendered pixels onto a screen — or into a texture, or a file. +- **Input drivers** read touch, mouse and keyboard events. + +Some display drivers bring their own input, so pairing is not always necessary. The tables below say which. + +If you are not sure which display driver you want, start from +[Choosing a Display Driver](/integration/embedded_linux#choosing-a-display-driver), which picks one based on +what your system already has. + +## Display Drivers + +| Driver | Best for | Rotation | Hardware acceleration | Runtime resolution change | Input | +|---|---|---|---|---|---| +| **[fbdev](/integration/embedded_linux/drivers/fbdev)** | Minimal systems exposing only `/dev/fb` | Software, but it disables direct mode | None | No | Pair separately | +| **[DRM](/integration/embedded_linux/drivers/drm)** | Production embedded targets | EGL backend only | EGL backend | EGL backend only | Pair separately | +| **[Wayland](/integration/embedded_linux/drivers/wayland)** | Systems running a compositor | Yes, all backends | EGL or G2D backend | Yes | Built in | +| **[X11](/integration/embedded_linux/drivers/X11)** | Development on an X desktop | None | None | Yes | Built in | +| **[GLFW](/integration/embedded_linux/drivers/glfw)** | Development with an instant GL context | Hardware | OpenGL ES | No | Built in | +| **[OpenGL Driver](/integration/embedded_linux/drivers/opengl_driver)** | Embedding LVGL in your own GL application | Hardware | OpenGL ES | Manual | None — you own the window | +| **[EGL](/integration/embedded_linux/drivers/egl)** | The layer under the accelerated backends, and headless rendering | Hardware | OpenGL ES | Depends on the driver | Depends on the driver | + +Each driver page carries a fuller **Support** table, including color formats, multiple-display support and the +render mode. + + +The [SDL driver](/integration/pc/sdl) is a perfectly good option on Linux and is often the quickest way to get +a window during development. Because it is cross-platform it lives under +[Running on PC](/integration/pc) rather than here. Its +[draw unit](/integration/embedded_linux/draw_units/draw_sdl) is documented with the other draw units. + + +### A note on EGL + +[EGL](/integration/embedded_linux/drivers/egl) is not usually a driver you select. It is the OpenGL ES +platform layer that the DRM, Wayland and SDL drivers use for their hardware-accelerated backends, so +selecting one of those backends turns it on for you. You reach for the EGL page directly in two cases: +custom platform integration, and off-screen rendering with no display server at all. + +## Input Drivers + +| Driver | Best for | Discovery and hotplug | Full keyboard | Touch calibration | Find device by capability | +|---|---|---|---|---|---| +| **[evdev](/integration/embedded_linux/drivers/evdev)** | The common case — a known touchscreen or mouse | Yes | No | Yes | No | +| **[libinput](/integration/embedded_linux/drivers/libinput)** | Text entry, or devices needing quirks | No | Yes, via XKB | Not needed | Yes | + +Use **evdev** unless you need real keyboard support — layouts and modifiers — or your device requires +libinput's quirk handling. evdev is lighter and is the only one of the two with automatic device discovery and +hotplug. + +Pair an input driver with a display driver by attaching it to the display: + +```c +lv_indev_t * touch = lv_evdev_create(LV_INDEV_TYPE_POINTER, "/dev/input/event0"); +lv_indev_set_display(touch, disp); +``` + +## Rendering + +Drivers decide how a frame reaches the screen; **draw units** decide who rasterizes it. The two are chosen +independently — see [Draw Units](/integration/embedded_linux/draw_units) and +[OpenGL Overview](/integration/embedded_linux/opengl). + +One consequence worth knowing before you start: on every GPU and compositor path the render mode is fixed by +the driver rather than configurable, because something other than LVGL owns the buffers. Only the CPU-blit +drivers — fbdev, X11 and SDL's software backend — let you choose it. + +## See Also + +- [Choosing a Display Driver](/integration/embedded_linux#choosing-a-display-driver) - decision table +- [Draw Units](/integration/embedded_linux/draw_units) - who does the rasterizing +- [OpenGL Overview](/integration/embedded_linux/opengl) - which drivers provide a GL context +- [Dependency Management](/integration/building/cmake) - how enabling a driver pulls in its libraries +- [lv_port_linux](https://github.com/lvgl/lv_port_linux) - reference project with every driver preconfigured diff --git a/docs/src/integration/embedded_linux/drivers/libinput.mdx b/docs/src/integration/embedded_linux/drivers/libinput.mdx index 75ccde33e0..4644f3f656 100644 --- a/docs/src/integration/embedded_linux/drivers/libinput.mdx +++ b/docs/src/integration/embedded_linux/drivers/libinput.mdx @@ -1,21 +1,29 @@ --- title: libinput -description: "Libinput is an input stack for processes that need to provide events from commonly used input devices. That includes mice, keyboards, touchpads, touchscreens and graphics tablets." +description: "The libinput driver reads pointer, touch and keyboard input through libinput, which handles device-specific quirks and offers full keyboard support through XKB." --- ## Overview -Libinput is an input stack for processes that need to provide events from commonly used input devices. That includes mice, keyboards, touchpads, -touchscreens and graphics tablets. Libinput handles device-specific quirks and provides an easy-to-use API to receive events from devices. +[libinput](https://wiki.archlinux.org/title/Libinput) is the input stack used by most Linux desktops. +It covers mice, keyboards, touchpads, touchscreens and graphics tablets, absorbing device-specific quirks +and normalizing everything into a uniform event stream. -## Prerequisites +Compared with [evdev](/integration/embedded_linux/drivers/evdev), libinput gives you two things that matter: +quirk handling for devices that need it, and real keyboard support (layouts, modifiers and non-US +keyboards) through XKB. In exchange it adds a dependency and gives up automatic device discovery. +Use [evdev](/integration/embedded_linux/drivers/evdev) for a minimal system with a known touchscreen; +use libinput when you need proper text entry or a device with quirks. -You have the development version of libinput installed (usually `libinput-dev`). If your input device requires quirks, make sure they are -installed as well (usually in `/usr/share/libinput/*.quirks`). To test if your device is set up correctly for use with libinput, you can -run `libinput list-devices`. +### Prerequisites -```console -$ sudo libinput list-devices +libinput must be available in the build (usually the `libinput` development package). If your device needs +quirks, make sure those are installed too, normally under `/usr/share/libinput/*.quirks`. + +Check that libinput sees your device: + +```bash +libinput list-devices ... Device: ETPS/2 Elantech Touchpad Kernel: /dev/input/event5 @@ -28,56 +36,102 @@ Tap-and-drag: enabled ... ``` -If your device doesn't show up, you may have to configure udev and the appropriate udev rules to connect it. +If it does not appear, you likely need udev rules to connect it. -Additionally, if you want full keyboard support, including letters and modifiers, you'll need the development version of libxkbcommon -installed (usually `libxkbcommon-dev`). +## Configuration -## Configuring the driver +Enable . -Enable the libinput driver support in lv_conf.h, by cmake compiler define or by KConfig. +### Full keyboard support -```c -#define LV_USE_LIBINPUT 1 -``` +Letters, modifiers and non-US layouts need XKB, which is off by default. Enable `LV_LIBINPUT_XKB`, then +describe your keyboard with these options: -Full keyboard support needs to be enabled separately. +| Symbol | Default | Meaning | +|---|---|---| +| `LV_LIBINPUT_XKB_RULES` | `""` | XKB rules file | +| `LV_LIBINPUT_XKB_MODEL` | `"pc101"` | Keyboard model | +| `LV_LIBINPUT_XKB_LAYOUT` | `"us"` | Layout | +| `LV_LIBINPUT_XKB_VARIANT` | `""` | Layout variant | +| `LV_LIBINPUT_XKB_OPTIONS_USE_DEFAULT` | on | Use the system default options, e.g. from `XKB_DEFAULT_OPTIONS` | +| `LV_LIBINPUT_XKB_OPTIONS` | `""` | Explicit options; only used when the above is off | -```c -#define LV_LIBINPUT_XKB 1 -#define LV_LIBINPUT_XKB_KEY_MAP { .rules = NULL, .model = "pc101", .layout = "us", .variant = NULL, .options = NULL } -``` +Run `setxkbmap -query` on a working system to find the right values. -To find the right key map values, you may use the `setxkbmap -query` command. +### Other options + +| Symbol | Default | Effect | +|---|---|---| +| `LV_LIBINPUT_BSD` | off | Use the BSD variant of libinput. | + +## Building + +The driver always requires `libinput`. +Additionally you may use XKB support which requires `libxbkcommon`. + + +LVGL's CMake integration resolves both. +Make sure the required libraries are present on your system or in your sysroot. + +See [Dependency Management](/integration/building/cmake). + ## Usage -To set up an input device via the libinput driver, all you need to do is call with the respective device type -( or ) and device node path (e.g. `/dev/input/event5`). +Call with the device type and the node path. ```c -lv_indev_t *indev = lv_libinput_create(LV_INDEV_TYPE_POINTER, "/dev/input/event5"); +lv_indev_t * indev = lv_libinput_create(LV_INDEV_TYPE_POINTER, "/dev/input/event5"); ``` -Note that touchscreens are treated as (absolute) pointer devices by the libinput driver and require . +The type is or . Note that +libinput treats touchscreens as absolute pointer devices, so a touchscreen also needs +. removes a device. -Depending on your system, the device node paths might not be stable across reboots. If this is the case, you can use -to find the first device that has a specific capability. +### Finding devices without hard-coded paths + +Device node paths are not necessarily stable across reboots. Look a device up by what it can do instead, with +: ```c -char *path = lv_libinput_find_dev(LV_LIBINPUT_CAPABILITY_TOUCH, true); +char * path = lv_libinput_find_dev(LV_LIBINPUT_CAPABILITY_TOUCH, true); ``` -The second argument controls whether or not all devices are rescanned. If you have many devices connected this can get quite slow. -Therefore, you should only specify `true` on the first call when calling this method multiple times in a row. If you want to find -all devices that have a specific capability, use . +The capability is one of `LV_LIBINPUT_CAPABILITY_KEYBOARD`, `LV_LIBINPUT_CAPABILITY_POINTER` or +`LV_LIBINPUT_CAPABILITY_TOUCH`. The second argument controls whether all devices are rescanned; scanning is +slow with many devices, so pass `true` only on the first of a series of calls. -If you want to connect a keyboard device to a textarea, create a dedicated input group and set it on both the indev and textarea. + returns every device with a given capability, and + reports what a specific device supports. + +### Connecting a keyboard to a text area + +Keyboard input reaches a widget through a group. Create one, set it on the input device, and add the widget: ```c -lv_obj_t *textarea = lv_textarea_create(...); -... -lv_group_t *keyboard_input_group = lv_group_create(); -lv_indev_set_group(indev, keyboard_input_group); -lv_group_add_obj(keyboard_input_group, textarea); +lv_obj_t * textarea = lv_textarea_create(lv_screen_active()); + +lv_group_t * g = lv_group_create(); +lv_indev_set_group(indev, g); +lv_group_add_obj(g, textarea); ``` + +## Support + +| Capability | Value | +|---|---| +| Device types | Pointer (mouse, touchpad, touchscreen) and keypad | +| Automatic discovery | No | +| Hotplug | No | +| Full keyboard (layouts, modifiers) | With `LV_LIBINPUT_XKB` | +| Touch calibration | Automatic | +| Axis swap | With libinput quirks or udev rules | +| Find device by capability | and | +| BSD | With `LV_LIBINPUT_BSD` | + +## See Also + +- [evdev](/integration/embedded_linux/drivers/evdev) - lighter alternative, with discovery and hotplug +- [Linux Framebuffer](/integration/embedded_linux/drivers/fbdev) - display driver needing a separate input driver +- [DRM](/integration/embedded_linux/drivers/drm) - display driver needing a separate input driver +- [Dependency Management](/integration/building/cmake) - how LVGL resolves libinput and xkbcommon diff --git a/docs/src/integration/embedded_linux/drivers/meta.json b/docs/src/integration/embedded_linux/drivers/meta.json index 861c81132f..bab05d0e2f 100644 --- a/docs/src/integration/embedded_linux/drivers/meta.json +++ b/docs/src/integration/embedded_linux/drivers/meta.json @@ -3,11 +3,11 @@ "pages": [ "fbdev", "drm", - "opengl_driver", - "glfw", - "egl", "wayland", "X11", + "glfw", + "opengl_driver", + "egl", "evdev", "libinput" ] diff --git a/docs/src/integration/embedded_linux/drivers/opengl_driver.mdx b/docs/src/integration/embedded_linux/drivers/opengl_driver.mdx index 4c23c9cb67..c24fe50d74 100644 --- a/docs/src/integration/embedded_linux/drivers/opengl_driver.mdx +++ b/docs/src/integration/embedded_linux/drivers/opengl_driver.mdx @@ -1,109 +1,155 @@ --- title: OpenGL Driver -description: The OpenGL display driver is a generic driver that creates textures for embedding LVGL content in other applications. The goal is to create textures that people can embed in other applications. +description: "The OpenGL driver renders an LVGL display into an OpenGL texture, for embedding LVGL inside an application that already owns the OpenGL context." --- ## Overview -The **OpenGL** display driver is a generic driver that creates textures for embedding -LVGL content in other applications. The goal is to create textures that people can -embed in other applications. The OpenGL context must be created by the user or they -can use GLFW or EGL as backends. +The **OpenGL** display driver renders an LVGL display into an OpenGL texture and hands you the texture id. +It creates no window and no context: it is the driver to use when something else, a game, a visualization +tool or your own engine already owns the OpenGL context and you want LVGL content inside it. -## Getting Started with OpenGL +If you do not already have a context, use a driver that creates one for you instead: -### Prerequisites +- [GLFW](/integration/embedded_linux/drivers/glfw) on PC-like platforms +- [EGL](/integration/embedded_linux/drivers/egl), or [DRM](/integration/embedded_linux/drivers/drm) and + [Wayland](/integration/embedded_linux/drivers/wayland) with their EGL backends, on embedded targets +- [SDL](/integration/pc/sdl) with its EGL backend -An OpenGL context must be created before using the OpenGL driver. You can create this using: +## Configuration -- GLFW (see [GLFW driver](/integration/embedded_linux/drivers/glfw)) -- EGL (see [EGL driver](/integration/embedded_linux/drivers/egl)) -- Your own OpenGL context management +Enable . -### Configure OpenGL Driver +There are no libraries for LVGL to resolve, the GL entry points come from the context you already created. -Enable the OpenGL driver support in lv_conf.h, by cmake compiler define or by KConfig: +To render on the GPU rather than uploading software-rendered pixels into the texture, also enable a draw +unit: (recommended) or . See +[OpenGL Overview](/integration/embedded_linux/opengl). -```c -#define LV_USE_OPENGLES 1 -``` +## Usage -### Basic Usage +The OpenGL context must already be current when you call . It +allocates the texture for you; returns the id to use in +your own rendering. ```c #include "lvgl/lvgl.h" -#define WIDTH 640 +#define WIDTH 640 #define HEIGHT 480 -/* This flush callback works with both FULL and DIRECT render modes*/ -static void flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map) +int main(void) { - if (lv_display_flush_is_last(disp)) { - const int32_t disp_width = lv_display_get_horizontal_resolution(disp); - const int32_t disp_height = lv_display_get_vertical_resolution(disp); - /* The texture occupies the full screen even if `area` is not the full screen which happens with RENDER_MODE_DIRECT */ - lv_area_t full_area; - lv_area_set(&full_area, 0, 0, disp_width, disp_height); - - /* Get the texture id containing LVGL generated UI */ - unsigned int texture_id = lv_opengles_texture_get_texture_id(disp); - /* This function will render to the current context */ - lv_opengles_render_texture(texture_id, &full_area, LV_OPA_COVER, disp_width, disp_height, &full_area, false, true); - } - lv_display_flush_ready(disp); -} - -int main() -{ - /* initialize lvgl */ lv_init(); /* Don't forget the tick callback */ - /* NOTE: OpenGL context must be created before this point */ + /* NOTE: the OpenGL context must be created and current before this point */ - /* Create a display that flushes to a texture. The OpenGL texture will be created for you */ - lv_display_t * texture = lv_opengles_texture_create(WIDTH, HEIGHT); - /* If you already have an OpenGL texture ready, you can use it instead: - * lv_display_t * texture = lv_opengles_texture_create_from_texture_id(WIDTH, HEIGHT, my_texture_id); */ + lv_display_t * disp = lv_opengles_texture_create(WIDTH, HEIGHT); - /* Set the display render mode and flush callback - * lv_display_set_render_mode(texture, LV_DISPLAY_RENDER_MODE_FULL); - * lv_display_set_flush_cb(texture, flush_cb); */ + /* The texture id, for use in your application's rendering */ + unsigned int texture_id = lv_opengles_texture_get_texture_id(disp); - /* get the texture ID for use in your application */ - unsigned int texture_id = lv_opengles_texture_get_texture_id(texture); - - /* create Widgets on the screen */ lv_demo_widgets(); - while (1) - { + 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); + /* Draw texture_id in your own scene, then swap buffers */ } return 0; } ``` -## OpenGL Texture Caching Renderer +If you have already allocated a texture yourself, wrap it instead of letting LVGL create one with +. + looks up the display belonging to a texture id, +and resizes a texture and its display together. -There is a renderer in LVGL which caches software-rendered areas as OpenGL textures. -The textures are retrieved from the cache and reused when there is a match. -The performance will be drastically improved in most cases. +Create as many displays as you need, each gets its own texture. + +### Drawing the texture yourself + +The driver flushes into the texture and stops there; putting it on screen is your job. + draws a texture into the current framebuffer if you want LVGL +to do it, and does the same for a display's own +texture. + +To take over presentation entirely, set your own flush callback. This one works in both the full and direct +render modes: ```c -#define LV_USE_DRAW_OPENGLES 1 +static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map) +{ + LV_UNUSED(area); + LV_UNUSED(px_map); + + if(lv_display_flush_is_last(disp)) { + const int32_t w = lv_display_get_horizontal_resolution(disp); + const int32_t h = lv_display_get_vertical_resolution(disp); + + /* The texture always covers the full screen, even when `area` does not, + * which is the case in the direct render mode */ + lv_area_t full_area; + lv_area_set(&full_area, 0, 0, w, h); + + unsigned int texture_id = lv_opengles_texture_get_texture_id(disp); + /* Renders into the current context */ + lv_opengles_render_texture(texture_id, &full_area, LV_OPA_COVER, w, h, &full_area, false, true); + } + + lv_display_flush_ready(disp); +} ``` +Register it after creating the display, together with the render mode you want: + +```c +lv_display_set_render_mode(disp, LV_DISPLAY_RENDER_MODE_FULL); +lv_display_set_flush_cb(disp, flush_cb); +``` + + sets the viewport LVGL renders through, if your application needs +LVGL confined to part of the framebuffer. + +## OpenGL Texture Caching Renderer + + enables a renderer that caches software-rendered areas as OpenGL +textures and reuses them whenever a later frame asks for the same thing. In most UIs this is a large +improvement, because most of the screen does not change between frames. + ### Known Limitations -- Performance will be the same or slightly worse if the drawn areas are never found in the cache - due to Widgets with continuously varying colors or shapes. One example is a label whose color - is set to a random value every frame, as in the "Multiple labels" scene of the benchmark demo. -- Layers with transparent pixels and an overall layer transparency will not blend correctly. - The effect can be observed in the "Containers with opa_layer" scene of the benchmark demo - in the border corners. -- Layers with rotation are not currently supported. Images with rotation are fine. +- Performance is the same or slightly worse when drawn areas never hit the cache — widgets whose color or + shape changes every frame, such as a label recolored randomly each frame (the "Multiple labels" scene of + the benchmark demo). +- Layers that have both transparent pixels and an overall layer opacity do not blend correctly. Visible in + the border corners of the benchmark demo's "Containers with opa_layer" scene. +- Layers with rotation are not supported. Rotated *images* are fine. + + avoids these limitations and performs better; prefer it unless you +specifically need the texture cache. See +[NanoVG Draw Unit](/integration/embedded_linux/draw_units/draw_nanovg). + +## Support + +| Capability | Value | +|---|---| +| Rotation | Hardware (GPU) | +| Runtime resolution change | With | +| Runtime color format change | No | +| Color formats | Derived from | +| Multiple displays / windows | Yes. One display per texture. Windows are not this driver's concern | +| Hardware acceleration | OpenGL ES, via or | +| Render mode | Direct by default | +| Input | None built in. The window belongs to your application, so feed LVGL input yourself | + +## See Also + +- [GLFW](/integration/embedded_linux/drivers/glfw) - creates the window and context for you, and can composite these textures +- [EGL](/integration/embedded_linux/drivers/egl) - context creation on embedded targets, including off-screen rendering +- [OpenGL Overview](/integration/embedded_linux/opengl) - how the drivers and draw units fit together +- [NanoVG Draw Unit](/integration/embedded_linux/draw_units/draw_nanovg) - the recommended GPU renderer +- [OpenGL ES Draw Unit](/integration/embedded_linux/draw_units/draw_opengl) - the texture-caching renderer diff --git a/docs/src/integration/embedded_linux/drivers/wayland.mdx b/docs/src/integration/embedded_linux/drivers/wayland.mdx index 5869c55f2f..14ef62faa0 100644 --- a/docs/src/integration/embedded_linux/drivers/wayland.mdx +++ b/docs/src/integration/embedded_linux/drivers/wayland.mdx @@ -5,7 +5,7 @@ description: "The Wayland driver renders LVGL into a Wayland surface and reads k ## Overview -The Wayland driver renders LVGL into a Wayland surface and reads keyboard, pointer and touch input from the compositor. +The [Wayland](https://en.wikipedia.org/wiki/Wayland_(protocol)) 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](/integration/embedded_linux/drivers/X11) and [SDL](/integration/pc/sdl) drivers. diff --git a/docs/src/integration/embedded_linux/index.mdx b/docs/src/integration/embedded_linux/index.mdx index b740e80292..36e1916f5d 100644 --- a/docs/src/integration/embedded_linux/index.mdx +++ b/docs/src/integration/embedded_linux/index.mdx @@ -12,6 +12,32 @@ flexibility to target anything from a minimal framebuffer setup to a fully GPU-a The recommended way to get started is the [lv_port_linux](https://github.com/lvgl/lv_port_linux) reference project. It provides a ready-to-build CMake project with the most common drivers pre-configured, and is the fastest path to a running LVGL application on Linux hardware. +## Choosing a Display Driver + +Pick the driver from what your system already has, not from what sounds fastest. On Linux there is usually +exactly one right answer. + +| What you have | Use | Why | +|---|---|---| +| A modern kernel with DRM/KMS, no compositor | **[DRM](/integration/embedded_linux/drivers/drm)** | The production default. Real modesetting, and an EGL backend when there is a GPU. | +| Only `/dev/fb`, no DRM | **[fbdev](/integration/embedded_linux/drivers/fbdev)** | Simplest possible path. No libraries, no GPU, no modesetting. | +| A Wayland compositor already running | **[Wayland](/integration/embedded_linux/drivers/wayland)** | SHM everywhere, EGL for the GPU, G2D on NXP i.MX. | +| An X11 desktop, for development | **[X11](/integration/embedded_linux/drivers/X11)** | Window on your dev machine. CPU-only, no rotation. | +| A dev machine, want a window fast | **[SDL](/integration/pc/sdl)** or **[GLFW](/integration/embedded_linux/drivers/glfw)** | Cross-platform. GLFW brings an OpenGL context with it. | +| An OpenGL context you already own | **[OpenGL Driver](/integration/embedded_linux/drivers/opengl_driver)** | Renders into a texture for embedding in your own GL application. | +| No display at all — CI, thumbnails, servers | **[EGL pbuffer](/integration/embedded_linux/drivers/egl)** | The only way to get GPU-rendered frames with no display server. | + +Then decide whether you want GPU rendering on top: see +[Rendering acceleration](#rendering-acceleration) below. Enabling a driver's EGL backend without a GPU draw +unit is valid — LVGL renders in software and uses OpenGL only to present the result. + + +Only the Wayland, X11, SDL and GLFW drivers come with input. With DRM or fbdev you pair a display driver +with an input driver yourself — [evdev](/integration/embedded_linux/drivers/evdev) for the simple case, +[libinput](/integration/embedded_linux/drivers/libinput) when you need full keyboard layouts or device +quirks. + + ## What LVGL supports ### Display and input drivers @@ -22,10 +48,14 @@ LVGL provides drivers for the most common Linux display and input interfaces: - **[DRM/KMS](/integration/embedded_linux/drivers/drm)**: modern direct rendering, recommended for production embedded targets - **[Wayland](/integration/embedded_linux/drivers/wayland)**: suitable for systems running a Wayland compositor, with SHM, EGL, and G2D backends. Also useful for development - **[X11](/integration/embedded_linux/drivers/X11)**: useful for development and desktop simulation -- **[EGL](/integration/embedded_linux/drivers/egl)**: hardware-accelerated OpenGL ES rendering, usable via DRM or Wayland +- **[EGL](/integration/embedded_linux/drivers/egl)**: the OpenGL ES layer under the DRM, Wayland and SDL hardware-accelerated backends, and the way to render off-screen with no display server - **[evdev](/integration/embedded_linux/drivers/evdev) / [libinput](/integration/embedded_linux/drivers/libinput)**: touchscreen, mouse, and keyboard input - **[GLFW](/integration/embedded_linux/drivers/glfw)**: cross-platform windowing, primarily for development +Each driver page carries a **Support** table listing what it can and cannot do — rotation, runtime resolution +and color format changes, multiple displays, hardware acceleration and input. The +[driver index](/integration/embedded_linux/drivers) collects the highlights into one comparison table. + ### Rendering acceleration Beyond the CPU-based software renderer, LVGL supports GPU-accelerated draw units on Linux: @@ -34,6 +64,13 @@ Beyond the CPU-based software renderer, LVGL supports GPU-accelerated draw units - **[OpenGL](/integration/embedded_linux/draw_units/draw_opengl)** (`draw_opengl`): direct OpenGL ES rendering, including 3D/glTF support - **[SDL](/integration/embedded_linux/draw_units/draw_sdl)** (`draw_sdl`): SDL2-based rendering +A draw unit needs a driver that provides an OpenGL context — see +[OpenGL Overview](/integration/embedded_linux/opengl) for which drivers do, and for why the render mode is +fixed on those paths rather than something you choose. + +3D and [glTF](/libs/gltf) content requires one of the GPU draw units; the software renderer cannot draw it +at all. + ### OS and distribution support LVGL works with standard Linux distributions and embedded build systems. Dedicated integration guides are available for: @@ -43,6 +80,12 @@ LVGL works with standard Linux distributions and embedded build systems. Dedicat - **[Yocto](/integration/embedded_linux/distros/yocto)**: layer-based embedded Linux build system - **[Torizon](/integration/embedded_linux/distros/torizon)**: container-based embedded Linux platform by Toradex +### Building and dependencies + +Enabling a driver's config symbol is also what pulls its libraries into the build — LVGL resolves them with +`find_package`, then `pkg-config`, then by fetching sources where that is possible. See +[Dependency Management](/integration/building/cmake) rather than installing packages by hand. + ### Multimedia LVGL supports hardware-accelerated video playback on Linux through: diff --git a/docs/src/integration/embedded_linux/opengl.mdx b/docs/src/integration/embedded_linux/opengl.mdx index 6ad4f85270..aefb430c32 100644 --- a/docs/src/integration/embedded_linux/opengl.mdx +++ b/docs/src/integration/embedded_linux/opengl.mdx @@ -1,60 +1,63 @@ --- title: OpenGL Overview -description: "OpenGL (Open Graphics Library) is a cross-platform, hardware-accelerated graphics API that provides a standardized interface for rendering 2D and 3D graphics. Originally developed by Silicon Graphi..." +description: "How LVGL's OpenGL support fits together on Linux: which display drivers create a context, which draw units render on the GPU, and how the two combine." --- -## Introduction +## Overview -### Overview +OpenGL is a cross-platform, hardware-accelerated graphics API, and OpenGL ES is the subset designed for +embedded and mobile hardware. LVGL uses it on Linux for three reasons: to offload rendering to the GPU, to +embed LVGL content inside existing OpenGL applications, and to render 3D content. -OpenGL (Open Graphics Library) is a cross-platform, hardware-accelerated graphics API that provides a standardized interface for rendering 2D and 3D graphics. -Originally developed by Silicon Graphics in 1992, OpenGL has become one of the most widely adopted graphics APIs across desktop, mobile, and embedded platforms. +LVGL's OpenGL support comes in two halves, and you generally need one of each: -### OpenGL Support in LVGL +- **Display drivers** create and own the OpenGL context, and put the finished frame on screen. +- **Draw units** do the actual rendering with OpenGL instead of the CPU. -The OpenGL integration consists of two main components: +Enabling a driver with an OpenGL backend but no GPU draw unit is valid and sometimes what you want, +LVGL can then render using software and use OpenGL to present the result to the display. -- OpenGL Display Drivers: Handle output by showing the LVGL rendered content on the display, window, or texture in OpenGL-based environments -- OpenGL Draw Units: When enabled, LVGL uses OpenGL for hardware-accelerated rendering operations. +## Drivers That Create a Context -OpenGL support addresses several key use cases: +These drivers create and manage an OpenGL context for you: -1. Performance optimization: Leverage GPU acceleration for rendering. -2. Cross-Platform compatibility: OpenGL's wide platform support enables LVGL UIs on desktop, mobile, and embedded systems. -3. Integration with existing applications: Embed LVGL UI elements into games, visualization tools, or other OpenGL applications. +| Driver | How to get the OpenGL path | +|---|---| +| [DRM](/integration/embedded_linux/drivers/drm) | `LV_LINUX_DRM_BACKEND_EGL` | +| [Wayland](/integration/embedded_linux/drivers/wayland) | `LV_WAYLAND_USE_EGL` | +| [SDL](/integration/pc/sdl) | `LV_SDL_BACKEND_EGL` | +| [GLFW](/integration/embedded_linux/drivers/glfw) | Always | -## OpenGL Driver Options +Every one of them except GLFW uses [EGL](/integration/embedded_linux/drivers/egl) underneath. -The following drivers can be used and will automatically create and maintain an OpenGL context. + + cannot be combined with + -- [SDL driver](/integration/pc/sdl) -- [Wayland driver](/integration/embedded_linux/drivers/wayland) -- [DRM driver](/integration/embedded_linux/drivers/drm) -- [GLFW driver](/integration/embedded_linux/drivers/glfw) +Additionally there's also a generic [OpenGL Driver](/integration/embedded_linux/drivers/opengl_driver) +which can be use to embed LVGL in an application that already owns the context. -All drivers except the GLFW driver use EGL (Embedded-System Graphics Library) under the hood. +## Draw Units -Additionally, LVGL provides a generic OpenGL driver which the user may use to embed -OpenGL textures in existing OpenGL applications. This driver assumes an existing OpenGL context -and generates textures with hardware acceleration for integration into custom graphics pipelines. +| Draw unit | Notes | +|---|---| +| [NanoVG](/integration/embedded_linux/draw_units/draw_nanovg) | **Recommended.** Rasterizes on the GPU, best performance and widest feature coverage | +| [OpenGL ES](/integration/embedded_linux/draw_units/draw_opengl) | Caches software-rendered areas as GPU textures. Slower, fewer features. | -For complete implementation details, see [OpenGL driver](/integration/embedded_linux/drivers/opengl_driver). +## 3D and glTF -## OpenGL Draw Unit Options +The glTF module loads and renders 3D models per the glTF 2.0 specification, with PBR materials, animations and +camera control. It needs OpenGL ES 2.0 with some extra extensions. -When one of these draw units is enabled as well as one of the supporting drivers, LVGL will use OpenGL for -hardware-accelerated rendering. +3D support comes from the GL renderers so a GPU draw unit is required. -- [NanoVG](/integration/embedded_linux/draw_units/draw_nanovg) -- [OpenGL](/integration/embedded_linux/draw_units/draw_opengl) +For details, see [glTF](/libs/gltf). -[NanoVG](/integration/embedded_linux/draw_units/draw_nanovg) is the recommended choice. It makes better use of the GPU -and supports more LVGL features. OpenGL is also available but the performance is worse and it supports fewer features. +## See Also -## 3D/glTF Support - -The glTF module provides support for loading and rendering 3D models using the glTF 2.0 specification within LVGL applications. -This support requires OpenGL ES 2.0 with some extra extensions and provides comprehensive 3D rendering capabilities including PBR materials, -animations, and interactive camera controls for embedded 3D visualization. - -For complete implementation details, see [glTF](/libs/gltf). +- [NanoVG Draw Unit](/integration/embedded_linux/draw_units/draw_nanovg) - the recommended GPU renderer +- [EGL](/integration/embedded_linux/drivers/egl) - the layer under most OpenGL paths on Linux +- [DRM](/integration/embedded_linux/drivers/drm) - production driver with an EGL backend +- [GLFW](/integration/embedded_linux/drivers/glfw) - quickest OpenGL setup for development +- [OpenGL Driver](/integration/embedded_linux/drivers/opengl_driver) - embedding LVGL in an existing context +- [glTF](/libs/gltf) - 3D model rendering