Skip to content

Commit dad3b57

Browse files
committed
drivers: display: sdl: Ensure draw is performed from init thread
Add a thread to the SDL display driver to ensure that init and renderer calls are performed from the same thread. Fixes #71410. Signed-off-by: Fabian Blatz <[email protected]>
1 parent c657904 commit dad3b57

File tree

2 files changed

+144
-32
lines changed

2 files changed

+144
-32
lines changed

drivers/display/Kconfig.sdl

+6
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,10 @@ config SDL_DISPLAY_TRANSPARENCY_GRID_CELL_COLOR_2
8080
help
8181
The color of the even cells in the transparency grid.
8282

83+
config SDL_DISPLAY_THREAD_PRIORITY
84+
int "SDL display thread priority"
85+
default 0
86+
help
87+
Drawing thread priority.
88+
8389
endif # SDL_DISPLAY

drivers/display/display_sdl.c

+138-32
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77

88
#define DT_DRV_COMPAT zephyr_sdl_dc
99

10+
#include <zephyr/kernel.h>
1011
#include <zephyr/drivers/display.h>
1112

13+
#include <nsi_tracing.h>
1214
#include <string.h>
1315
#include <stdlib.h>
1416
#include <soc.h>
@@ -22,6 +24,26 @@ LOG_MODULE_REGISTER(display_sdl);
2224

2325
static uint32_t sdl_display_zoom_pct;
2426

27+
enum sdl_display_op {
28+
SDL_WRITE,
29+
SDL_BLANKING_OFF,
30+
SDL_BLANKING_ON,
31+
};
32+
33+
struct sdl_display_write {
34+
uint16_t x;
35+
uint16_t y;
36+
const struct display_buffer_descriptor *desc;
37+
};
38+
39+
struct sdl_display_task {
40+
enum sdl_display_op op;
41+
union {
42+
struct sdl_display_write write;
43+
};
44+
};
45+
46+
2547
struct sdl_display_config {
2648
uint16_t height;
2749
uint16_t width;
@@ -38,6 +60,12 @@ struct sdl_display_data {
3860
enum display_pixel_format current_pixel_format;
3961
uint8_t *buf;
4062
uint8_t *read_buf;
63+
struct k_thread sdl_thread;
64+
65+
K_KERNEL_STACK_MEMBER(sdl_thread_stack, CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE);
66+
struct k_msgq *task_msgq;
67+
struct k_sem task_sem;
68+
struct k_mutex task_mutex;
4169
};
4270

4371
static inline uint32_t mono_pixel_order(uint32_t order)
@@ -49,14 +77,73 @@ static inline uint32_t mono_pixel_order(uint32_t order)
4977
}
5078
}
5179

52-
static int sdl_display_init(const struct device *dev)
80+
static void exec_sdl_task(const struct device *dev, const struct sdl_display_task *task)
5381
{
82+
struct sdl_display_data *disp_data = dev->data;
83+
84+
switch (task->op) {
85+
case SDL_WRITE:
86+
sdl_display_write_bottom(task->write.desc->height, task->write.desc->width,
87+
task->write.x, task->write.y, disp_data->renderer,
88+
disp_data->mutex, disp_data->texture,
89+
disp_data->background_texture, disp_data->buf,
90+
disp_data->display_on,
91+
task->write.desc->frame_incomplete);
92+
break;
93+
case SDL_BLANKING_OFF:
94+
sdl_display_blanking_off_bottom(disp_data->renderer, disp_data->texture,
95+
disp_data->background_texture);
96+
break;
97+
case SDL_BLANKING_ON:
98+
sdl_display_blanking_on_bottom(disp_data->renderer);
99+
break;
100+
default:
101+
LOG_ERR("Unknown SDL task");
102+
break;
103+
}
104+
}
105+
106+
static void sdl_task_thread(void *p1, void *p2, void *p3)
107+
{
108+
const struct device *dev = p1;
109+
struct sdl_display_data *disp_data = dev->data;
54110
const struct sdl_display_config *config = dev->config;
111+
struct sdl_display_task task;
112+
bool use_accelerator =
113+
IS_ENABLED(CONFIG_SDL_DISPLAY_USE_HARDWARE_ACCELERATOR);
114+
115+
if (sdl_display_zoom_pct == UINT32_MAX) {
116+
sdl_display_zoom_pct = CONFIG_SDL_DISPLAY_ZOOM_PCT;
117+
}
118+
119+
int rc = sdl_display_init_bottom(config->height, config->width, sdl_display_zoom_pct,
120+
use_accelerator, &disp_data->window, dev,
121+
&disp_data->renderer, &disp_data->mutex,
122+
&disp_data->texture, &disp_data->read_texture,
123+
&disp_data->background_texture,
124+
CONFIG_SDL_DISPLAY_TRANSPARENCY_GRID_CELL_COLOR_1,
125+
CONFIG_SDL_DISPLAY_TRANSPARENCY_GRID_CELL_COLOR_2,
126+
CONFIG_SDL_DISPLAY_TRANSPARENCY_GRID_CELL_SIZE);
127+
128+
if (rc != 0) {
129+
nsi_print_error_and_exit("Failed to create SDL display");
130+
return;
131+
}
132+
133+
disp_data->display_on = false;
134+
135+
while (1) {
136+
k_msgq_get(disp_data->task_msgq, &task, K_FOREVER);
137+
exec_sdl_task(dev, &task);
138+
k_sem_give(&disp_data->task_sem);
139+
}
140+
}
141+
142+
static int sdl_display_init(const struct device *dev)
143+
{
55144
struct sdl_display_data *disp_data = dev->data;
56-
bool use_accelerator = true;
57-
LOG_DBG("Initializing display driver");
58145

59-
IF_DISABLED(CONFIG_SDL_DISPLAY_USE_HARDWARE_ACCELERATOR, (use_accelerator = false));
146+
LOG_DBG("Initializing display driver");
60147

61148
disp_data->current_pixel_format =
62149
#if defined(CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_RGB_888)
@@ -76,25 +163,12 @@ static int sdl_display_init(const struct device *dev)
76163
#endif /* SDL_DISPLAY_DEFAULT_PIXEL_FORMAT */
77164
;
78165

79-
if (sdl_display_zoom_pct == UINT32_MAX) {
80-
sdl_display_zoom_pct = CONFIG_SDL_DISPLAY_ZOOM_PCT;
81-
}
82-
83-
int rc = sdl_display_init_bottom(config->height, config->width, sdl_display_zoom_pct,
84-
use_accelerator, &disp_data->window, dev,
85-
&disp_data->renderer, &disp_data->mutex,
86-
&disp_data->texture, &disp_data->read_texture,
87-
&disp_data->background_texture,
88-
CONFIG_SDL_DISPLAY_TRANSPARENCY_GRID_CELL_COLOR_1,
89-
CONFIG_SDL_DISPLAY_TRANSPARENCY_GRID_CELL_COLOR_2,
90-
CONFIG_SDL_DISPLAY_TRANSPARENCY_GRID_CELL_SIZE);
91-
92-
if (rc != 0) {
93-
LOG_ERR("Failed to create SDL display");
94-
return -EIO;
95-
}
96-
97-
disp_data->display_on = false;
166+
k_sem_init(&disp_data->task_sem, 1, 1);
167+
k_mutex_init(&disp_data->task_mutex);
168+
k_thread_create(&disp_data->sdl_thread, disp_data->sdl_thread_stack,
169+
K_KERNEL_STACK_SIZEOF(disp_data->sdl_thread_stack),
170+
sdl_task_thread, (void *)dev, NULL, NULL,
171+
CONFIG_SDL_DISPLAY_THREAD_PRIORITY, 0, K_NO_WAIT);
98172

99173
return 0;
100174
}
@@ -253,6 +327,14 @@ static int sdl_display_write(const struct device *dev, const uint16_t x,
253327
{
254328
const struct sdl_display_config *config = dev->config;
255329
struct sdl_display_data *disp_data = dev->data;
330+
struct sdl_display_task task = {
331+
.op = SDL_WRITE,
332+
.write = {
333+
.x = x,
334+
.y = y,
335+
.desc = desc,
336+
},
337+
};
256338

257339
LOG_DBG("Writing %dx%d (w,h) bitmap @ %dx%d (x,y)", desc->width,
258340
desc->height, x, y);
@@ -289,10 +371,14 @@ static int sdl_display_write(const struct device *dev, const uint16_t x,
289371
sdl_display_write_l8(disp_data->buf, desc, buf);
290372
}
291373

292-
sdl_display_write_bottom(desc->height, desc->width, x, y, disp_data->renderer,
293-
disp_data->mutex, disp_data->texture,
294-
disp_data->background_texture, disp_data->buf,
295-
disp_data->display_on, desc->frame_incomplete);
374+
if (k_current_get() == &disp_data->sdl_thread) {
375+
exec_sdl_task(dev, &task);
376+
} else {
377+
k_mutex_lock(&disp_data->task_mutex, K_FOREVER);
378+
k_sem_take(&disp_data->task_sem, K_FOREVER);
379+
k_msgq_put(disp_data->task_msgq, &task, K_FOREVER);
380+
k_mutex_unlock(&disp_data->task_mutex);
381+
}
296382

297383
return 0;
298384
}
@@ -517,26 +603,44 @@ static int sdl_display_clear(const struct device *dev)
517603
static int sdl_display_blanking_off(const struct device *dev)
518604
{
519605
struct sdl_display_data *disp_data = dev->data;
606+
struct sdl_display_task task = {
607+
.op = SDL_BLANKING_OFF,
608+
};
520609

521610
LOG_DBG("Turning display blacking off");
522-
523611
disp_data->display_on = true;
524612

525-
sdl_display_blanking_off_bottom(disp_data->renderer, disp_data->texture,
526-
disp_data->background_texture);
613+
if (k_current_get() == &disp_data->sdl_thread) {
614+
exec_sdl_task(dev, &task);
615+
} else {
616+
k_mutex_lock(&disp_data->task_mutex, K_FOREVER);
617+
k_sem_take(&disp_data->task_sem, K_FOREVER);
618+
k_msgq_put(disp_data->task_msgq, &task, K_FOREVER);
619+
k_mutex_unlock(&disp_data->task_mutex);
620+
}
527621

528622
return 0;
529623
}
530624

531625
static int sdl_display_blanking_on(const struct device *dev)
532626
{
533627
struct sdl_display_data *disp_data = dev->data;
628+
struct sdl_display_task task = {
629+
.op = SDL_BLANKING_ON,
630+
};
534631

535632
LOG_DBG("Turning display blanking on");
536-
537633
disp_data->display_on = false;
538634

539-
sdl_display_blanking_on_bottom(disp_data->renderer);
635+
if (k_current_get() == &disp_data->sdl_thread) {
636+
exec_sdl_task(dev, &task);
637+
} else {
638+
k_mutex_lock(&disp_data->task_mutex, K_FOREVER);
639+
k_sem_take(&disp_data->task_sem, K_FOREVER);
640+
k_msgq_put(disp_data->task_msgq, &task, K_FOREVER);
641+
k_mutex_unlock(&disp_data->task_mutex);
642+
}
643+
540644
return 0;
541645
}
542646

@@ -609,9 +713,11 @@ static DEVICE_API(display, sdl_display_api) = {
609713
* DT_INST_PROP(n, width)]; \
610714
static uint8_t sdl_read_buf_##n[4 * DT_INST_PROP(n, height) \
611715
* DT_INST_PROP(n, width)]; \
716+
K_MSGQ_DEFINE(sdl_task_msgq_##n, sizeof(struct sdl_display_task), 1, 4); \
612717
static struct sdl_display_data sdl_data_##n = { \
613718
.buf = sdl_buf_##n, \
614719
.read_buf = sdl_read_buf_##n, \
720+
.task_msgq = &sdl_task_msgq_##n, \
615721
}; \
616722
\
617723
DEVICE_DT_INST_DEFINE(n, &sdl_display_init, NULL, \

0 commit comments

Comments
 (0)