Skip to content

Commit da59df2

Browse files
danieldegrassecarlescufi
authored andcommitted
modules: lvgl: allow offloading rendering process to background thread
Enable offloading of display_write call to background thread for color displays. This feature is opt-in, as it may offer significant performance gains for every display pipeline. When enabled display_write and lv_disp_flush_ready will be called from a background thread. This means that while the display driver waits on the hardware to render the framebuffer, the LVGL rendering thread will not be blocked. Signed-off-by: Daniel DeGrasse <[email protected]>
1 parent 82bfb26 commit da59df2

6 files changed

+132
-28
lines changed

modules/lvgl/Kconfig

+24
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Copyright (c) 2023 Fabian Blatz <[email protected]>
2+
# Copyright 2023 NXP
23
# SPDX-License-Identifier: Apache-2.0
34

45
config ZEPHYR_LVGL_MODULE
@@ -53,6 +54,29 @@ endchoice
5354
config LV_COLOR_16_SWAP
5455
bool
5556

57+
config LV_Z_FLUSH_THREAD
58+
bool "Flush LVGL frames in a separate thread"
59+
help
60+
Flush LVGL frames in a separate thread, while the primary thread
61+
renders the next LVGL frame. Can be disabled if the performance
62+
gain this approach offers is not required
63+
64+
if LV_Z_FLUSH_THREAD
65+
66+
config LV_Z_FLUSH_THREAD_STACK_SIZE
67+
int "Stack size for flushing thread"
68+
default 1024
69+
help
70+
Stack size for LVGL flush thread, which will call display_write
71+
72+
config LV_Z_FLUSH_THREAD_PRIO
73+
int "LVGL flush thread priority"
74+
default 0
75+
help
76+
Cooperative priority of LVGL flush thread.
77+
78+
endif # LV_Z_FLUSH_THREAD
79+
5680
rsource "Kconfig.memory"
5781
rsource "Kconfig.input"
5882
rsource "Kconfig.shell"

modules/lvgl/lvgl_display.c

+63
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,59 @@
11
/*
22
* Copyright (c) 2019 Jan Van Winkel <[email protected]>
3+
* Copyright 2023 NXP
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
67

8+
#include <zephyr/kernel.h>
79
#include <errno.h>
810

911
#include "lvgl_display.h"
1012

13+
#ifdef CONFIG_LV_Z_FLUSH_THREAD
14+
15+
K_SEM_DEFINE(flush_complete, 0, 1);
16+
/* Message queue will only ever need to queue one message */
17+
K_MSGQ_DEFINE(flush_queue, sizeof(struct lvgl_display_flush), 1, 1);
18+
19+
void lvgl_flush_thread_entry(void *arg1, void *arg2, void *arg3)
20+
{
21+
struct lvgl_display_flush flush;
22+
struct lvgl_disp_data *data;
23+
24+
while (1) {
25+
k_msgq_get(&flush_queue, &flush, K_FOREVER);
26+
data = (struct lvgl_disp_data *)flush.disp_drv->user_data;
27+
28+
display_write(data->display_dev, flush.x, flush.y, &flush.desc,
29+
flush.buf);
30+
31+
lv_disp_flush_ready(flush.disp_drv);
32+
k_sem_give(&flush_complete);
33+
}
34+
}
35+
36+
K_THREAD_DEFINE(lvgl_flush_thread, CONFIG_LV_Z_FLUSH_THREAD_STACK_SIZE,
37+
lvgl_flush_thread_entry, NULL, NULL, NULL,
38+
K_PRIO_COOP(CONFIG_LV_Z_FLUSH_THREAD_PRIO), 0, 0);
39+
40+
41+
void lvgl_wait_cb(lv_disp_drv_t *disp_drv)
42+
{
43+
k_sem_take(&flush_complete, K_FOREVER);
44+
}
45+
46+
#endif /* CONFIG_LV_Z_FLUSH_THREAD */
47+
1148
int set_lvgl_rendering_cb(lv_disp_drv_t *disp_drv)
1249
{
1350
int err = 0;
1451
struct lvgl_disp_data *data = (struct lvgl_disp_data *)disp_drv->user_data;
1552

53+
#ifdef CONFIG_LV_Z_FLUSH_THREAD
54+
disp_drv->wait_cb = lvgl_wait_cb;
55+
#endif
56+
1657
switch (data->cap.current_pixel_format) {
1758
case PIXEL_FORMAT_ARGB_8888:
1859
disp_drv->flush_cb = lvgl_flush_cb_32bit;
@@ -54,3 +95,25 @@ int set_lvgl_rendering_cb(lv_disp_drv_t *disp_drv)
5495

5596
return err;
5697
}
98+
99+
void lvgl_flush_display(struct lvgl_display_flush *request)
100+
{
101+
#ifdef CONFIG_LV_Z_FLUSH_THREAD
102+
/*
103+
* LVGL will only start a flush once the previous one is complete,
104+
* so we can reset the flush state semaphore here.
105+
*/
106+
k_sem_reset(&flush_complete);
107+
k_msgq_put(&flush_queue, request, K_FOREVER);
108+
/* Explicitly yield, in case the calling thread is a cooperative one */
109+
k_yield();
110+
#else
111+
/* Write directly to the display */
112+
struct lvgl_disp_data *data =
113+
(struct lvgl_disp_data *)request->disp_drv->user_data;
114+
115+
display_write(data->display_dev, request->x, request->y,
116+
&request->desc, request->buf);
117+
lv_disp_flush_ready(request->disp_drv);
118+
#endif
119+
}

modules/lvgl/lvgl_display.h

+11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2019 Jan Van Winkel <[email protected]>
3+
* Copyright 2023 NXP
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
@@ -20,6 +21,14 @@ struct lvgl_disp_data {
2021
bool blanking_on;
2122
};
2223

24+
struct lvgl_display_flush {
25+
lv_disp_drv_t *disp_drv;
26+
uint16_t x;
27+
uint16_t y;
28+
struct display_buffer_descriptor desc;
29+
void *buf;
30+
};
31+
2332
void lvgl_flush_cb_mono(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p);
2433
void lvgl_flush_cb_16bit(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p);
2534
void lvgl_flush_cb_24bit(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p);
@@ -38,6 +47,8 @@ void lvgl_rounder_cb_mono(lv_disp_drv_t *disp_drv, lv_area_t *area);
3847

3948
int set_lvgl_rendering_cb(lv_disp_drv_t *disp_drv);
4049

50+
void lvgl_flush_display(struct lvgl_display_flush *request);
51+
4152
#ifdef __cplusplus
4253
}
4354
#endif

modules/lvgl/lvgl_display_16bit.c

+11-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2019 Jan Van Winkel <[email protected]>
3+
* Copyright 2023 NXP
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
@@ -10,18 +11,19 @@
1011

1112
void lvgl_flush_cb_16bit(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
1213
{
13-
struct lvgl_disp_data *data = (struct lvgl_disp_data *)disp_drv->user_data;
1414
uint16_t w = area->x2 - area->x1 + 1;
1515
uint16_t h = area->y2 - area->y1 + 1;
16-
struct display_buffer_descriptor desc;
16+
struct lvgl_display_flush flush;
1717

18-
desc.buf_size = w * 2U * h;
19-
desc.width = w;
20-
desc.pitch = w;
21-
desc.height = h;
22-
display_write(data->display_dev, area->x1, area->y1, &desc, (void *)color_p);
23-
24-
lv_disp_flush_ready(disp_drv);
18+
flush.disp_drv = disp_drv;
19+
flush.x = area->x1;
20+
flush.y = area->y1;
21+
flush.desc.buf_size = w * 2U * h;
22+
flush.desc.width = w;
23+
flush.desc.pitch = w;
24+
flush.desc.height = h;
25+
flush.buf = (void *)color_p;
26+
lvgl_flush_display(&flush);
2527
}
2628

2729
#ifndef CONFIG_LV_COLOR_DEPTH_16

modules/lvgl/lvgl_display_24bit.c

+12-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2019 Jan Van Winkel <[email protected]>
3+
* Copyright 2023 NXP
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
@@ -10,18 +11,19 @@
1011

1112
void lvgl_flush_cb_24bit(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
1213
{
13-
struct lvgl_disp_data *data = (struct lvgl_disp_data *)disp_drv->user_data;
1414
uint16_t w = area->x2 - area->x1 + 1;
1515
uint16_t h = area->y2 - area->y1 + 1;
16-
struct display_buffer_descriptor desc;
17-
18-
desc.buf_size = w * 3U * h;
19-
desc.width = w;
20-
desc.pitch = w;
21-
desc.height = h;
22-
display_write(data->display_dev, area->x1, area->y1, &desc, (void *)color_p);
23-
24-
lv_disp_flush_ready(disp_drv);
16+
struct lvgl_display_flush flush;
17+
18+
flush.disp_drv = disp_drv;
19+
flush.x = area->x1;
20+
flush.y = area->y1;
21+
flush.desc.buf_size = w * 3U * h;
22+
flush.desc.width = w;
23+
flush.desc.pitch = w;
24+
flush.desc.height = h;
25+
flush.buf = (void *)color_p;
26+
lvgl_flush_display(&flush);
2527
}
2628

2729
void lvgl_set_px_cb_24bit(lv_disp_drv_t *disp_drv, uint8_t *buf, lv_coord_t buf_w, lv_coord_t x,

modules/lvgl/lvgl_display_32bit.c

+11-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2019 Jan Van Winkel <[email protected]>
3+
* Copyright 2023 NXP
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
@@ -10,18 +11,19 @@
1011

1112
void lvgl_flush_cb_32bit(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
1213
{
13-
struct lvgl_disp_data *data = (struct lvgl_disp_data *)disp_drv->user_data;
1414
uint16_t w = area->x2 - area->x1 + 1;
1515
uint16_t h = area->y2 - area->y1 + 1;
16-
struct display_buffer_descriptor desc;
16+
struct lvgl_display_flush flush;
1717

18-
desc.buf_size = w * 4U * h;
19-
desc.width = w;
20-
desc.pitch = w;
21-
desc.height = h;
22-
display_write(data->display_dev, area->x1, area->y1, &desc, (void *)color_p);
23-
24-
lv_disp_flush_ready(disp_drv);
18+
flush.disp_drv = disp_drv;
19+
flush.x = area->x1;
20+
flush.y = area->y1;
21+
flush.desc.buf_size = w * 4U * h;
22+
flush.desc.width = w;
23+
flush.desc.pitch = w;
24+
flush.desc.height = h;
25+
flush.buf = (void *)color_p;
26+
lvgl_flush_display(&flush);
2527
}
2628

2729
#ifndef CONFIG_LV_COLOR_DEPTH_32

0 commit comments

Comments
 (0)