feat(wayland): support falling back to different backends at runtime

This commit is contained in:
André Costa
2026-03-09 12:18:20 +01:00
parent f5a8770f06
commit f93ec6c72c
10 changed files with 226 additions and 74 deletions
+6 -21
View File
@@ -230,27 +230,6 @@ LV_EXPORT_CONST_INT(LV_DRAW_BUF_ALIGN);
#define LV_LOG_TRACE_ANIM 0
#endif /*LV_USE_LOG*/
#if LV_USE_WAYLAND
/*Automatically detect wayland backend*/
#if LV_USE_OPENGLES
#define LV_WAYLAND_USE_EGL 1
#define LV_WAYLAND_USE_G2D 0
#define LV_WAYLAND_USE_SHM 0
#elif LV_USE_G2D
#define LV_WAYLAND_USE_EGL 0
#define LV_WAYLAND_USE_G2D 1
#define LV_WAYLAND_USE_SHM 0
#else
#define LV_WAYLAND_USE_EGL 0
#define LV_WAYLAND_USE_G2D 0
#define LV_WAYLAND_USE_SHM 1
#endif
#else
#define LV_WAYLAND_USE_G2D 0
#define LV_WAYLAND_USE_SHM 0
#define LV_WAYLAND_USE_EGL 0
#endif
#if LV_USE_LINUX_DRM
#if LV_USE_OPENGLES
#define LV_LINUX_DRM_USE_EGL 1
@@ -309,6 +288,12 @@ LV_EXPORT_CONST_INT(LV_DRAW_BUF_ALIGN);
#define LV_SDL_USE_EGL 0
#endif
#if LV_USE_WAYLAND && LV_USE_OPENGLES
#define LV_WAYLAND_USE_EGL 1
#else
#define LV_WAYLAND_USE_EGL 0
#endif
#ifndef LV_USE_EGL
#if LV_LINUX_DRM_USE_EGL || LV_WAYLAND_USE_EGL || LV_SDL_USE_EGL
#define LV_USE_EGL 1
+3 -5
View File
@@ -125,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);
@@ -167,7 +166,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) {
@@ -324,8 +323,7 @@ static void handle_global(void * data, struct wl_registry * registry, uint32_t n
ctx->wl_output_count++;
}
}
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)
+118
View File
@@ -0,0 +1,118 @@
/**
* @file lv_wayland_backend.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_wayland_backend_private.h"
#if LV_USE_WAYLAND
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
#if LV_USE_OPENGLES
extern const lv_wayland_backend_ops_t wl_egl_ops;
extern const lv_wayland_backend_display_ops_t wl_egl_display_ops;
#endif /*LV_USE_OPENGLES*/
#if LV_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_USE_G2D*/
extern const lv_wayland_backend_ops_t wl_shm_ops;
extern const lv_wayland_backend_display_ops_t wl_shm_display_ops;
/**********************
* MACROS
**********************/
static struct {
const char * name;
const lv_wayland_backend_ops_t * ops;
const lv_wayland_backend_display_ops_t * display_ops;
void * backend_ctx;
} backends[] = {
#if LV_USE_OPENGLES
{"EGL", &wl_egl_ops, &wl_egl_display_ops, NULL},
#endif /*LV_USE_OPENGLES*/
#if LV_USE_G2D
{"G2D", &wl_g2d_ops, &wl_g2d_display_ops, NULL},
#endif /*LV_USE_G2D*/
{"SHM", &wl_shm_ops, &wl_shm_display_ops, NULL},
};
const size_t backend_count = (sizeof(backends) / sizeof(backends[0]));
/**********************
* 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_ctx = backends[i].ops->init();
}
}
void lv_wayland_backend_deinit_all(void)
{
for(size_t i = 0; i < backend_count; ++i) {
LV_LOG_INFO("Deinitializing '%s' wayland backend", backends[i].name);
backends[i].ops->deinit(backends[i].backend_ctx);
}
}
void lv_wayland_backend_global_handler(struct wl_registry * registry, uint32_t name,
const char * interface, uint32_t version)
{
for(size_t i = 0; i < backend_count; ++i) {
backends[i].ops->global_handler(backends[i].backend_ctx, 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)
{
for(size_t i = 0; i < backend_count; ++i) {
void * display_data = backends[i].display_ops->init_display(backends[i].backend_ctx, display, width, height);
if(!display_data) {
LV_LOG_INFO("Failed to initialize display for '%s' wayland backend", backends[i].name);
continue;
}
backend_ddata->ops = backends[i].display_ops;
backend_ddata->backend_ctx = backends[i].backend_ctx;
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;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_WAYLAND*/
+6 -3
View File
@@ -8,7 +8,7 @@
#include "lv_wayland_private.h"
#if LV_WAYLAND_USE_EGL
#if LV_USE_WAYLAND && LV_USE_OPENGLES
#include "../../display/lv_display_private.h"
#include "../opengles/lv_opengles_driver.h"
@@ -68,10 +68,13 @@ 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,
@@ -420,4 +423,4 @@ static void wl_egl_flip_cb(void * driver_data, bool vsync)
* through wl_surface_commit() which is called in the flush callback */
}
#endif /*LV_WAYLAND_USE_EGL*/
#endif /*LV_USE_WAYLAND && LV_USE_OPENGLES*/
+6 -3
View File
@@ -10,7 +10,7 @@
#include "lv_wayland_private.h"
#if LV_WAYLAND_USE_G2D
#if LV_USE_WAYLAND && LV_USE_G2D
#include "../../display/lv_display_private.h"
#include <wayland_linux_dmabuf.h>
@@ -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,
@@ -644,4 +647,4 @@ static void flush_cb(lv_display_t * disp, const lv_area_t * area, unsigned char
return;
}
#endif /*LV_USE_WAYLAND_G2D*/
#endif /*LV_USE_WAYLAND && LV_USE_G2D*/
@@ -136,27 +136,74 @@ typedef void (*lv_wayland_backend_global_handler_t)(void * backend_ctx, struct w
* @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
* 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 context
*/
typedef struct {
lv_wayland_backend_init_t init; /**< Initialize backend context */
lv_wayland_backend_global_handler_t global_handler; /**< Handle Wayland global objects */
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;
extern const lv_wayland_backend_ops_t wl_backend_ops;
/**
* @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_display_ops_t;
typedef struct {
const lv_wayland_backend_display_ops_t * ops; /**< Backend display specific operations */
void * backend_ctx; /**< General backend context */
void * display_data; /**< Specific display backend data */
} lv_wayland_backend_display_data_t;
/* @brief Initializes all backends
*
*/
void lv_wayland_backend_init_all(void);
/* @brief Deinitializes all backends
*
*/
void lv_wayland_backend_deinit_all(void);
/* @brief Deinitializes all backends
*
*/
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 it can initialize a display
*
* @return Pointer to the initialize backend operations or NULL if no backend could be probed
*
* @note this function does not initialize the backend itself
* */
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 Get the backend-specific display data
*
+6 -3
View File
@@ -9,7 +9,7 @@
#include "lv_wayland_private.h"
#if LV_WAYLAND_USE_SHM
#if LV_USE_WAYLAND
#include "../../draw/sw/lv_draw_sw_utils.h"
#include "../../display/lv_display_private.h"
@@ -87,10 +87,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,
@@ -454,4 +457,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*/
+1 -2
View File
@@ -99,7 +99,6 @@ typedef struct {
struct wl_shm * wl_shm;
lv_wl_seat_t seat;
void * backend_data;
lv_wl_output_info_t physical_outputs[LV_WAYLAND_MAX_OUTPUTS];
uint8_t wl_output_count;
@@ -126,12 +125,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;
+18 -7
View File
@@ -90,7 +90,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 tat we can freely use these operations afterwards*/
LV_ASSERT_NULL(window->backend_ddata.ops);
lv_wayland_xdg_configure_surface(window);
@@ -128,7 +137,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:
@@ -145,7 +155,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)
@@ -153,7 +163,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)
@@ -289,8 +299,7 @@ void lv_wayland_window_delete(lv_wl_window_t * window)
/* 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;
window->backend_ddata.ops->deinit_display(window->backend_ddata.backend_ctx, window->lv_disp);
/* Set the driver data to NULL before calling display delete
* so that the delete event doesn't do anything*/
@@ -338,7 +347,9 @@ 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);
window->backend_ddata.display_data = window->backend_ddata.ops->resize_display(window->backend_ddata.backend_ctx,
display);
}
#endif /* LV_USE_WAYLAND */
+6 -21
View File
@@ -4861,27 +4861,6 @@ LV_EXPORT_CONST_INT(LV_DRAW_BUF_ALIGN);
#define LV_LOG_TRACE_ANIM 0
#endif /*LV_USE_LOG*/
#if LV_USE_WAYLAND
/*Automatically detect wayland backend*/
#if LV_USE_OPENGLES
#define LV_WAYLAND_USE_EGL 1
#define LV_WAYLAND_USE_G2D 0
#define LV_WAYLAND_USE_SHM 0
#elif LV_USE_G2D
#define LV_WAYLAND_USE_EGL 0
#define LV_WAYLAND_USE_G2D 1
#define LV_WAYLAND_USE_SHM 0
#else
#define LV_WAYLAND_USE_EGL 0
#define LV_WAYLAND_USE_G2D 0
#define LV_WAYLAND_USE_SHM 1
#endif
#else
#define LV_WAYLAND_USE_G2D 0
#define LV_WAYLAND_USE_SHM 0
#define LV_WAYLAND_USE_EGL 0
#endif
#if LV_USE_LINUX_DRM
#if LV_USE_OPENGLES
#define LV_LINUX_DRM_USE_EGL 1
@@ -4940,6 +4919,12 @@ LV_EXPORT_CONST_INT(LV_DRAW_BUF_ALIGN);
#define LV_SDL_USE_EGL 0
#endif
#if LV_USE_WAYLAND && LV_USE_OPENGLES
#define LV_WAYLAND_USE_EGL 1
#else
#define LV_WAYLAND_USE_EGL 0
#endif
#ifndef LV_USE_EGL
#if LV_LINUX_DRM_USE_EGL || LV_WAYLAND_USE_EGL || LV_SDL_USE_EGL
#define LV_USE_EGL 1