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