feat(wayland): support falling back between multiple backends (#10430)

This commit is contained in:
André Costa
2026-08-06 19:29:39 +02:00
committed by GitHub
parent 066c8d9e87
commit 6404de3b90
17 changed files with 712 additions and 536 deletions
+24 -49
View File
@@ -2723,63 +2723,38 @@ config LV_WAYLAND_DIRECT_EXIT
help
LVGL is deinitialized before the application exits.
config LV_WAYLAND_AUTO_BACKEND
bool "Auto-select the Wayland backend (legacy)"
default y
help
Legacy behavior, slated for removal: the backend defaults to SHM and any
LV_WAYLAND_USE_* set directly in lv_conf.h is honored. Disable this and pick
a backend explicitly in the "Rendering backend" choice.
choice
prompt "Rendering backend"
default LV_WAYLAND_BACKEND_SHM
depends on !LV_WAYLAND_AUTO_BACKEND
help
Select the rendering backend used by the Wayland driver.
config LV_WAYLAND_BACKEND_SHM
bool "SHM (Shared Memory)"
select LV_WAYLAND_USE_SHM
help
Default backend, using wl_shm for double-buffered direct rendering.
Compatible with all Wayland compositors; no special hardware required.
config LV_WAYLAND_BACKEND_EGL
bool "EGL (OpenGL ES, hardware-accelerated)"
select LV_WAYLAND_USE_EGL
select LV_USE_OPENGLES
help
Hardware-accelerated rendering via OpenGL ES 2.0 and EGL, compatible
with LVGL 3D/glTF rendering. Requires OpenGL ES 2.0 on the target
hardware and linking with wayland-egl (-lwayland-egl).
config LV_WAYLAND_BACKEND_G2D
bool "G2D (NXP i.MX hardware accelerator)"
select LV_WAYLAND_USE_G2D
select LV_USE_DRAW_G2D
help
Hardware-accelerated 2D rendering via NXP's G2D engine.
Supports NXP i.MX6/i.MX8 platforms with G2D library installed.
endchoice
config LV_WAYLAND_BACKEND
int
default 0 if LV_WAYLAND_BACKEND_SHM
default 1 if LV_WAYLAND_BACKEND_EGL
default 2 if LV_WAYLAND_BACKEND_G2D
config LV_WAYLAND_USE_SHM
bool
bool "SHM (Shared Memory) Backend"
default y
depends on !LV_USE_DRAW_OPENGLES && !LV_USE_DRAW_NANOVG
help
Default backend, using wl_shm for double-buffered direct rendering.
Compatible with all Wayland compositors; no special hardware required.
Unavailable with the OpenGL ES and NanoVG renderers, which can only
render into a GPU surface.
config LV_WAYLAND_USE_EGL
bool
bool "EGL (OpenGL ES, hardware-accelerated) Backend"
default y if LV_USE_DRAW_OPENGLES || LV_USE_DRAW_NANOVG
select LV_USE_EGL
select LV_USE_OPENGLES
select LV_WAYLAND_USE_DMABUF if !LV_USE_DRAW_OPENGLES && !LV_USE_DRAW_NANOVG
help
Hardware-accelerated rendering via OpenGL ES 2.0 and EGL, compatible
with LVGL 3D/glTF rendering. Requires OpenGL ES 2.0 on the target
hardware and linking with wayland-egl (-lwayland-egl).
The only backend available with the OpenGL ES and NanoVG renderers.
config LV_WAYLAND_USE_G2D
bool
bool "G2D (NXP i.MX hardware accelerator)"
depends on !LV_USE_DRAW_OPENGLES && !LV_USE_DRAW_NANOVG
select LV_USE_DRAW_G2D
select LV_WAYLAND_USE_DMABUF
help
Hardware-accelerated 2D rendering via NXP's G2D engine.
Supports NXP i.MX6/i.MX8 platforms with G2D library installed.
Unavailable with the OpenGL ES and NanoVG renderers, which can only
render into a GPU surface.
config LV_WAYLAND_USE_DMABUF
bool
+25 -9
View File
@@ -138,9 +138,10 @@ Set it to one of the predefined GPU/revision combinations:
#### Drivers
Each backend-selecting driver (SDL, Wayland and DRM) now exposes an explicit `LV_<DRIVER>_BACKEND` choice instead of inferring the backend automatically.
No driver infers its rendering backend from the enabled draw units any more. SDL and DRM now expose an explicit `LV_<DRIVER>_BACKEND` choice; Wayland instead lets you
enable each of its backends individually and resolves between them at runtime. See below.
The `LV_<DRIVER>_AUTO_BACKEND` flags (enabled by default) exist purely to ease migration: they let LVGL reproduce the old auto-detected backend so existing projects
Their `LV_<DRIVER>_AUTO_BACKEND` flags (enabled by default) exist purely to ease migration: they let LVGL reproduce the old auto-detected backend so existing projects
don't silently switch to a different backend on update simply because they never set one explicitly. Leaving an `_AUTO_BACKEND` flag enabled triggers a build-time warning.
These flags are not meant to be relied on going forward and will be removed for v10, every project should set its backend explicitly with `LV_<DRIVER>_BACKEND` and then
disable the corresponding `_AUTO_BACKEND` flag to silence the warning.
@@ -172,14 +173,29 @@ Set `LV_LINUX_DRM_AUTO_BACKEND` to 0 and select a backend explicitly with `LV_LI
`LV_USE_LINUX_DRM_GBM_BUFFERS` is no longer a user-facing setting. It is now set internally and automatically enabled whenever the `EGL` or `GBM` backend is selected; it should no longer be set directly in `lv_conf.h`.
- **Wayland** — while `LV_WAYLAND_AUTO_BACKEND` is enabled, the backend is inferred the legacy way: EGL when `LV_USE_OPENGLES` is enabled, otherwise G2D when `LV_USE_DRAW_G2D` is enabled, otherwise SHM.
Set `LV_WAYLAND_AUTO_BACKEND` to 0 and select a backend explicitly with `LV_WAYLAND_BACKEND`:
- **Wayland** — the backend is no longer inferred, and no longer has to be a single one.
| Value | Backend |
|---|---|
| `LV_WAYLAND_BACKEND_SHM` | SHM (Shared Memory) |
| `LV_WAYLAND_BACKEND_EGL` | EGL (OpenGL ES, hardware-accelerated; enable: `LV_USE_OPENGLES`) |
| `LV_WAYLAND_BACKEND_G2D` | G2D (NXP i.MX hardware accelerator; enable: `LV_USE_DRAW_G2D`) |
Previously `LV_WAYLAND_USE_SHM`, `LV_WAYLAND_USE_EGL` and `LV_WAYLAND_USE_G2D` were derived internally and mutually exclusive: enabling `LV_USE_OPENGLES` gave you EGL,
otherwise enabling `LV_USE_G2D` gave you G2D, otherwise you got SHM. Setting them in `lv_conf.h` had no effect.
They are now ordinary options that you set yourself, and **more than one may be enabled at a time**:
| Symbol | Backend | Default |
|---|---|---|
| `LV_WAYLAND_USE_SHM` | SHM (Shared Memory) | on, except with a GPU draw unit |
| `LV_WAYLAND_USE_EGL` | EGL (OpenGL ES, hardware-accelerated; enable: `LV_USE_OPENGLES`) | off; under Kconfig, on with a GPU draw unit |
| `LV_WAYLAND_USE_G2D` | G2D (NXP i.MX hardware accelerator; enable: `LV_USE_DRAW_G2D`) | off |
To reproduce exactly what you had before, enable the one backend the old rules would have picked for your config. `LV_USE_G2D` no longer plays a part in the choice:
it is a deprecated no-op (see [No-op options kept for compatibility](#no-op-options-kept-for-compatibility)) and the G2D backend is now tied to `LV_USE_DRAW_G2D`.
| You had | Backend you got | Add |
|---|---|---|
| `LV_USE_OPENGLES` = 1 | EGL | `LV_WAYLAND_USE_EGL` = 1 (keep `LV_USE_OPENGLES`) |
| `LV_USE_G2D` = 1 | G2D | `LV_WAYLAND_USE_G2D` = 1 and `LV_USE_DRAW_G2D` = 1 |
| neither | SHM | nothing — `LV_WAYLAND_USE_SHM` is on by default |
See the [Wayland driver docs](/integration/embedded_linux/drivers/wayland#runtime-backend-selection) for more information.
- **X11** — render mode (unrelated to backend selection) is now a single value mapped onto the standard `LV_DISPLAY_RENDER_MODE_*` constants:
File diff suppressed because it is too large Load Diff
+41 -68
View File
@@ -111,11 +111,6 @@
#define LV_SDL_MOUSEWHEEL_MODE_ENCODER 0
#define LV_SDL_MOUSEWHEEL_MODE_CROWN 1
/* Rendering backend */
#define LV_WAYLAND_BACKEND_SHM 0
#define LV_WAYLAND_BACKEND_EGL 1
#define LV_WAYLAND_BACKEND_G2D 2
/* Log behavior on LV_CHECK_ARG failure */
#define LV_CHECK_ARG_LOG_MODE_NONE 0
#define LV_CHECK_ARG_LOG_MODE_MINIMAL 1
@@ -3544,23 +3539,31 @@
#endif
#endif
#ifndef LV_WAYLAND_AUTO_BACKEND
#ifndef LV_WAYLAND_USE_SHM
#ifdef LV_KCONFIG_PRESENT
#ifdef CONFIG_LV_WAYLAND_AUTO_BACKEND
#define LV_WAYLAND_AUTO_BACKEND CONFIG_LV_WAYLAND_AUTO_BACKEND
#ifdef CONFIG_LV_WAYLAND_USE_SHM
#define LV_WAYLAND_USE_SHM CONFIG_LV_WAYLAND_USE_SHM
#else
#define LV_WAYLAND_AUTO_BACKEND 0
#define LV_WAYLAND_USE_SHM 0
#endif
#else
#define LV_WAYLAND_AUTO_BACKEND LV_USE_WAYLAND
#define LV_WAYLAND_USE_SHM !LV_USE_DRAW_OPENGLES && !LV_USE_DRAW_NANOVG && LV_USE_WAYLAND
#endif
#endif
#ifndef LV_WAYLAND_BACKEND
#ifdef CONFIG_LV_WAYLAND_BACKEND
#define LV_WAYLAND_BACKEND CONFIG_LV_WAYLAND_BACKEND
#ifndef LV_WAYLAND_USE_EGL
#ifdef CONFIG_LV_WAYLAND_USE_EGL
#define LV_WAYLAND_USE_EGL CONFIG_LV_WAYLAND_USE_EGL
#else
#define LV_WAYLAND_BACKEND LV_WAYLAND_BACKEND_SHM
#define LV_WAYLAND_USE_EGL 0
#endif
#endif
#ifndef LV_WAYLAND_USE_G2D
#ifdef CONFIG_LV_WAYLAND_USE_G2D
#define LV_WAYLAND_USE_G2D CONFIG_LV_WAYLAND_USE_G2D
#else
#define LV_WAYLAND_USE_G2D 0
#endif
#endif
@@ -4756,28 +4759,14 @@
#endif
#endif /*LV_USE_SDL && LV_SDL_AUTO_BACKEND*/
/* Wayland never inferred its backend from LV_USE_OPENGLES; the legacy interface
* was setting LV_WAYLAND_USE_* directly. While LV_WAYLAND_AUTO_BACKEND is set we
* honor any such define, default to SHM, and keep the three mutually exclusive.
* The #warning fires only if a legacy LV_WAYLAND_USE_* was set by hand. */
#if LV_USE_WAYLAND && LV_WAYLAND_AUTO_BACKEND
#if defined(LV_WAYLAND_USE_EGL) || defined(LV_WAYLAND_USE_G2D) || defined(LV_WAYLAND_USE_SHM)
#warning Setting LV_WAYLAND_USE_* directly is deprecated and will be removed in a future release. Set LV_WAYLAND_AUTO_BACKEND to 0 and select a backend with LV_WAYLAND_BACKEND.
#endif
#ifndef LV_WAYLAND_USE_EGL
#define LV_WAYLAND_USE_EGL 0
#endif
#ifndef LV_WAYLAND_USE_G2D
#define LV_WAYLAND_USE_G2D 0
#endif
#ifndef LV_WAYLAND_USE_SHM
#if LV_WAYLAND_USE_EGL || LV_WAYLAND_USE_G2D
#define LV_WAYLAND_USE_SHM 0
#else
#define LV_WAYLAND_USE_SHM 1
#endif
#endif
#endif /*LV_USE_WAYLAND && LV_WAYLAND_AUTO_BACKEND*/
/* The Wayland backends used to be mutually exclusive: LV_WAYLAND_BACKEND picked
* exactly one of them, and the deprecated LV_WAYLAND_AUTO_BACKEND kept the older
* behavior of setting LV_WAYLAND_USE_* by hand. Several backends can now be
* enabled at once and the driver probes them at runtime, so both symbols are
* gone. Warn rather than let an old lv_conf.h silently fall back to SHM. */
#if LV_USE_WAYLAND && defined(LV_WAYLAND_BACKEND)
#warning LV_WAYLAND_BACKEND is deprecated and has no effect. Enable each backend you want with LV_WAYLAND_USE_SHM, LV_WAYLAND_USE_EGL and LV_WAYLAND_USE_G2D instead; the driver initializes the first one that works.
#endif /*LV_USE_WAYLAND && defined(LV_WAYLAND_BACKEND) */
#if defined(LV_ASSERT_HANDLER_INCLUDE) && !LV_DISABLE_ASSERT_HANDLER_INCLUDE_WARNING
#warning "LV_ASSERT_HANDLER_INCLUDE is deprecated and will be removed in a future release. Use LV_ASSERT_CUSTOM_INCLUDE and define LV_ASSERT_HANDLER inside. To suppress this warning, remove LV_ASSERT_HANDLER_INCLUDE or enable LV_DISABLE_ASSERT_HANDLER_INCLUDE_WARNING."
@@ -4902,27 +4891,11 @@
#endif
#endif
#ifndef LV_WAYLAND_USE_SHM
#if ((LV_WAYLAND_BACKEND == LV_WAYLAND_BACKEND_SHM) && (LV_USE_WAYLAND))
#define LV_WAYLAND_USE_SHM 1
#ifndef LV_WAYLAND_USE_DMABUF
#if (((LV_WAYLAND_USE_EGL && !LV_USE_DRAW_OPENGLES && !LV_USE_DRAW_NANOVG && LV_USE_WAYLAND) || (LV_WAYLAND_USE_G2D && !LV_USE_DRAW_OPENGLES && !LV_USE_DRAW_NANOVG && LV_USE_WAYLAND)) && (LV_USE_WAYLAND))
#define LV_WAYLAND_USE_DMABUF 1
#else
#define LV_WAYLAND_USE_SHM 0
#endif
#endif
#ifndef LV_WAYLAND_USE_EGL
#if ((LV_WAYLAND_BACKEND == LV_WAYLAND_BACKEND_EGL) && (LV_USE_WAYLAND))
#define LV_WAYLAND_USE_EGL 1
#else
#define LV_WAYLAND_USE_EGL 0
#endif
#endif
#ifndef LV_WAYLAND_USE_G2D
#if ((LV_WAYLAND_BACKEND == LV_WAYLAND_BACKEND_G2D) && (LV_USE_WAYLAND))
#define LV_WAYLAND_USE_G2D 1
#else
#define LV_WAYLAND_USE_G2D 0
#define LV_WAYLAND_USE_DMABUF 0
#endif
#endif
@@ -4934,14 +4907,6 @@
#endif
#endif
#ifndef LV_WAYLAND_USE_DMABUF
#if (((LV_WAYLAND_USE_EGL && !LV_USE_DRAW_OPENGLES && !LV_USE_DRAW_NANOVG && LV_USE_WAYLAND) || (LV_WAYLAND_USE_G2D && LV_USE_WAYLAND)) && (LV_USE_WAYLAND))
#define LV_WAYLAND_USE_DMABUF 1
#else
#define LV_WAYLAND_USE_DMABUF 0
#endif
#endif
/* Optional user headers (LV_*_USE_CUSTOM_INCLUDE) overriding config macros. */
#if LV_OS_USE_CUSTOM_INCLUDE
#include LV_OS_CUSTOM_INCLUDE
@@ -5154,8 +5119,8 @@ LV_EXPORT_CONST_INT(LV_DRAW_BUF_ALIGN);
#error "LV_USE_DRAW_DMA2D_INTERRUPT requires LV_USE_DRAW_DMA2D (Kconfig depends on)"
#endif
#if (LV_WAYLAND_BACKEND == LV_WAYLAND_BACKEND_G2D) && !LV_USE_DRAW_G2D
#error "LV_USE_DRAW_G2D must be enabled: Kconfig selects it from LV_WAYLAND_BACKEND == LV_WAYLAND_BACKEND_G2D"
#if (LV_WAYLAND_USE_G2D && !LV_USE_DRAW_OPENGLES && !LV_USE_DRAW_NANOVG && LV_USE_WAYLAND) && !LV_USE_DRAW_G2D
#error "LV_USE_DRAW_G2D must be enabled: Kconfig selects it from LV_WAYLAND_USE_G2D && !LV_USE_DRAW_OPENGLES && !LV_USE_DRAW_NANOVG && LV_USE_WAYLAND"
#endif
#if LV_USE_G2D_ASSERT && !(LV_USE_DRAW_G2D && LV_USE_DRAW_G2D)
@@ -5318,8 +5283,8 @@ LV_EXPORT_CONST_INT(LV_DRAW_BUF_ALIGN);
#error "LV_USE_NUTTX_TRACE_FILE requires LV_USE_PROFILER_BUILTIN && LV_USE_NUTTX (Kconfig depends on)"
#endif
#if (LV_USE_DRAW_NANOVG || LV_USE_DRAW_OPENGLES || LV_LINUX_DRM_BACKEND == LV_LINUX_DRM_BACKEND_EGL || (LV_USE_GLFW && !LV_USE_EGL) || LV_WAYLAND_BACKEND == LV_WAYLAND_BACKEND_EGL) && !LV_USE_OPENGLES
#error "LV_USE_OPENGLES must be enabled: Kconfig selects it from LV_USE_DRAW_NANOVG || LV_USE_DRAW_OPENGLES || LV_LINUX_DRM_BACKEND == LV_LINUX_DRM_BACKEND_EGL || (LV_USE_GLFW && !LV_USE_EGL) || LV_WAYLAND_BACKEND == LV_WAYLAND_BACKEND_EGL"
#if (LV_USE_DRAW_NANOVG || LV_USE_DRAW_OPENGLES || LV_LINUX_DRM_BACKEND == LV_LINUX_DRM_BACKEND_EGL || (LV_USE_GLFW && !LV_USE_EGL) || (LV_WAYLAND_USE_EGL && LV_USE_WAYLAND)) && !LV_USE_OPENGLES
#error "LV_USE_OPENGLES must be enabled: Kconfig selects it from LV_USE_DRAW_NANOVG || LV_USE_DRAW_OPENGLES || LV_LINUX_DRM_BACKEND == LV_LINUX_DRM_BACKEND_EGL || (LV_USE_GLFW && !LV_USE_EGL) || (LV_WAYLAND_USE_EGL && LV_USE_WAYLAND)"
#endif
#if LV_USE_OPENGLES_DEBUG && !(LV_USE_OPENGLES)
@@ -5338,6 +5303,14 @@ LV_EXPORT_CONST_INT(LV_DRAW_BUF_ALIGN);
#error "LV_UEFI_USE_MEMORY_SERVICES requires LV_USE_UEFI (Kconfig depends on)"
#endif
#if LV_WAYLAND_USE_EGL && !(LV_USE_WAYLAND)
#error "LV_WAYLAND_USE_EGL requires LV_USE_WAYLAND (Kconfig depends on)"
#endif
#if LV_WAYLAND_USE_G2D && !(!LV_USE_DRAW_OPENGLES && !LV_USE_DRAW_NANOVG && LV_USE_WAYLAND)
#error "LV_WAYLAND_USE_G2D requires !LV_USE_DRAW_OPENGLES && !LV_USE_DRAW_NANOVG && LV_USE_WAYLAND (Kconfig depends on)"
#endif
#if LV_USE_WINDOWS && !(LV_USE_OS == LV_OS_WINDOWS)
#error "LV_USE_WINDOWS requires LV_USE_OS == LV_OS_WINDOWS (Kconfig depends on)"
#endif
+30 -10
View File
@@ -1769,20 +1769,40 @@
/** LVGL is deinitialized before the application exits. */
#define LV_WAYLAND_DIRECT_EXIT 1
/** Legacy behavior, slated for removal: the backend defaults to SHM and any
* LV_WAYLAND_USE_* set directly in lv_conf.h is honored. Disable this and pick
* a backend explicitly in the "Rendering backend" choice.
#if !LV_USE_DRAW_OPENGLES
#if !LV_USE_DRAW_NANOVG
/** Default backend, using wl_shm for double-buffered direct rendering.
* Compatible with all Wayland compositors; no special hardware required.
* Unavailable with the OpenGL ES and NanoVG renderers, which can only
* render into a GPU surface.
*/
#define LV_WAYLAND_AUTO_BACKEND 1
#define LV_WAYLAND_USE_SHM 1
/** Select the rendering backend used by the Wayland driver.
* Possible values:
* - LV_WAYLAND_BACKEND_SHM: SHM (Shared Memory)
* - LV_WAYLAND_BACKEND_EGL: EGL (OpenGL ES, hardware-accelerated) (enable: LV_USE_OPENGLES)
* - LV_WAYLAND_BACKEND_G2D: G2D (NXP i.MX hardware accelerator) (enable: LV_USE_DRAW_G2D)
#endif /*!LV_USE_DRAW_NANOVG*/
#endif /*!LV_USE_DRAW_OPENGLES*/
/** Hardware-accelerated rendering via OpenGL ES 2.0 and EGL, compatible
* with LVGL 3D/glTF rendering. Requires OpenGL ES 2.0 on the target
* hardware and linking with wayland-egl (-lwayland-egl).
* The only backend available with the OpenGL ES and NanoVG renderers.
*
* Enable: LV_USE_OPENGLES
*/
#define LV_WAYLAND_BACKEND LV_WAYLAND_BACKEND_SHM
#define LV_WAYLAND_USE_EGL 0
#if !LV_USE_DRAW_OPENGLES
#if !LV_USE_DRAW_NANOVG
/** Hardware-accelerated 2D rendering via NXP's G2D engine.
* Supports NXP i.MX6/i.MX8 platforms with G2D library installed.
* Unavailable with the OpenGL ES and NanoVG renderers, which can only
* render into a GPU surface.
*
* Enable: LV_USE_DRAW_G2D
*/
#define LV_WAYLAND_USE_G2D 0
#endif /*!LV_USE_DRAW_NANOVG*/
#endif /*!LV_USE_DRAW_OPENGLES*/
#endif /*LV_USE_WAYLAND*/
#if LV_USE_OS == LV_OS_WINDOWS
+8 -22
View File
@@ -267,28 +267,14 @@ INTERNAL_COMPATIBILITY_BLOCK = r"""
#endif
#endif /*LV_USE_SDL && LV_SDL_AUTO_BACKEND*/
/* Wayland never inferred its backend from LV_USE_OPENGLES; the legacy interface
* was setting LV_WAYLAND_USE_* directly. While LV_WAYLAND_AUTO_BACKEND is set we
* honor any such define, default to SHM, and keep the three mutually exclusive.
* The #warning fires only if a legacy LV_WAYLAND_USE_* was set by hand. */
#if LV_USE_WAYLAND && LV_WAYLAND_AUTO_BACKEND
#if defined(LV_WAYLAND_USE_EGL) || defined(LV_WAYLAND_USE_G2D) || defined(LV_WAYLAND_USE_SHM)
#warning Setting LV_WAYLAND_USE_* directly is deprecated and will be removed in a future release. Set LV_WAYLAND_AUTO_BACKEND to 0 and select a backend with LV_WAYLAND_BACKEND.
#endif
#ifndef LV_WAYLAND_USE_EGL
#define LV_WAYLAND_USE_EGL 0
#endif
#ifndef LV_WAYLAND_USE_G2D
#define LV_WAYLAND_USE_G2D 0
#endif
#ifndef LV_WAYLAND_USE_SHM
#if LV_WAYLAND_USE_EGL || LV_WAYLAND_USE_G2D
#define LV_WAYLAND_USE_SHM 0
#else
#define LV_WAYLAND_USE_SHM 1
#endif
#endif
#endif /*LV_USE_WAYLAND && LV_WAYLAND_AUTO_BACKEND*/
/* The Wayland backends used to be mutually exclusive: LV_WAYLAND_BACKEND picked
* exactly one of them, and the deprecated LV_WAYLAND_AUTO_BACKEND kept the older
* behavior of setting LV_WAYLAND_USE_* by hand. Several backends can now be
* enabled at once and the driver probes them at runtime, so both symbols are
* gone. Warn rather than let an old lv_conf.h silently fall back to SHM. */
#if LV_USE_WAYLAND && defined(LV_WAYLAND_BACKEND)
#warning LV_WAYLAND_BACKEND is deprecated and has no effect. Enable each backend you want with LV_WAYLAND_USE_SHM, LV_WAYLAND_USE_EGL and LV_WAYLAND_USE_G2D instead; the driver initializes the first one that works.
#endif /*LV_USE_WAYLAND && defined(LV_WAYLAND_BACKEND) */
#if defined(LV_ASSERT_HANDLER_INCLUDE) && !LV_DISABLE_ASSERT_HANDLER_INCLUDE_WARNING
#warning "LV_ASSERT_HANDLER_INCLUDE is deprecated and will be removed in a future release. Use LV_ASSERT_CUSTOM_INCLUDE and define LV_ASSERT_HANDLER inside. To suppress this warning, remove LV_ASSERT_HANDLER_INCLUDE or enable LV_DISABLE_ASSERT_HANDLER_INCLUDE_WARNING."
+24 -49
View File
@@ -12,63 +12,38 @@ config LV_WAYLAND_DIRECT_EXIT
help
LVGL is deinitialized before the application exits.
config LV_WAYLAND_AUTO_BACKEND
bool "Auto-select the Wayland backend (legacy)"
default y
help
Legacy behavior, slated for removal: the backend defaults to SHM and any
LV_WAYLAND_USE_* set directly in lv_conf.h is honored. Disable this and pick
a backend explicitly in the "Rendering backend" choice.
choice
prompt "Rendering backend"
default LV_WAYLAND_BACKEND_SHM
depends on !LV_WAYLAND_AUTO_BACKEND
help
Select the rendering backend used by the Wayland driver.
config LV_WAYLAND_BACKEND_SHM
bool "SHM (Shared Memory)"
select LV_WAYLAND_USE_SHM
help
Default backend, using wl_shm for double-buffered direct rendering.
Compatible with all Wayland compositors; no special hardware required.
config LV_WAYLAND_BACKEND_EGL
bool "EGL (OpenGL ES, hardware-accelerated)"
select LV_WAYLAND_USE_EGL
select LV_USE_OPENGLES
help
Hardware-accelerated rendering via OpenGL ES 2.0 and EGL, compatible
with LVGL 3D/glTF rendering. Requires OpenGL ES 2.0 on the target
hardware and linking with wayland-egl (-lwayland-egl).
config LV_WAYLAND_BACKEND_G2D
bool "G2D (NXP i.MX hardware accelerator)"
select LV_WAYLAND_USE_G2D
select LV_USE_DRAW_G2D
help
Hardware-accelerated 2D rendering via NXP's G2D engine.
Supports NXP i.MX6/i.MX8 platforms with G2D library installed.
endchoice
config LV_WAYLAND_BACKEND
int
default 0 if LV_WAYLAND_BACKEND_SHM
default 1 if LV_WAYLAND_BACKEND_EGL
default 2 if LV_WAYLAND_BACKEND_G2D
config LV_WAYLAND_USE_SHM
bool
bool "SHM (Shared Memory) Backend"
default y
depends on !LV_USE_DRAW_OPENGLES && !LV_USE_DRAW_NANOVG
help
Default backend, using wl_shm for double-buffered direct rendering.
Compatible with all Wayland compositors; no special hardware required.
Unavailable with the OpenGL ES and NanoVG renderers, which can only
render into a GPU surface.
config LV_WAYLAND_USE_EGL
bool
bool "EGL (OpenGL ES, hardware-accelerated) Backend"
default y if LV_USE_DRAW_OPENGLES || LV_USE_DRAW_NANOVG
select LV_USE_EGL
select LV_USE_OPENGLES
select LV_WAYLAND_USE_DMABUF if !LV_USE_DRAW_OPENGLES && !LV_USE_DRAW_NANOVG
help
Hardware-accelerated rendering via OpenGL ES 2.0 and EGL, compatible
with LVGL 3D/glTF rendering. Requires OpenGL ES 2.0 on the target
hardware and linking with wayland-egl (-lwayland-egl).
The only backend available with the OpenGL ES and NanoVG renderers.
config LV_WAYLAND_USE_G2D
bool
bool "G2D (NXP i.MX hardware accelerator)"
depends on !LV_USE_DRAW_OPENGLES && !LV_USE_DRAW_NANOVG
select LV_USE_DRAW_G2D
select LV_WAYLAND_USE_DMABUF
help
Hardware-accelerated 2D rendering via NXP's G2D engine.
Supports NXP i.MX6/i.MX8 platforms with G2D library installed.
Unavailable with the OpenGL ES and NanoVG renderers, which can only
render into a GPU surface.
config LV_WAYLAND_USE_DMABUF
bool
+4 -4
View File
@@ -24,6 +24,7 @@
#include LV_STDDEF_INCLUDE
#include LV_STDINT_INCLUDE
#include LV_STDBOOL_INCLUDE
#include "lv_wayland_private.h"
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
@@ -124,8 +125,7 @@ lv_result_t lv_wayland_init(void)
LV_LOG_ERROR("failed to connect to Wayland server");
return LV_RESULT_INVALID;
}
lv_wl_ctx.backend_data = wl_backend_ops.init();
lv_wayland_backend_init_all();
/* Add registry listener and wait for registry reception */
lv_wl_ctx.wl_registry = wl_display_get_registry(lv_wl_ctx.wl_display);
@@ -160,7 +160,7 @@ void lv_wayland_deinit(void)
lv_wayland_xdg_deinit();
if(is_wayland_initialized) {
wl_backend_ops.deinit(lv_wl_ctx.backend_data);
lv_wayland_backend_deinit_all();
}
if(lv_wl_ctx.seat.wl_seat) {
@@ -330,7 +330,7 @@ static void handle_global(void * data, struct wl_registry * registry, uint32_t n
}
}
wl_backend_ops.global_handler(lv_wl_ctx.backend_data, registry, name, interface, version);
lv_wayland_backend_global_handler(registry, name, interface, version);
}
static void handle_global_remove(void * data, struct wl_registry * registry, uint32_t name)
+188
View File
@@ -0,0 +1,188 @@
/**
* @file lv_wayland_backend.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_wayland_backend_private.h"
#if LV_USE_WAYLAND
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
#if LV_WAYLAND_USE_EGL
extern const lv_wayland_backend_ops_t wl_egl_ops;
extern const lv_wayland_backend_display_ops_t wl_egl_display_ops;
#endif /*LV_WAYLAND_USE_EGL*/
#if LV_WAYLAND_USE_G2D
extern const lv_wayland_backend_ops_t wl_g2d_ops;
extern const lv_wayland_backend_display_ops_t wl_g2d_display_ops;
#endif /*LV_WAYLAND_USE_G2D*/
#if LV_WAYLAND_USE_SHM
extern const lv_wayland_backend_ops_t wl_shm_ops;
extern const lv_wayland_backend_display_ops_t wl_shm_display_ops;
#endif /*LV_WAYLAND_USE_SHM*/
#if !LV_WAYLAND_USE_EGL && !LV_WAYLAND_USE_G2D && !LV_WAYLAND_USE_SHM
#error "At least one wayland backend must be selected. Note that with LV_USE_DRAW_OPENGLES or LV_USE_DRAW_NANOVG only LV_WAYLAND_USE_EGL is available."
#endif
/* The SHM and G2D backends hand a CPU buffer to LVGL, which the OpenGL ES and
* NanoVG draw units cannot render into: they would claim the draw tasks and
* leave the buffer untouched. Kconfig keeps this out of reach, catch an
* lv_conf.h that sets the flags by hand. */
#if (LV_WAYLAND_USE_SHM || LV_WAYLAND_USE_G2D) && (LV_USE_DRAW_OPENGLES || LV_USE_DRAW_NANOVG)
#error "LV_WAYLAND_USE_SHM and LV_WAYLAND_USE_G2D are not compatible with LV_USE_DRAW_OPENGLES or LV_USE_DRAW_NANOVG. Use LV_WAYLAND_USE_EGL instead."
#endif
/* Ordered by preference: the first backend that can initialize a display wins. */
static struct {
const char * name;
const lv_wayland_backend_ops_t * ops;
const lv_wayland_backend_display_ops_t * display_ops;
void * backend_data;
bool available;
} backends[] = {
#if LV_WAYLAND_USE_EGL
{"EGL", &wl_egl_ops, &wl_egl_display_ops, NULL, false},
#endif /*LV_WAYLAND_USE_EGL*/
#if LV_WAYLAND_USE_G2D
{"G2D", &wl_g2d_ops, &wl_g2d_display_ops, NULL, false},
#endif /*LV_WAYLAND_USE_G2D*/
#if LV_WAYLAND_USE_SHM
{"SHM", &wl_shm_ops, &wl_shm_display_ops, NULL, false},
#endif /*LV_WAYLAND_USE_SHM*/
};
static const size_t backend_count = (sizeof(backends) / sizeof(backends[0]));
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_wayland_backend_init_all(void)
{
for(size_t i = 0; i < backend_count; ++i) {
LV_LOG_INFO("Initializing '%s' wayland backend", backends[i].name);
backends[i].backend_data = NULL;
backends[i].available = (backends[i].ops->init(&backends[i].backend_data) == LV_RESULT_OK);
if(!backends[i].available) {
LV_LOG_WARN("Failed to initialize the '%s' wayland backend, it will not be used", backends[i].name);
backends[i].backend_data = NULL;
}
}
}
void lv_wayland_backend_deinit_all(void)
{
for(size_t i = 0; i < backend_count; ++i) {
if(!backends[i].available) {
continue;
}
LV_LOG_INFO("Deinitializing '%s' wayland backend", backends[i].name);
backends[i].ops->deinit(backends[i].backend_data);
backends[i].backend_data = NULL;
backends[i].available = false;
}
}
void lv_wayland_backend_global_handler(struct wl_registry * registry, uint32_t name,
const char * interface, uint32_t version)
{
LV_ASSERT(registry != NULL);
LV_ASSERT(interface != NULL);
for(size_t i = 0; i < backend_count; ++i) {
if(!backends[i].available) {
continue;
}
backends[i].ops->global_handler(backends[i].backend_data, registry, name, interface, version);
}
}
lv_result_t lv_wayland_backend_init_display(lv_wayland_backend_display_data_t * backend_ddata,
lv_display_t * display,
int32_t width,
int32_t height)
{
LV_ASSERT(backend_ddata != NULL);
LV_ASSERT(display != NULL);
lv_memzero(backend_ddata, sizeof(*backend_ddata));
/* Every attempt gets the display in the same state: a backend configures it
* before it knows whether it will succeed, so restore what a failed attempt
* may have changed. */
const lv_color_format_t cf = lv_display_get_color_format(display);
for(size_t i = 0; i < backend_count; ++i) {
if(!backends[i].available) {
continue;
}
void * display_data = backends[i].display_ops->init_display(backends[i].backend_data, display, width, height);
if(!display_data) {
LV_LOG_WARN("Failed to initialize a display with the '%s' wayland backend", backends[i].name);
/* A backend may publish its display data through
* lv_wayland_set_backend_display_data() before bailing out; drop the
* pointer it left behind, it is freed by now. */
backend_ddata->display_data = NULL;
lv_display_set_color_format(display, cf);
continue;
}
backend_ddata->ops = backends[i].display_ops;
backend_ddata->backend_data = backends[i].backend_data;
backend_ddata->display_data = display_data;
LV_LOG_INFO("Initialized display with '%s' wayland backend", backends[i].name);
return LV_RESULT_OK;
}
return LV_RESULT_INVALID;
}
void lv_wayland_backend_deinit_display(lv_wayland_backend_display_data_t * backend_ddata,
lv_display_t * display)
{
LV_ASSERT(backend_ddata != NULL);
LV_ASSERT(display != NULL);
if(!backend_ddata->ops) {
/* No backend ever took this display */
return;
}
backend_ddata->ops->deinit_display(backend_ddata->backend_data, display);
lv_memzero(backend_ddata, sizeof(*backend_ddata));
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_WAYLAND*/
+40 -22
View File
@@ -101,7 +101,7 @@ typedef struct {
* STATIC PROTOTYPES
**********************/
static void * wl_egl_init(void);
static lv_result_t wl_egl_init(void ** backend_data);
static void wl_egl_deinit(void * backend_ctx);
static void * wl_egl_init_display(void * backend_ctx, lv_display_t * display, int32_t width, int32_t height);
static void * wl_egl_resize_display(void * backend_ctx, lv_display_t * display);
@@ -144,14 +144,22 @@ static void delete_buffer(lv_opengles_egl_t * egl_ctx, lv_wl_buffer_t * buffer);
* STATIC VARIABLES
**********************/
/* TODO: the opengl driver doesn't support multiple instances
* so we can only handle one display per EGL instance
* WIP: https://github.com/lvgl/lvgl/pull/9854 */
static bool has_display;
static const struct wl_callback_listener frame_listener = {
.done = frame_done,
};
const lv_wayland_backend_ops_t wl_backend_ops = {
const lv_wayland_backend_ops_t wl_egl_ops = {
.init = wl_egl_init,
.deinit = wl_egl_deinit,
.global_handler = wl_egl_global_handler,
};
const lv_wayland_backend_display_ops_t wl_egl_display_ops = {
.init_display = wl_egl_init_display,
.deinit_display = wl_egl_deinit_display,
.resize_display = wl_egl_resize_display,
@@ -184,14 +192,17 @@ static void frame_done(void * data, struct wl_callback * callback, uint32_t time
lv_display_flush_ready(display);
}
static void * wl_egl_init(void)
static lv_result_t wl_egl_init(void ** backend_data)
{
has_display = false;
#if LV_WL_EGL_DMABUF_ENABLED
lv_wayland_dmabuf_ctx_init(&ctx);
return &ctx;
*backend_data = &ctx;
#else
return NULL;
/* Without the DMA-BUF fast-path the backend keeps no global state */
*backend_data = NULL;
#endif
return LV_RESULT_OK;
}
static void wl_egl_deinit(void * backend_ctx)
@@ -208,7 +219,7 @@ static lv_wl_egl_display_data_t * egl_create_display_data(lv_display_t * display
{
lv_wl_egl_display_data_t * ddata = lv_zalloc(sizeof(*ddata));
if(!ddata) {
LV_LOG_ERROR("Failed to allocate data for display");
LV_LOG_WARN("Failed to allocate data for display");
return NULL;
}
@@ -224,7 +235,7 @@ static lv_wl_egl_display_data_t * egl_create_display_data(lv_display_t * display
lv_egl_interface_t egl_interface = wl_egl_get_interface(display);
ddata->egl_ctx = lv_opengles_egl_context_create(&egl_interface);
if(!ddata->egl_ctx) {
LV_LOG_ERROR("Failed to create EGL context");
LV_LOG_WARN("Failed to create EGL context");
goto egl_ctx_err;
}
@@ -244,7 +255,7 @@ static lv_wl_egl_display_data_t * egl_create_display_data(lv_display_t * display
/*Initialize the draw buffers and texture*/
lv_result_t res = lv_opengles_texture_reshape(&ddata->texture, display, width, height);
if(res != LV_RESULT_OK) {
LV_LOG_ERROR("Failed to create draw buffers");
LV_LOG_WARN("Failed to create draw buffers");
goto texture_err;
}
return ddata;
@@ -360,7 +371,7 @@ static void egl_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t *
* full-screen quad pass and no eglSwapBuffers copy. */
lv_wl_buffer_t * buf = get_next_buffer(ddata);
if(!buf) {
LV_LOG_ERROR("Failed to acquire a wayland window body buffer");
LV_LOG_WARN("Failed to acquire a wayland window body buffer");
lv_display_flush_ready(disp);
return;
}
@@ -434,9 +445,13 @@ static void egl_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t *
static void * wl_egl_init_display(void * backend_ctx, lv_display_t * display, int32_t width, int32_t height)
{
LV_UNUSED(backend_ctx);
if(has_display) {
LV_LOG_INFO("The EGL backend can only handle one display at a time");
return NULL;
}
lv_wl_egl_display_data_t * ddata = egl_create_display_data(display, width, height);
if(!ddata) {
LV_LOG_ERROR("Failed to create display data");
LV_LOG_WARN("Failed to create display data");
return NULL;
}
@@ -451,7 +466,7 @@ static void * wl_egl_init_display(void * backend_ctx, lv_display_t * display, in
LV_ASSERT_MALLOC(buf1);
LV_ASSERT_MALLOC(buf2);
if(!buf1 || !buf2) {
LV_LOG_ERROR("Failed to allocate display buffer");
LV_LOG_WARN("Failed to allocate display buffer");
lv_free(buf1);
lv_free(buf2);
egl_destroy_display_data(ddata);
@@ -464,6 +479,7 @@ static void * wl_egl_init_display(void * backend_ctx, lv_display_t * display, in
lv_display_set_buffers(display, buf1, buf2, buf_size, LV_DISPLAY_RENDER_MODE_DIRECT);
lv_display_set_flush_cb(display, egl_flush_cb);
lv_display_set_flush_wait_cb(display, flush_wait_cb);
has_display = true;
return ddata;
}
#endif /*LV_WL_EGL_DMABUF_ENABLED*/
@@ -472,6 +488,7 @@ static void * wl_egl_init_display(void * backend_ctx, lv_display_t * display, in
lv_display_set_flush_wait_cb(display, flush_wait_cb);
lv_display_set_render_mode(display, LV_USE_DRAW_NANOVG ? LV_DISPLAY_RENDER_MODE_FULL : LV_DISPLAY_RENDER_MODE_DIRECT);
has_display = true;
return ddata;
}
@@ -547,6 +564,7 @@ static void wl_egl_deinit_display(void * backend_ctx, lv_display_t * display)
#endif
egl_destroy_display_data(ddata);
has_display = false;
}
static void wl_egl_global_handler(void * backend_ctx, struct wl_registry * registry, uint32_t name,
@@ -629,7 +647,7 @@ static void * wl_egl_create_window(void * driver_data, const lv_egl_native_windo
lv_wl_egl_display_data_t * ddata = lv_wayland_get_backend_display_data(display);
if(!wl_surface) {
LV_LOG_ERROR("Failed to get Wayland surface");
LV_LOG_WARN("Failed to get Wayland surface");
return NULL;
}
@@ -637,7 +655,7 @@ static void * wl_egl_create_window(void * driver_data, const lv_egl_native_windo
lv_display_get_horizontal_resolution(display),
lv_display_get_vertical_resolution(display));
if(!ddata->egl_window) {
LV_LOG_ERROR("Failed to create wl_egl_window");
LV_LOG_WARN("Failed to create wl_egl_window");
return NULL;
}
@@ -704,13 +722,13 @@ static bool egl_dmabuf_setup(lv_wl_egl_display_data_t * ddata, lv_display_t * di
ddata->drm_fd = open_drm_device();
if(ddata->drm_fd < 0) {
LV_LOG_ERROR("Failed to open DRM device");
LV_LOG_WARN("Failed to open DRM device");
return false;
}
ddata->gbm_device = gbm_create_device(ddata->drm_fd);
if(!ddata->gbm_device) {
LV_LOG_ERROR("Failed to create GBM device");
LV_LOG_WARN("Failed to create GBM device");
close(ddata->drm_fd);
ddata->drm_fd = -1;
return false;
@@ -740,7 +758,7 @@ static bool egl_dmabuf_setup(lv_wl_egl_display_data_t * ddata, lv_display_t * di
}
if(!ok) {
LV_LOG_ERROR("DMA-BUF creation failed");
LV_LOG_WARN("DMA-BUF creation failed");
egl_dmabuf_teardown(ddata);
return false;
}
@@ -876,7 +894,7 @@ static void load_egl_extensions(void)
eglGetProcAddress("glEGLImageTargetTexture2DOES");
if(!glEGLImageTargetTexture2DOES) {
LV_LOG_ERROR("Failed to load glEGLImageTargetTexture2DOES extension");
LV_LOG_WARN("Failed to load glEGLImageTargetTexture2DOES extension");
}
else {
LV_LOG_INFO("Loaded glEGLImageTargetTexture2DOES extension");
@@ -890,7 +908,7 @@ static int open_drm_device(void)
num_devices = drmGetDevices2(0, devices, 64);
if(num_devices < 0) {
LV_LOG_ERROR("drmGetDevices2 failed: %s", strerror(-num_devices));
LV_LOG_WARN("drmGetDevices2 failed: %s", strerror(-num_devices));
return -1;
}
@@ -909,7 +927,7 @@ static int open_drm_device(void)
drmFreeDevices(devices, num_devices);
if(fd < 0) {
LV_LOG_ERROR("Failed to open DRM device");
LV_LOG_WARN("Failed to open DRM device");
}
return fd;
@@ -927,7 +945,7 @@ static bool init_buffer(lv_wayland_dmabuf_ctx_t * dmabuf_ctx, lv_wl_buffer_t * b
buffer->bo = gbm_bo_create(ddata->gbm_device, width, height, gbm_cf, gbm_flags);
if(!buffer->bo) {
LV_LOG_ERROR("Failed to create GBM buffer object");
LV_LOG_WARN("Failed to create GBM buffer object");
return false;
}
@@ -935,7 +953,7 @@ static bool init_buffer(lv_wayland_dmabuf_ctx_t * dmabuf_ctx, lv_wl_buffer_t * b
buffer->offset = gbm_bo_get_offset(buffer->bo, 0);
buffer->dmabuf_fd = gbm_bo_get_fd(buffer->bo);
if(buffer->dmabuf_fd < 0) {
LV_LOG_ERROR("Failed to export GBM buffer object as a DMA-BUF fd");
LV_LOG_WARN("Failed to export GBM buffer object as a DMA-BUF fd");
return false;
}
@@ -953,7 +971,7 @@ static bool init_buffer(lv_wayland_dmabuf_ctx_t * dmabuf_ctx, lv_wl_buffer_t * b
buffer->egl_image = eglCreateImageKHR(ddata->egl_ctx->egl_display, EGL_NO_CONTEXT,
EGL_LINUX_DMA_BUF_EXT, NULL, attribs);
if(buffer->egl_image == EGL_NO_IMAGE_KHR) {
LV_LOG_ERROR("Failed to create EGL image from DMA-BUF");
LV_LOG_WARN("Failed to create EGL image from DMA-BUF");
return false;
}
+15 -7
View File
@@ -64,7 +64,7 @@ typedef struct {
* STATIC PROTOTYPES
**********************/
static void * wl_g2d_init(void);
static lv_result_t wl_g2d_init(void ** backend_data);
static void wl_g2d_deinit(void * backend_ctx);
static void wl_g2d_global_handler(void * backend_ctx, struct wl_registry * registry, uint32_t name,
const char * interface, uint32_t version);
@@ -121,10 +121,13 @@ static lv_wl_buffer_t * get_next_buffer(lv_wl_g2d_display_data_t * ddata);
static lv_wl_g2d_ctx_t ctx;
const lv_wayland_backend_ops_t wl_backend_ops = {
const lv_wayland_backend_ops_t wl_g2d_ops = {
.init = wl_g2d_init,
.deinit = wl_g2d_deinit,
.global_handler = wl_g2d_global_handler,
};
const lv_wayland_backend_display_ops_t wl_g2d_display_ops = {
.init_display = wl_g2d_init_display,
.deinit_display = wl_g2d_deinit_display,
.resize_display = wl_g2d_resize_display,
@@ -175,10 +178,11 @@ static const struct wl_callback_listener frame_listener = {
**********************/
static void * wl_g2d_init(void)
static lv_result_t wl_g2d_init(void ** backend_data)
{
lv_memset(&ctx, 0, sizeof(ctx));
return &ctx;
*backend_data = &ctx;
return LV_RESULT_OK;
}
static void wl_g2d_deinit(void * backend_ctx)
@@ -260,7 +264,8 @@ static void delete_buffer(lv_wl_buffer_t * buffer)
static lv_wl_g2d_display_data_t * wl_g2d_create_display_data(lv_wl_g2d_ctx_t * ctx, lv_display_t * display,
int32_t width, int32_t height)
{
lv_wl_g2d_display_data_t * ddata = lv_zalloc(sizeof(*ddata));
if(!ctx->handler)
lv_wl_g2d_display_data_t * ddata = lv_zalloc(sizeof(*ddata));
LV_ASSERT_MALLOC(ddata);
if(!ddata) {
return NULL;
@@ -325,11 +330,14 @@ static void wl_g2d_delete_display_data(lv_wl_g2d_display_data_t * ddata)
static void * wl_g2d_init_display(void * backend_ctx, lv_display_t * display, int32_t width, int32_t height)
{
lv_wl_g2d_ctx_t * ctx = (lv_wl_g2d_ctx_t *)backend_ctx;
if(!ctx->handler) {
LV_LOG_WARN("dmabuf registry not bound. Can't initialize a display with the g2d backend");
return NULL;
}
lv_wl_g2d_display_data_t * ddata = wl_g2d_create_display_data(ctx, display, width, height);
if(!ddata) {
LV_LOG_ERROR("Failed to create display data");
LV_LOG_WARN("Failed to create display data");
return NULL;
}
@@ -14,7 +14,7 @@ extern "C" {
* INCLUDES
*********************/
#include "lv_wayland_private.h"
#include "../../lvgl_public.h"
#if LV_USE_WAYLAND
@@ -30,33 +30,37 @@ extern "C" {
/**
* @typedef lv_wayland_backend_init_t
* @brief Initialize the backend context
* @brief Initialize the backend data
*
* This function is called once when the Wayland driver is initialized to create
* the global backend context. The returned pointer will be passed as backend_ctx
* to all other backend operations.
* the global backend data. The context written to backend_data is passed back
* to every other operation of the backend. It may be left NULL by a backend that
* keeps no global state.
*
* @return Pointer to backend-specific context data, or NULL on failure
* @param[out] backend_data Receives a pointer to backend-specific context data
* @return LV_RESULT_OK if the backend is usable, otherwise LV_RESULT_INVALID.
* A backend that fails here is skipped entirely: no further operation is
* called on it, not even deinit()
*
* @note This is called before any displays are created
* @see lv_wayland_backend_deinit_t
*/
typedef void * (*lv_wayland_backend_init_t)(void);
typedef lv_result_t (*lv_wayland_backend_init_t)(void ** backend_data);
/**
* @typedef lv_wayland_backend_deinit_t
* @brief Deinitialize the backend context
* @brief Deinitialize the backend data
*
* This function is called when the Wayland driver is deinitialized. It must
* clean up all resources allocated in the init function and free the backend
* context.
*
* @param[in] backend_ctx Pointer to the backend context returned by init
* @param[in] backend_data Pointer to the backend data returned by init
*
* @note This is called after all displays have been destroyed
* @see lv_wayland_backend_init_t
*/
typedef void (*lv_wayland_backend_deinit_t)(void * backend_ctx);
typedef void (*lv_wayland_backend_deinit_t)(void * backend_data);
/**
* @typedef lv_wayland_backend_init_display_t
@@ -65,7 +69,7 @@ typedef void (*lv_wayland_backend_deinit_t)(void * backend_ctx);
* This function is called when creating a new LVGL display on Wayland. It should
* allocate and initialize per-display resources needed for rendering.
*
* @param[in] backend_ctx Pointer to the backend context
* @param[in] backend_data Pointer to the backend data
* @param[in] display Pointer to the LVGL display object
* @param[in] width Initial width of the display in pixels
* @param[in] height Initial height of the display in pixels
@@ -76,7 +80,7 @@ typedef void (*lv_wayland_backend_deinit_t)(void * backend_ctx);
* @note It is expected that each display gets its own data structure in order for a backend
* to support multiple displays
*/
typedef void * (*lv_wayland_backend_init_display_t)(void * backend_ctx, lv_display_t * display, int32_t width,
typedef void * (*lv_wayland_backend_init_display_t)(void * backend_data, lv_display_t * display, int32_t width,
int32_t height);
/**
@@ -86,7 +90,7 @@ typedef void * (*lv_wayland_backend_init_display_t)(void * backend_ctx, lv_displ
* This function is called when a display needs to be resized or when its rotation
* is modified. The backend should update its rendering resources accordingly.
*
* @param[in] backend_ctx Pointer to the backend context
* @param[in] backend_data Pointer to the backend data
* @param[in] display Pointer to the LVGL display object being resized
* @return Pointer to updated display-specific data, or NULL on failure
*
@@ -95,7 +99,7 @@ typedef void * (*lv_wayland_backend_init_display_t)(void * backend_ctx, lv_displ
* retrieved using lv_wayland_get_backend_display_data()
* @warning The display data is overwritten with the return value of this function
*/
typedef void * (*lv_wayland_backend_resize_display_t)(void * backend_ctx, lv_display_t * display);
typedef void * (*lv_wayland_backend_resize_display_t)(void * backend_data, lv_display_t * display);
/**
* @typedef lv_wayland_backend_destroy_display_t
@@ -105,12 +109,12 @@ typedef void * (*lv_wayland_backend_resize_display_t)(void * backend_ctx, lv_dis
* all per-display resources and free the display data that was allocated in
* init_display.
*
* @param[in] backend_ctx Pointer to the backend context
* @param[in] backend_data Pointer to the backend data
* @param[in] display Pointer to the LVGL display object being destroyed
*
* @note The display data associated with this display must be freed
*/
typedef void (*lv_wayland_backend_destroy_display_t)(void * backend_ctx, lv_display_t * display);
typedef void (*lv_wayland_backend_destroy_display_t)(void * backend_data, lv_display_t * display);
/**
* @typedef lv_wayland_backend_global_handler_t
@@ -120,7 +124,7 @@ typedef void (*lv_wayland_backend_destroy_display_t)(void * backend_ctx, lv_disp
* compositor. The backend can use this to bind to Wayland protocols it requires
* (e.g., wl_shm, EGL extensions, DMA-BUF protocols, etc.).
*
* @param[in] backend_ctx Pointer to the backend context
* @param[in] backend_data Pointer to the backend data
* @param[in] registry Wayland registry object
* @param[in] name Numeric name of the global object
* @param[in] interface String name of the interface (e.g., "wl_shm")
@@ -129,34 +133,94 @@ typedef void (*lv_wayland_backend_destroy_display_t)(void * backend_ctx, lv_disp
* @note This is called during Wayland connection setup
* @note The backend should use wl_registry_bind() to bind to needed protocols
*/
typedef void (*lv_wayland_backend_global_handler_t)(void * backend_ctx, struct wl_registry * registry, uint32_t name,
typedef void (*lv_wayland_backend_global_handler_t)(void * backend_data, struct wl_registry * registry, uint32_t name,
const char * interface, uint32_t version);
/**
* @struct lv_wayland_backend_ops_t
* @brief Wayland backend operations structure
*
* This structure defines the complete set of operations that a Wayland backend
* This structure defines the general set of operations that a Wayland backend
* must implement. All function pointers must be non-NULL.
*
* @par Lifecycle Order:
* 1. init() - Initialize backend context
* 1. init() - Initialize backend data
* 2. global_handler() - Called for each Wayland global (may be called multiple times)
* 3. init_display() - Create display (may be called multiple times for multiple displays)
* 4. resize_display() - Resize display (called as needed)
* 5. deinit_display() - Destroy display (called once per display)
* 6. deinit() - Clean up backend context
* 3. deinit() - Clean up backend data
*/
typedef struct {
lv_wayland_backend_init_t init; /**< Initialize backend context */
lv_wayland_backend_init_t init; /**< Initialize backend data */
lv_wayland_backend_global_handler_t global_handler; /**< Handle Wayland global objects */
lv_wayland_backend_deinit_t deinit; /**< Deinitialize backend data */
} lv_wayland_backend_ops_t;
/**
* @struct lv_wayland_backend_display_ops_t
* @brief Wayland backend display operations structure
*
* This structure defines the display specific set of operations that a Wayland backend
* must implement. All function pointers must be non-NULL.
*
* @par Lifecycle Order:
* 1. init_display() - Create display (may be called multiple times for multiple displays)
* 2. resize_display() - Resize display (called as needed)
* 3. deinit_display() - Destroy display (called once per display)
*/
typedef struct {
lv_wayland_backend_init_display_t init_display; /**< Initialize a new display */
lv_wayland_backend_resize_display_t resize_display; /**< Resize or reconfigure display */
lv_wayland_backend_destroy_display_t deinit_display; /**< Destroy a display */
lv_wayland_backend_deinit_t deinit; /**< Deinitialize backend context */
} lv_wayland_backend_ops_t;
} lv_wayland_backend_display_ops_t;
extern const lv_wayland_backend_ops_t wl_backend_ops;
typedef struct {
const lv_wayland_backend_display_ops_t * ops; /**< Backend display specific operations */
void * backend_data; /**< General backend data */
void * display_data; /**< Specific display backend data */
} lv_wayland_backend_display_data_t;
/** @brief Initializes every compiled-in backend
*
* A backend whose init() fails is marked unavailable and skipped by all the
* functions below.
*/
void lv_wayland_backend_init_all(void);
/** @brief Deinitializes every available backend
*/
void lv_wayland_backend_deinit_all(void);
/** @brief Dispatches a global handler call to all available backends
*
* @param[in] registry Wayland registry object
* @param[in] name Numeric name of the global object
* @param[in] interface String name of the interface
* @param[in] version Version number of the interface
*/
void lv_wayland_backend_global_handler(struct wl_registry * registry, uint32_t name,
const char * interface, uint32_t version);
/** @brief Loops through all available backends to find one capable of initializing a display
*
* The function loops through all available backends until one can initialize a display
*
* @param[out] backend_ddata Backend display data
* @param[in] display The display to initialize for
* @param[in] width the display width
* @param[in] height the display height
* @return LV_RESULT_OK if the display was initialized else LV_RESULT_INVALID
*/
lv_result_t lv_wayland_backend_init_display(lv_wayland_backend_display_data_t * backend_ddata,
lv_display_t * display,
int32_t width,
int32_t height);
/** @brief Deinitializes a display
*
* @param[in] backend_ddata Backend display data of the display
* @param[in] display The display to deinitialize
*/
void lv_wayland_backend_deinit_display(lv_wayland_backend_display_data_t * backend_ddata, lv_display_t * display);
/** @brief Get the backend-specific display data
*
+12 -5
View File
@@ -54,7 +54,7 @@ typedef struct {
* STATIC PROTOTYPES
**********************/
static void * shm_init(void);
static lv_result_t shm_init(void ** backend_data);
static void shm_deinit(void *);
static void * shm_init_display(void * backend_ctx, lv_display_t * display, int32_t width, int32_t height);
static void * shm_resize_display(void * backend_ctx, lv_display_t * display);
@@ -86,10 +86,13 @@ static const struct wl_buffer_listener buffer_listener = {
.release = buffer_release
};
const lv_wayland_backend_ops_t wl_backend_ops = {
const lv_wayland_backend_ops_t wl_shm_ops = {
.init = shm_init,
.deinit = shm_deinit,
.global_handler = shm_global_handler,
};
const lv_wayland_backend_display_ops_t wl_shm_display_ops = {
.init_display = shm_init_display,
.deinit_display = shm_deinit_display,
.resize_display = shm_resize_display,
@@ -145,15 +148,19 @@ static int32_t lv_cf_to_shm_cf(lv_color_format_t cf)
}
}
static void * shm_init(void)
static lv_result_t shm_init(void ** backend_data)
{
lv_memzero(&shm_ctx, sizeof(shm_ctx));
return &shm_ctx;
*backend_data = &shm_ctx;
return LV_RESULT_OK;
}
static void shm_deinit(void * backend_ctx)
{
lv_wl_shm_ctx_t * ctx = backend_ctx;
if(!ctx) {
return;
}
if(ctx->shm) {
wl_shm_destroy(ctx->shm);
ctx->shm = NULL;
@@ -459,4 +466,4 @@ static void shm_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t *
ddata->curr_wl_buffer_idx = (ddata->curr_wl_buffer_idx + 1) % LV_WL_SHM_BUF_COUNT;
}
#endif /*LV_WAYLAND_USE_SHM*/
#endif /*LV_USE_WAYLAND*/
+2 -1
View File
@@ -19,6 +19,7 @@ extern "C" {
#if LV_USE_WAYLAND
#include "lv_wayland_backend_private.h"
#include <sys/poll.h>
#include <wayland-client-protocol.h>
#include <wayland_xdg_shell.h>
@@ -127,12 +128,12 @@ typedef struct {
typedef struct _lv_wl_window_t {
void * backend_display_data;
lv_display_t * lv_disp;
lv_indev_t * lv_indev_pointer;
lv_indev_t * lv_indev_pointeraxis;
lv_indev_t * lv_indev_touch;
lv_indev_t * lv_indev_keyboard;
lv_wayland_backend_display_data_t backend_ddata;
lv_wayland_display_close_cb_t close_cb;
lv_wl_window_xdg_t xdg;
+24 -9
View File
@@ -11,7 +11,6 @@
#if LV_USE_WAYLAND
#include <errno.h>
#include <stdlib.h>
#include <string.h>
@@ -84,7 +83,16 @@ lv_display_t * lv_wayland_window_create(uint32_t hor_res, uint32_t ver_res, char
lv_display_set_driver_data(window->lv_disp, window);
/* Initialize display driver */
window->backend_display_data = wl_backend_ops.init_display(lv_wl_ctx.backend_data, window->lv_disp, hor_res, ver_res);
lv_result_t res = lv_wayland_backend_init_display(&window->backend_ddata,
window->lv_disp, hor_res,
ver_res);
if(res != LV_RESULT_OK) {
LV_LOG_ERROR("Failed to create display");
goto init_display_err;
}
/*Assert here so that we can freely use these operations afterwards*/
LV_ASSERT_NULL(window->backend_ddata.ops);
lv_wayland_xdg_configure_surface(window);
@@ -123,7 +131,8 @@ lv_display_t * lv_wayland_window_create(uint32_t hor_res, uint32_t ver_res, char
LV_LOG_ERROR("failed to register keyboard indev");
}
return window->lv_disp;
init_display_err:
lv_wayland_xdg_delete_window(&window->xdg);
create_window_err:
wl_surface_destroy(window->body);
create_surface_err:
@@ -140,7 +149,7 @@ void * lv_wayland_get_backend_display_data(lv_display_t * display)
LV_ASSERT_NULL(display);
lv_wl_window_t * window = lv_display_get_driver_data(display);
LV_ASSERT_NULL(window);
return window->backend_display_data;
return window->backend_ddata.display_data;
}
void lv_wayland_set_backend_display_data(lv_display_t * display, void * data)
@@ -148,7 +157,7 @@ void lv_wayland_set_backend_display_data(lv_display_t * display, void * data)
LV_ASSERT_NULL(display);
lv_wl_window_t * window = lv_display_get_driver_data(display);
LV_ASSERT_NULL(window);
window->backend_display_data = data;
window->backend_ddata.display_data = data;
}
struct wl_surface * lv_wayland_get_window_surface(lv_display_t * display)
@@ -298,9 +307,7 @@ static void delete_event(lv_event_t * e)
/* Make sure buffer is correctly released*/
wl_display_roundtrip(lv_wl_ctx.wl_display);
wl_backend_ops.deinit_display(window->backend_display_data, window->lv_disp);
window->backend_display_data = NULL;
lv_wayland_backend_deinit_display(&window->backend_ddata, window->lv_disp);
if(LV_WAYLAND_DIRECT_EXIT) {
lv_display_set_driver_data(window->lv_disp, NULL);
@@ -337,7 +344,15 @@ static void res_changed_event(lv_event_t * e)
{
lv_display_t * display = (lv_display_t *) lv_event_get_target(e);
lv_wl_window_t * window = lv_display_get_driver_data(display);
window->backend_display_data = wl_backend_ops.resize_display(lv_wl_ctx.backend_data, display);
void * display_data = window->backend_ddata.ops->resize_display(window->backend_ddata.backend_data, display);
if(!display_data) {
/* The backend kept the display data of the previous resolution alive */
LV_LOG_ERROR("Failed to resize the display, keeping the previous configuration");
return;
}
window->backend_ddata.display_data = display_data;
}
#endif /* LV_USE_WAYLAND */
+3 -1
View File
@@ -3,5 +3,7 @@
CONFIG_LV_USE_DRAW_OPENGLES=y
CONFIG_LV_LINUX_DRM_BACKEND_EGL=y
CONFIG_LV_WAYLAND_BACKEND_EGL=y
CONFIG_LV_SDL_BACKEND_EGL=y
CONFIG_LV_WAYLAND_USE_EGL=y
CONFIG_LV_WAYLAND_USE_SHM=y
+1 -2
View File
@@ -7,8 +7,7 @@ CONFIG_LV_USE_LINUX_DRM=y
CONFIG_LV_LINUX_DRM_BACKEND_FBDEV=y
CONFIG_LV_USE_WAYLAND=y
# CONFIG_LV_WAYLAND_AUTO_BACKEND is not set
CONFIG_LV_WAYLAND_BACKEND_SHM=y
CONFIG_LV_WAYLAND_USE_SHM=y
# X11 has no backend choice, it is software only
CONFIG_LV_USE_X11=y