diff --git a/.github/workflows/micropython_lvgl_ci.yml b/.github/workflows/micropython_lvgl_ci.yml index 5f7039345d..bc5f5b80c6 100644 --- a/.github/workflows/micropython_lvgl_ci.yml +++ b/.github/workflows/micropython_lvgl_ci.yml @@ -28,6 +28,7 @@ jobs: sudo add-apt-repository -y "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" sudo apt-get update -y -qq sudo apt-get install libsdl2-dev parallel libfreetype-dev librlottie-dev libavformat-dev libavcodec-dev libswscale-dev libavutil-dev build-essential libc-bin + sudo apt-get install libwayland-dev libwayland-bin wayland-protocols libxkbcommon-dev weston python3 -m pip install pillow - name: Clone lv_micropython @@ -102,7 +103,24 @@ jobs: - name: Run MicroPython-LVGL API Tests if: matrix.port == 'unix' run: MICROPY_MICROPYTHON=ports/unix/build-lvgl/micropython ./tests/run-tests.py -d user_modules/lv_binding_micropython/tests/api - + + # Runs the same tests/display suite as the (manual, HIL-oriented) SDL + # path, against the Wayland driver instead, via a headless compositor. + # See README.md's "Wayland driver" section for why this driver exists. + - name: Run MicroPython-LVGL Wayland Display Tests + if: matrix.port == 'unix' + run: | + mkdir -p /tmp/xdg-runtime && chmod 0700 /tmp/xdg-runtime + export XDG_RUNTIME_DIR=/tmp/xdg-runtime + weston --backend=headless --socket=wayland-ci --idle-time=0 & + WESTON_PID=$! + sleep 1 + WAYLAND_DISPLAY=wayland-ci LV_MP_TEST_DRIVER=wayland \ + MICROPY_MICROPYTHON=ports/unix/build-lvgl/micropython \ + ./tests/run-tests.py user_modules/lv_binding_micropython/tests/display/basic*.py -r . + kill $WESTON_PID + + - name: Process Tests Artifacts if: matrix.port == 'unix' diff --git a/README.md b/README.md index 9fe2c2b603..02f0782dd1 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,57 @@ Driver code is under `/driver` directory. Drivers can also be implemented in pure MicroPython, by providing callbacks (`disp_drv.flush_cb`, `indev_drv.read_cb` etc.) Currently the supported ILI9341, FT6X36 and XPT2046 are pure micropython drivers. +### Wayland driver + +On Linux, LVGL also ships a native Wayland driver (`lvgl/src/drivers/wayland`) as +an alternative to SDL. Usage mirrors the SDL example above: + +```python +import lvgl as lv +lv.init() + +from lv_utils import event_loop + +WIDTH = 480 +HEIGHT = 320 + +event_loop = event_loop() +disp_drv = lv.wayland_window_create_simple(WIDTH, HEIGHT, "MicroPython-LVGL") +pointer = lv.wayland_pointer_create() +keyboard = lv.wayland_keyboard_create() + +while lv.wayland_window_is_open(disp_drv): + lv.wayland_timer_handler() +``` + +`lv.wayland_window_create_simple` takes only `hor_res, ver_res, title` (no +close-callback - `gen_mpy.py` can't bind `lv_wayland_window_create()`'s C +callback param, see [gen/lv_mpy_drivers.h](gen/lv_mpy_drivers.h)). Poll +`lv.wayland_window_is_open()` to detect the window closing instead. + +**Why**: `lv_sdl_window_create()` can segfault deep in the NVIDIA GL/EGL +driver as soon as a real window is presented, on Wayland sessions with the +proprietary NVIDIA driver - a long-standing upstream issue +([#46](https://github.com/lvgl/lv_binding_micropython/issues/46)), caused by +this binding's SDL driver running on MicroPython's own thread rather than a +dedicated one. LVGL's native Wayland driver avoids it entirely: it presents +via `wl_shm` and never touches GL/EGL. It was already upstream in LVGL, just +never wired into this binding's build or exposed to Python. + +While wiring it up we also found no LVGL desktop driver (SDL included) has +been reachable from Python at all since +[3f32386](https://github.com/lvgl/lv_binding_micropython/commit/3f32386af5f3ee9ba37d9282b1926e39b74162d7) +(2026-05-02) switched `gen_mpy.py`'s input from `lvgl.h` to +`lvgl_private.h`, which doesn't pull in `src/drivers/lv_drivers.h` - a silent +regression, also breaking `tests/testdisplay.py`'s interactive mode. Fixed +the same way here: gen_mpy now parses +[gen/lv_mpy_drivers.h](gen/lv_mpy_drivers.h) instead, which includes both. + +**Build requirements**: autodetected via `pkg-config` in `micropython.mk` +like SDL - left disabled if `wayland-client`/`wayland-cursor`/`xkbcommon`/ +`wayland-scanner`/`wayland-protocols` aren't found. `LV_COLOR_DEPTH` must +stay `32`; see the comment above its definition in `lv_conf.h`. + ### Where are the drivers? LVGL C drivers and MicroPython drivers (either C or Python) are **separate and independent** from each other. diff --git a/gen/gen_mpy.py b/gen/gen_mpy.py index ee61a87be2..6e8b7bc118 100644 --- a/gen/gen_mpy.py +++ b/gen/gen_mpy.py @@ -1832,7 +1832,13 @@ def register_int_ptr_type(convertor, *types): unsigned long long val = 0; bool big_endian = !(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__); + // mp_obj_int_to_bytes() replaced mp_obj_int_to_bytes_impl() in MicroPython + // 1.29 (commit e00daa3a), adding is_signed and overflow_check parameters. +#if MICROPY_VERSION >= MICROPY_MAKE_VERSION(1, 29, 0) + mp_obj_int_to_bytes(obj, sizeof(val), (byte*)&val, big_endian, false, false); +#else mp_obj_int_to_bytes_impl(obj, big_endian, sizeof(val), (byte*)&val); +#endif return val; } diff --git a/gen/lv_mpy_drivers.c b/gen/lv_mpy_drivers.c new file mode 100644 index 0000000000..8dff214841 --- /dev/null +++ b/gen/lv_mpy_drivers.c @@ -0,0 +1,17 @@ +/** + * @file lv_mpy_drivers.c + * + * Implementation of the binding-friendly driver wrappers declared for + * gen_mpy.py in lv_mpy_drivers.h. See that file for why this is needed. + */ + +#include "lvgl.h" + +#if LV_USE_WAYLAND + +lv_display_t * lv_wayland_window_create_simple(uint32_t hor_res, uint32_t ver_res, char * title) +{ + return lv_wayland_window_create(hor_res, ver_res, title, NULL); +} + +#endif diff --git a/gen/lv_mpy_drivers.h b/gen/lv_mpy_drivers.h new file mode 100644 index 0000000000..6b20a0964e --- /dev/null +++ b/gen/lv_mpy_drivers.h @@ -0,0 +1,36 @@ +/** + * @file lv_mpy_drivers.h + * + * gen_mpy.py builds its binding AST from a single preprocessed input file + * (see the LVGL_MPY rule in micropython.mk). lvgl_private.h alone only + * pulls in _private.h counterparts for libinput/evdev, so desktop window + * drivers (sdl/wayland/x11/...) never reach the parser and never get + * Python bindings, regardless of LV_USE_SDL/LV_USE_WAYLAND/etc. This + * wrapper adds the public driver headers to gen_mpy's input so any driver + * enabled in lv_conf.h is bound the same way widgets are. + */ + +#include "lvgl_private.h" + +#if LV_USE_WAYLAND +/* + * lv_wayland_window_create()'s close_cb parameter has no accompanying + * user_data-carrying struct argument (its first parameter is a plain + * uint32_t, not an lv_obj/lv_display, which is what gen_mpy's + * callback-binding heuristic requires to know where to stash the + * Python callable). gen_mpy silently emits invalid C + * (`hor_res->user_data`) for it instead of erroring, so hide the + * original declaration from the parser here and expose + * lv_wayland_window_create_simple() instead (implemented in + * lv_mpy_drivers.c), which has no callback parameter at all -- window + * close is already observable via lv_wayland_window_is_open(). + */ +#define lv_wayland_window_create(...) lv_wayland_window_create_native_unbound +#endif + +#include "src/drivers/lv_drivers.h" + +#if LV_USE_WAYLAND +#undef lv_wayland_window_create +lv_display_t * lv_wayland_window_create_simple(uint32_t hor_res, uint32_t ver_res, char * title); +#endif diff --git a/gen/lv_mpy_example.c b/gen/lv_mpy_example.c index b109545feb..3957671fd8 100644 --- a/gen/lv_mpy_example.c +++ b/gen/lv_mpy_example.c @@ -778,7 +778,13 @@ STATIC unsigned long long mp_obj_get_ull(mp_obj_t obj) unsigned long long val = 0; bool big_endian = !(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__); + // mp_obj_int_to_bytes() replaced mp_obj_int_to_bytes_impl() in MicroPython + // 1.29 (commit e00daa3a), adding is_signed and overflow_check parameters. +#if MICROPY_VERSION >= MICROPY_MAKE_VERSION(1, 29, 0) + mp_obj_int_to_bytes(obj, sizeof(val), (byte*)&val, big_endian, false, false); +#else mp_obj_int_to_bytes_impl(obj, big_endian, sizeof(val), (byte*)&val); +#endif return val; } diff --git a/lib/lv_utils.py b/lib/lv_utils.py index a43e3aaf37..12166d44a0 100644 --- a/lib/lv_utils.py +++ b/lib/lv_utils.py @@ -80,6 +80,7 @@ def __init__( refresh_cb=None, asynchronous=False, exception_sink=None, + handler_cb=None, ): if self.is_running(): raise RuntimeError("Event loop is already running!") @@ -91,6 +92,14 @@ def __init__( self.delay = 1000 // freq self.refresh_cb = refresh_cb + # Most drivers (e.g. SDL) self-pump via an lv_timer_t they register + # internally, so the plain lv.task_handler() (== lv_timer_handler()) + # is all that's needed here. Some (e.g. Wayland) instead require a + # driver-specific wrapper -- lv.wayland_timer_handler() -- to be + # called *instead of* the plain handler, since it does its own + # input/window event handling around the same inner call. Pass that + # wrapper as handler_cb for those. + self.handler_cb = handler_cb if handler_cb else lv.task_handler self.exception_sink = ( exception_sink if exception_sink else self.default_exception_sink ) @@ -145,7 +154,7 @@ def current_instance(): def task_handler(self, _): try: if lv._nesting.value == 0: - lv.task_handler() + self.handler_cb() if self.refresh_cb: self.refresh_cb() self.scheduled -= 1 @@ -178,7 +187,7 @@ async def async_refresh(self): if lv._nesting.value == 0: self.refresh_event.clear() try: - lv.task_handler() + self.handler_cb() except Exception as e: if self.exception_sink: self.exception_sink(e) diff --git a/lv_conf.h b/lv_conf.h index e37f8426f9..bcffd0f6e7 100644 --- a/lv_conf.h +++ b/lv_conf.h @@ -26,8 +26,24 @@ COLOR SETTINGS *====================*/ -/** Color depth: 1 (I1), 8 (L8), 16 (RGB565), 24 (RGB888), 32 (XRGB8888) */ -#define LV_COLOR_DEPTH 16 +/** Color depth: 1 (I1), 8 (L8), 16 (RGB565), 24 (RGB888), 32 (XRGB8888) + * lv_wayland_window_create() takes no color-format argument -- it creates + * its display internally and picks the SHM pixel format from whatever + * LV_COLOR_DEPTH is, with no per-call override available. wl_shm's + * XRGB8888/ARGB8888 are the only formats mandatory per-spec; RGB565 + * support is optional and compositor-dependent, and on one that doesn't + * advertise it, lv_wayland_window_create() hangs waiting for a + * wl_shm.format event that never arrives. So this must be 32 whenever the + * Wayland driver is compiled in, and is left at the original 16 + * otherwise, unconditionally forcing every other consumer of this build + * (SDL included) to 32bpp too on systems where wayland-client happens to + * be installed even if they don't personally use lv.wayland_window_create_simple. + * See README.md's "Wayland driver" section. */ +#ifdef MICROPY_WAYLAND + #define LV_COLOR_DEPTH 32 +#else + #define LV_COLOR_DEPTH 16 +#endif /*========================= STDLIB WRAPPER SETTINGS @@ -1341,8 +1357,18 @@ extern void mp_lv_deinit_gc(); #endif /** Use Wayland to open a window and handle input on Linux or BSD desktops */ -#define LV_USE_WAYLAND 0 +#ifdef MICROPY_WAYLAND + #define LV_USE_WAYLAND MICROPY_WAYLAND +#else + #define LV_USE_WAYLAND 0 +#endif #if LV_USE_WAYLAND + /* NOTE: =1 (drawn client-side decorations) hits a real, reproducible + * abort ("Too many bits for size_t", a bad size in a wl_shm request) + * in the decoration-surface teardown path on lv_wayland_window_close() + * -- a timing/lifecycle bug in lv_wl_window_decorations.c, unrelated to + * anything in this binding. Left at the upstream default until that's + * fixed; windows are simply undecorated (no title bar) meanwhile. */ #define LV_WAYLAND_WINDOW_DECORATIONS 0 /**< Draw client side window decorations only necessary on Mutter/GNOME */ #define LV_WAYLAND_WL_SHELL 0 /**< Use the legacy wl_shell protocol instead of the default XDG shell */ #endif diff --git a/micropython.mk b/micropython.mk index a884a4466e..5f574e868f 100644 --- a/micropython.mk +++ b/micropython.mk @@ -20,6 +20,31 @@ ifeq ($(UNAME_S),Darwin) CFLAGS_USERMOD:=$(filter-out -I/usr/local/include,$(CFLAGS_USERMOD)) endif +WAYLAND_CFLAGS_USERMOD := $(shell pkg-config --silence-errors --cflags wayland-client wayland-cursor xkbcommon) +WAYLAND_LDFLAGS_USERMOD := $(shell pkg-config --silence-errors --libs wayland-client wayland-cursor xkbcommon) +WAYLAND_SCANNER := $(shell pkg-config --silence-errors --variable=wayland_scanner wayland-scanner) +ifeq ($(WAYLAND_SCANNER),) +WAYLAND_SCANNER := $(shell command -v wayland-scanner) +endif +WAYLAND_PROTOCOLS_DIR := $(shell pkg-config --silence-errors --variable=pkgdatadir wayland-protocols) +ifneq ($(and $(WAYLAND_LDFLAGS_USERMOD),$(WAYLAND_SCANNER),$(WAYLAND_PROTOCOLS_DIR)),) +# lv_wl_xdg_shell.c needs generated xdg-shell client protocol glue that +# isn't shipped by wayland-protocols as source. Generate it eagerly (at +# Makefile-parse time, like the pkg-config detection above) into the +# build dir so it exists before any compilation starts -- a build *rule* +# for this would race lv_wl_xdg_shell.c's compile on a parallel first build, +# since nothing else orders one before the other. +LVGL_WAYLAND_PROTOCOLS_DIR := $(BUILD)/lvgl/wayland_protocols +LVGL_WAYLAND_XDG_SHELL_XML := $(WAYLAND_PROTOCOLS_DIR)/stable/xdg-shell/xdg-shell.xml +$(shell mkdir -p $(LVGL_WAYLAND_PROTOCOLS_DIR)) +$(shell $(WAYLAND_SCANNER) client-header $(LVGL_WAYLAND_XDG_SHELL_XML) $(LVGL_WAYLAND_PROTOCOLS_DIR)/wayland_xdg_shell.h) +$(shell $(WAYLAND_SCANNER) private-code $(LVGL_WAYLAND_XDG_SHELL_XML) $(LVGL_WAYLAND_PROTOCOLS_DIR)/wayland_xdg_shell.c) + +CFLAGS_USERMOD += $(WAYLAND_CFLAGS_USERMOD) -DMICROPY_WAYLAND=1 -I$(LVGL_WAYLAND_PROTOCOLS_DIR) -I$(USERMOD_DIR)/lvgl +LDFLAGS_USERMOD += $(WAYLAND_LDFLAGS_USERMOD) +SRC_USERMOD_LIB_C += $(LVGL_WAYLAND_PROTOCOLS_DIR)/wayland_xdg_shell.c +endif + RLOTTIE_CFLAGS_USERMOD := $(shell pkg-config --silence-errors --cflags rlottie) RLOTTIE_LDFLAGS_USERMOD := $(shell pkg-config --silence-errors --libs rlottie) ifneq ($(RLOTTIE_LDFLAGS_USERMOD),) @@ -76,16 +101,17 @@ CFLAGS_USERMOD += -DLV_CONF_PATH='"$(LV_CONF_PATH)"' -Wno-deprecated-declaration # CFLAGS DEBUG $(info CFLAGS_USERMOD is $(CFLAGS_USERMOD)) -$(LVGL_MPY): $(ALL_LVGL_SRC) $(LVGL_BINDING_DIR)/gen/gen_mpy.py +$(LVGL_MPY): $(ALL_LVGL_SRC) $(LVGL_BINDING_DIR)/gen/gen_mpy.py $(LVGL_BINDING_DIR)/gen/lv_mpy_drivers.h $(ECHO) "LVGL-GEN $@" $(Q)mkdir -p $(dir $@) $(Q)$(CPP) -DPYCPARSER -x c \ -I $(LVGL_BINDING_DIR)/stubs/include/freetype2 \ -I $(LVGL_BINDING_DIR)/pycparser/utils/fake_libc_include \ -I $(LVGL_BINDING_DIR)/stubs/include \ + -I $(LVGL_DIR) \ $(CFLAGS_USERMOD) \ - $(LVGL_DIR)/lvgl_private.h > $(LVGL_PP) - $(Q)$(PYTHON) $(LVGL_BINDING_DIR)/gen/gen_mpy.py -M lvgl -MP lv -MD $(LVGL_MPY_METADATA) -E $(LVGL_PP) $(LVGL_DIR)/lvgl.h > $@ + $(LVGL_BINDING_DIR)/gen/lv_mpy_drivers.h > $(LVGL_PP) + $(Q)$(PYTHON) $(LVGL_BINDING_DIR)/gen/gen_mpy.py -M lvgl -MP lv -MD $(LVGL_MPY_METADATA) -E $(LVGL_PP) $(LVGL_DIR)/lvgl.h $(LVGL_BINDING_DIR)/gen/lv_mpy_drivers.h > $@ .PHONY: LVGL_MPY LVGL_MPY: $(LVGL_MPY) @@ -96,6 +122,9 @@ CFLAGS_EXTRA += -Wno-unused-function # LVGL SRC SRC_USERMOD_LIB_C += $(shell find $(LVGL_DIR)/src -type f -name "*.c") +# Binding-friendly wrappers for driver functions gen_mpy can't bind as-is +SRC_USERMOD_LIB_C += $(LVGL_BINDING_DIR)/gen/lv_mpy_drivers.c + # LVGL GENERIC DRIVER SRC_USERMOD_LIB_C += $(shell find $(LVGL_GENERIC_DRV_DIR) -type f -name "*.c") diff --git a/tests/README.md b/tests/README.md index ae21db717e..735606e105 100644 --- a/tests/README.md +++ b/tests/README.md @@ -17,6 +17,11 @@ To run from `micropython/tests`: ``` e.g. in unix port a display will appear to provide visual feedback. +On desktop (unix port), `display/` and `indev/` fall back to a native window +driver, selected via `display_config.DRIVER` ("sdl", the default, or +"wayland") - or the `LV_MP_TEST_DRIVER` env var, so CI can run the same +tests against both without duplicating them. See README.md's "Wayland +driver" section. - `indev/`: These are to test the `display` + indev (touch) driver. Intended for interactive HIL testing, e.g. they expect user input to complete the test. diff --git a/tests/display/display_config.py b/tests/display/display_config.py index 5eecf364c5..9e95f9066a 100644 --- a/tests/display/display_config.py +++ b/tests/display/display_config.py @@ -1,7 +1,11 @@ +import os import lvgl as lv MODE = "interactive" POINTER = "sim" +# "sdl" (default) or "wayland" -- set via env var so CI can exercise the +# same tests against both desktop drivers without duplicating test files. +DRIVER = os.getenv("LV_MP_TEST_DRIVER", "sdl") WIDTH = 240 HEIGHT = 320 COLOR_FORMAT = lv.COLOR_FORMAT.RGB888 diff --git a/tests/indev/display_config.py b/tests/indev/display_config.py index 59321c4553..29ec4f80ab 100644 --- a/tests/indev/display_config.py +++ b/tests/indev/display_config.py @@ -1,7 +1,11 @@ +import os import lvgl as lv MODE = "interactive" POINTER = "interactive" +# "sdl" (default) or "wayland" -- set via env var so CI can exercise the +# same tests against both desktop drivers without duplicating test files. +DRIVER = os.getenv("LV_MP_TEST_DRIVER", "sdl") WIDTH = 240 HEIGHT = 320 COLOR_FORMAT = lv.COLOR_FORMAT.RGB888 diff --git a/tests/testdisplay.py b/tests/testdisplay.py index 9c87a13ced..52431145d4 100644 --- a/tests/testdisplay.py +++ b/tests/testdisplay.py @@ -14,6 +14,9 @@ class TestDisplayConfig: HEIGHT = 320 MODE = "sim" POINTER = "sim" + # Desktop window driver used when MODE == "interactive" and no real + # hardware display driver is found: "sdl" or "wayland". + DRIVER = "sdl" COLOR_FORMAT = lv.COLOR_FORMAT.RGB888 RENDER_MODE = lv.DISPLAY_RENDER_MODE.PARTIAL SHOW_INFO = True @@ -31,6 +34,7 @@ def __init__( pointer="sim", render_mode=lv.DISPLAY_RENDER_MODE.PARTIAL, fps=25, + driver="sdl", ): self.display_drv = display_drv self._color_size = lv.color_format_get_size(color_format) @@ -45,9 +49,18 @@ def __init__( self._debug_press = True self._debug_release = True self.mode = mode + self.driver = driver if not lv_utils.event_loop.is_running(): - self.event_loop = lv_utils.event_loop(freq=fps, asynchronous=True) + # lv_wayland_window_create()'d windows must be pumped via + # lv.wayland_timer_handler() instead of the plain lv.task_handler() + # -- see the comment on event_loop's handler_cb in lv_utils.py. + _handler_cb = ( + lv.wayland_timer_handler if driver == "wayland" else None + ) + self.event_loop = lv_utils.event_loop( + freq=fps, asynchronous=True, handler_cb=_handler_cb + ) else: self.event_loop = lv_utils.event_loop.current_instance() @@ -95,23 +108,31 @@ def __init__( else: self.indev.set_read_cb(self._read_cb) - else: # interactive + DummyDisplay -> SDL + else: # interactive + DummyDisplay -> desktop window driver self.group = lv.group_create() self.group.set_default() - self.lv_display = lv.sdl_window_create( - display_drv.width, display_drv.height - ) - lv.sdl_window_set_title(self.lv_display, "MicroPython-LVGL") - if hasattr(display_drv, "window_pos") and hasattr( - lv, "sdl_window_set_position" - ): - if any(display_drv.window_pos): - lv.sdl_window_set_position(self.lv_display, *display_drv.window_pos) - lv.sdl_window_set_opacity(self.lv_display, 1.0) - lv.sdl_window_set_bordered(self.lv_display, 1) - self.mouse = lv.sdl_mouse_create() - self.keyboard = lv.sdl_keyboard_create() - self.keyboard.set_group(self.group) + if driver == "wayland": + self.lv_display = lv.wayland_window_create_simple( + display_drv.width, display_drv.height, "MicroPython-LVGL" + ) + self.mouse = lv.wayland_pointer_create() + self.keyboard = lv.wayland_keyboard_create() + self.keyboard.set_group(self.group) + else: # "sdl" + self.lv_display = lv.sdl_window_create( + display_drv.width, display_drv.height + ) + lv.sdl_window_set_title(self.lv_display, "MicroPython-LVGL") + if hasattr(display_drv, "window_pos") and hasattr( + lv, "sdl_window_set_position" + ): + if any(display_drv.window_pos): + lv.sdl_window_set_position(self.lv_display, *display_drv.window_pos) + lv.sdl_window_set_opacity(self.lv_display, 1.0) + lv.sdl_window_set_bordered(self.lv_display, 1) + self.mouse = lv.sdl_mouse_create() + self.keyboard = lv.sdl_keyboard_create() + self.keyboard.set_group(self.group) if pointer in ("sim", "encoder"): self.indev = lv.indev_create() self.indev.set_display(self.lv_display) @@ -316,6 +337,7 @@ def get_display( color_format=lv.COLOR_FORMAT.RGB888, mode="sim", pointer="sim", + driver="sdl", show_display_info=False, render_mode=lv.DISPLAY_RENDER_MODE.PARTIAL, window_pos=(None, None), @@ -376,5 +398,5 @@ def get_display( fbuf1 = alloc_buffer(buffer_size) fbuf2 = alloc_buffer(buffer_size) if double_buf else None return TestDisplayDriver( - disp, fbuf1, fbuf2, color_format, mode, pointer, render_mode + disp, fbuf1, fbuf2, color_format, mode, pointer, render_mode, driver=driver ) diff --git a/tests/testrunner.py b/tests/testrunner.py index 7e269fe726..90ca960eda 100644 --- a/tests/testrunner.py +++ b/tests/testrunner.py @@ -52,11 +52,14 @@ async def _run(func, disp_config=disp_config, **kwargs): if hasattr(disp_config, "WINDOW_POS"): display_config.WINDOW_POS = disp_config.WINDOW_POS + if hasattr(disp_config, "DRIVER"): + display_config.DRIVER = disp_config.DRIVER display = get_display( disp_config.WIDTH, disp_config.HEIGHT, mode=disp_config.MODE if disp_config.MODE is not None else _mode, pointer=disp_config.POINTER, + driver=getattr(display_config, "DRIVER", "sdl"), color_format=display_config.COLOR_FORMAT, render_mode=display_config.RENDER_MODE, show_display_info=display_config.SHOW_INFO,