mirror of
https://github.com/lvgl/lvgl.git
synced 2026-09-25 16:44:03 +08:00
docs(linux): standardize and update embedded linux docs
This commit is contained in:
@@ -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 <ApiLink name="LV_USE_DRAW_NANOVG" />.
|
||||
|
||||
```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+ |
|
||||
|
||||
<Callout type="warning" title="The backend must match the context">
|
||||
`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.
|
||||
</Callout>
|
||||
|
||||
## 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 <ApiLink name="LV_USE_VECTOR_GRAPHIC" /> |
|
||||
| 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 |
|
||||
|---|---|---|
|
||||
| <ApiLink name="LV_COLOR_FORMAT_A8" /> | Alpha texture | Tinted in the shader |
|
||||
| <ApiLink name="LV_COLOR_FORMAT_ARGB8888" /> | BGR→RGB swizzle | Premultiplication handled in the shader |
|
||||
| <ApiLink name="LV_COLOR_FORMAT_XRGB8888" /> | BGR→RGB, alpha forced to 1 | X channel ignored |
|
||||
| <ApiLink name="LV_COLOR_FORMAT_RGB888" /> | BGR→RGB swizzle | No alpha |
|
||||
| <ApiLink name="LV_COLOR_FORMAT_RGB565" /> | 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
|
||||
|
||||
@@ -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
|
||||
<Callout type="info" title="Prefer NanoVG">
|
||||
[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.
|
||||
</Callout>
|
||||
|
||||
- **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 <ApiLink name="LV_USE_DRAW_OPENGLES" />
|
||||
|
||||
```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
|
||||
|
||||
@@ -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 <ApiLink name="LV_USE_DRAW_SDL" /> and <ApiLink name="LV_USE_SDL" />. It has no options of its
|
||||
Select `LV_SDL_BACKEND_TEXTURE` as your <ApiLink name="LV_SDL_BACKEND" />
|
||||
|
||||
```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`.
|
||||
|
||||
<Callout type="tip">
|
||||
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).
|
||||
</Callout>
|
||||
|
||||
## 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
|
||||
|
||||
@@ -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 <ApiLink name="LV_USE_X11" />.
|
||||
|
||||
The X11 driver uses XLib to access the linux window manager.
|
||||
<ApiLink name="LV_COLOR_DEPTH" /> 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
|
||||
<Callout type="tip">
|
||||
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).
|
||||
</Callout>
|
||||
|
||||
## 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 <ApiLink name="lv_x11_window_create" />, then attach input with
|
||||
<ApiLink name="lv_x11_inputs_create" />. 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 <ApiLink name="lv_x11_window_create" /> 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
|
||||
<ApiLink name="LV_EVENT_DELETE" /> 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 <ApiLink name="LV_COLOR_DEPTH" /> (`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 <ApiLink name="lv_x11_inputs_create" /> |
|
||||
|
||||
## 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
|
||||
|
||||
@@ -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 <ApiLink name="LV_USE_LINUX_DRM" />, and set <ApiLink name="LV_COLOR_DEPTH" /> 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:
|
||||
<Callout type="tip">
|
||||
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).
|
||||
</Callout>
|
||||
|
||||
## 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 |
|
||||
|
||||
<Callout type="warning" title="Turn off the legacy auto-backend first">
|
||||
`LV_LINUX_DRM_AUTO_BACKEND` infers the backend from <ApiLink name="LV_USE_OPENGLES" />,
|
||||
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.
|
||||
</Callout>
|
||||
|
||||
For the GPU draw units that run on top of the EGL backend, see
|
||||
[OpenGL Overview](/integration/embedded_linux/opengl).
|
||||
|
||||
## Usage
|
||||
|
||||
<Callout type="tip">
|
||||
[LVGL's linux port](https://github.com/lvgl/lv_port_linux) can be used to quickly get started with LVGL's DRM backend.
|
||||
</Callout>
|
||||
|
||||
Create the display with <ApiLink name="lv_linux_drm_create" />, then bind it to a device node and connector
|
||||
with <ApiLink name="lv_linux_drm_set_file" />.
|
||||
|
||||
```c
|
||||
#define LV_USE_LINUX_DRM 1
|
||||
```
|
||||
|
||||
2. Link against `libdrm` when building.
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```c
|
||||
#include "lvgl/lvgl.h"
|
||||
#include <lvgl/lvgl.h>
|
||||
#include "lvgl/demos/lv_demos.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* Initialize LVGL */
|
||||
lv_init();
|
||||
|
||||
/* DRM device node */
|
||||
const char *device = "/dev/dri/card0";
|
||||
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 <ApiLink name="lv_linux_drm_find_device_path" />.
|
||||
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
|
||||
<ApiLink name="lv_linux_drm_find_device_path" />. 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 <ApiLink name="LV_USE_OPENGLES" /> 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
|
||||
<ApiLink name="lv_linux_drm_set_mode_cb" /> before calling <ApiLink name="lv_linux_drm_set_file" />. It
|
||||
receives every mode the connector reports and returns the index of the one to use.
|
||||
|
||||
<Callout type="info">
|
||||
Custom mode selection is currently only supported when using DRM with EGL
|
||||
(<ApiLink name="LV_USE_OPENGLES" /> 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.
|
||||
</Callout>
|
||||
|
||||
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 <ApiLink name="lv_linux_drm_set_mode_cb" />:
|
||||
|
||||
```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 |
|
||||
|---|---|
|
||||
| <ApiLink name="lv_linux_drm_mode_get_horizontal_resolution" /> | Width in pixels |
|
||||
| <ApiLink name="lv_linux_drm_mode_get_vertical_resolution" /> | Height in pixels |
|
||||
| <ApiLink name="lv_linux_drm_mode_get_refresh_rate" /> | Refresh rate in Hz |
|
||||
| <ApiLink name="lv_linux_drm_mode_is_preferred" /> | Whether this is the display's native mode |
|
||||
| <ApiLink name="lv_linux_drm_mode_get_raw" /> | 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
|
||||
<ApiLink name="lv_linux_drm_set_mode_cb" /> restores the default behaviour.
|
||||
|
||||
- <ApiLink name="lv_linux_drm_mode_get_horizontal_resolution" /> - Get width in pixels
|
||||
- <ApiLink name="lv_linux_drm_mode_get_vertical_resolution" /> - Get height in pixels
|
||||
- <ApiLink name="lv_linux_drm_mode_get_refresh_rate" /> - Get refresh rate in Hz
|
||||
- <ApiLink name="lv_linux_drm_mode_is_preferred" /> - 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 <ApiLink name="LV_COLOR_DEPTH" /> | RGB565 or XRGB8888, from <ApiLink name="LV_COLOR_DEPTH" /> | RGB565 or ARGB8888, from <ApiLink name="LV_COLOR_DEPTH" /> |
|
||||
| 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 <ApiLink name="lv_linux_drm_set_mode_cb" /> 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
|
||||
|
||||
@@ -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 <ApiLink name="lv_opengles_window_t" />
|
||||
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 <ApiLink name="LV_USE_OPENGLES" /> 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)
|
||||
|
||||
<Callout type="warn">
|
||||
This feature is experimental and the API is private. Expect breaking changes.
|
||||
<Callout type="warning" title="EGL and GLFW are mutually exclusive">
|
||||
<ApiLink name="LV_USE_GLFW" /> cannot be combined with <ApiLink name="LV_USE_EGL" />
|
||||
each wants to own context creation.
|
||||
</Callout>
|
||||
|
||||
If you want to use EGL without being tied to DRM, you can enable <ApiLink name="LV_USE_EGL" /> 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
|
||||
|
||||
@@ -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 <ApiLink name="LV_USE_EVDEV" />.
|
||||
|
||||
## Building
|
||||
|
||||
The driver always requires `libevdev`.
|
||||
|
||||
<Callout type="tip">
|
||||
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).
|
||||
</Callout>
|
||||
|
||||
## Usage
|
||||
|
||||
To set up an event input, first create an input device with <ApiLink name="lv_evdev_create" />, setting it to the correct Linux event device.
|
||||
Then link this to the LVGL display with <ApiLink name="lv_indev_set_display" />.
|
||||
|
||||
```c
|
||||
lv_indev_t *touch = lv_evdev_create(LV_INDEV_TYPE_POINTER, "/dev/input/event0");
|
||||
lv_indev_set_display(touch, disp);
|
||||
```
|
||||
|
||||
Ensure that an <ApiLink name="lv_display_t" /> 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 <ApiLink name="lv_evdev_create" />, giving it the device type and node path, then
|
||||
attach it to a display with <ApiLink name="lv_indev_set_display" />.
|
||||
|
||||
```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 <ApiLink name="LV_INDEV_TYPE_POINTER" /> for mice and touchscreens, or
|
||||
<ApiLink name="LV_INDEV_TYPE_KEYPAD" /> for keyboards. <ApiLink name="lv_evdev_create_fd" /> takes an already
|
||||
open file descriptor instead of a path, and <ApiLink name="lv_evdev_delete" /> 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
|
||||
<ApiLink name="lv_evdev_set_calibration" />, and correct a transposed panel with
|
||||
<ApiLink name="lv_evdev_set_swap_axes" />.
|
||||
|
||||
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 <ApiLink name="lv_evdev_discovery_start" display="lv_evdev_discovery_start(NULL, NULL)" />.
|
||||
```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. <ApiLink name="lv_evdev_discovery_start" /> 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.
|
||||
<ApiLink name="lv_evdev_discovery_stop" /> turns it off again.
|
||||
|
||||
<Callout type="info">
|
||||
Discovery relies on `inotify` and is not available on BSD. Create devices explicitly there.
|
||||
</Callout>
|
||||
|
||||
### Raw key codes
|
||||
|
||||
For keys LVGL does not map to one of its own, <ApiLink name="lv_evdev_is_raw_key" /> tells you an event
|
||||
carries a raw code and <ApiLink name="lv_evdev_get_raw_key" /> 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 — <ApiLink name="lv_evdev_discovery_start" /> |
|
||||
| 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 — <ApiLink name="lv_evdev_set_calibration" /> |
|
||||
| Axis swap | Yes — <ApiLink name="lv_evdev_set_swap_axes" /> |
|
||||
| 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
|
||||
|
||||
@@ -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 <ApiLink name="LV_USE_LINUX_FBDEV" />.
|
||||
|
||||
### 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 <ApiLink name="LV_DISPLAY_RENDER_MODE_PARTIAL" />,
|
||||
<ApiLink name="LV_DISPLAY_RENDER_MODE_DIRECT" /> or <ApiLink name="LV_DISPLAY_RENDER_MODE_FULL" />.
|
||||
|
||||
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 <ApiLink name="lv_linux_fbdev_create" />. Afterwards set the framebuffer device
|
||||
node on the display with <ApiLink name="lv_linux_fbdev_set_file" /> (usually this is `/dev/fb0`).
|
||||
<Callout type="tip">
|
||||
[LVGL's linux port](https://github.com/lvgl/lv_port_linux) can be used to quickly get started with LVGL's FBDEV backend.
|
||||
</Callout>
|
||||
|
||||
Create the display with <ApiLink name="lv_linux_fbdev_create" />, then point it at a device node with
|
||||
<ApiLink name="lv_linux_fbdev_set_file" />.
|
||||
|
||||
```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 <ApiLink name="LV_DISPLAY_RENDER_MODE_DIRECT" />. Additionally, you can
|
||||
activate a force refresh mode with <ApiLink name="lv_linux_fbdev_set_force_refresh" />. 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 <ApiLink name="LV_DISPLAY_RENDER_MODE_DIRECT" /> first. If that does not help, force a refresh of the
|
||||
whole screen on every flush with <ApiLink name="lv_linux_fbdev_set_force_refresh" />. 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
|
||||
|
||||
@@ -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 <ApiLink name="LV_USE_GLFW" />.
|
||||
|
||||
### Prerequisites
|
||||
<Callout type="warning" title="GLFW and EGL are mutually exclusive">
|
||||
<ApiLink name="LV_USE_GLFW" /> cannot be combined with `EGL`.
|
||||
GLFW manages the context itself, so the two window-system layers would collide.
|
||||
</Callout>
|
||||
|
||||
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
|
||||
```
|
||||
<Callout type="tip">
|
||||
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).
|
||||
</Callout>
|
||||
|
||||
## GPU Rendering
|
||||
|
||||
To render on the GPU rather than blitting software-rendered pixels, also enable one of the draw units:
|
||||
|
||||
| Symbol | Effect |
|
||||
|---|---|
|
||||
| <ApiLink name="LV_USE_DRAW_NANOVG" /> | Vector rendering on the GPU. Recommended — best performance and feature coverage. |
|
||||
| <ApiLink name="LV_USE_DRAW_OPENGLES" /> | 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
|
||||
|
||||
<Callout type="tip">
|
||||
[LVGL's linux port](https://github.com/lvgl/lv_port_linux) can be used to quickly get started with LVGL's GLFW backend.
|
||||
</Callout>
|
||||
|
||||
<ApiLink name="lv_opengles_glfw_window_create" /> opens the window and initializes OpenGL. The third
|
||||
argument enables the mouse input device. <ApiLink name="lv_opengles_window_display_create" /> 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 <ApiLink name="lv_opengles_texture_create" /> for an LVGL display that renders into its own texture, and
|
||||
<ApiLink name="lv_opengles_window_add_texture" /> to place any texture id in the window.
|
||||
|
||||
```c
|
||||
#include "lvgl/lvgl.h"
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#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
|
||||
<ApiLink name="lv_opengles_window_texture_remove" /> 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
|
||||
<ApiLink name="lv_opengles_texture_create_from_texture_id" />. 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 <ApiLink name="LV_COLOR_DEPTH" /> |
|
||||
| Multiple displays / windows | Yes |
|
||||
| Hardware acceleration | OpenGL ES, via <ApiLink name="LV_USE_DRAW_NANOVG" /> or <ApiLink name="LV_USE_DRAW_OPENGLES" /> |
|
||||
| Render mode | Full with <ApiLink name="LV_USE_DRAW_OPENGLES" />, 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
|
||||
|
||||
@@ -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.
|
||||
|
||||
<Callout type="info" title="SDL is documented elsewhere">
|
||||
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.
|
||||
</Callout>
|
||||
|
||||
### 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
|
||||
|
||||
<DirectoryIndex />
|
||||
|
||||
@@ -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 <ApiLink name="LV_USE_LIBINPUT" />.
|
||||
|
||||
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`.
|
||||
|
||||
<Callout type="tip">
|
||||
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).
|
||||
</Callout>
|
||||
|
||||
## Usage
|
||||
|
||||
To set up an input device via the libinput driver, all you need to do is call <ApiLink name="lv_libinput_create" /> with the respective device type
|
||||
(<ApiLink name="LV_INDEV_TYPE_POINTER" /> or <ApiLink name="LV_INDEV_TYPE_KEYPAD" />) and device node path (e.g. `/dev/input/event5`).
|
||||
Call <ApiLink name="lv_libinput_create" /> 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 <ApiLink name="LV_INDEV_TYPE_POINTER" />.
|
||||
The type is <ApiLink name="LV_INDEV_TYPE_POINTER" /> or <ApiLink name="LV_INDEV_TYPE_KEYPAD" />. Note that
|
||||
libinput treats touchscreens as absolute pointer devices, so a touchscreen also needs
|
||||
<ApiLink name="LV_INDEV_TYPE_POINTER" />. <ApiLink name="lv_libinput_delete" /> 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 <ApiLink name="lv_libinput_find_dev" />
|
||||
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
|
||||
<ApiLink name="lv_libinput_find_dev" />:
|
||||
|
||||
```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 <ApiLink name="lv_libinput_find_devs" />.
|
||||
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.
|
||||
<ApiLink name="lv_libinput_find_devs" /> returns every device with a given capability, and
|
||||
<ApiLink name="lv_libinput_query_capability" /> 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 | <ApiLink name="lv_libinput_find_dev" /> and <ApiLink name="lv_libinput_find_devs" /> |
|
||||
| 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
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
"pages": [
|
||||
"fbdev",
|
||||
"drm",
|
||||
"opengl_driver",
|
||||
"glfw",
|
||||
"egl",
|
||||
"wayland",
|
||||
"X11",
|
||||
"glfw",
|
||||
"opengl_driver",
|
||||
"egl",
|
||||
"evdev",
|
||||
"libinput"
|
||||
]
|
||||
|
||||
@@ -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 <ApiLink name="LV_USE_OPENGLES" />.
|
||||
|
||||
### 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: <ApiLink name="LV_USE_DRAW_NANOVG" /> (recommended) or <ApiLink name="LV_USE_DRAW_OPENGLES" />. 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 <ApiLink name="lv_opengles_texture_create" />. It
|
||||
allocates the texture for you; <ApiLink name="lv_opengles_texture_get_texture_id" /> 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
|
||||
<ApiLink name="lv_opengles_texture_create_from_texture_id" />.
|
||||
<ApiLink name="lv_opengles_texture_get_from_texture_id" /> looks up the display belonging to a texture id,
|
||||
and <ApiLink name="lv_opengles_texture_reshape" /> 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.
|
||||
<ApiLink name="lv_opengles_render_texture" /> draws a texture into the current framebuffer if you want LVGL
|
||||
to do it, and <ApiLink name="lv_opengles_render_display_texture" /> 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);
|
||||
```
|
||||
|
||||
<ApiLink name="lv_opengles_viewport" /> sets the viewport LVGL renders through, if your application needs
|
||||
LVGL confined to part of the framebuffer.
|
||||
|
||||
## OpenGL Texture Caching Renderer
|
||||
|
||||
<ApiLink name="LV_USE_DRAW_OPENGLES" /> 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.
|
||||
|
||||
<ApiLink name="LV_USE_DRAW_NANOVG" /> 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 <ApiLink name="lv_opengles_texture_reshape" /> |
|
||||
| Runtime color format change | No |
|
||||
| Color formats | Derived from <ApiLink name="LV_COLOR_DEPTH" /> |
|
||||
| Multiple displays / windows | Yes. One display per texture. Windows are not this driver's concern |
|
||||
| Hardware acceleration | OpenGL ES, via <ApiLink name="LV_USE_DRAW_NANOVG" /> or <ApiLink name="LV_USE_DRAW_OPENGLES" /> |
|
||||
| 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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
<Callout type="info" title="Input is separate">
|
||||
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.
|
||||
</Callout>
|
||||
|
||||
## 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:
|
||||
|
||||
@@ -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.
|
||||
<Callout type="warning" title="GLFW and EGL are mutually exclusive">
|
||||
<ApiLink name="LV_USE_GLFW" /> cannot be combined with <ApiLink name="LV_USE_EGL" />
|
||||
</Callout>
|
||||
|
||||
- [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
|
||||
|
||||
Reference in New Issue
Block a user