Skip to content

Commit 11b9eba

Browse files
faxe1008kartben
authored andcommitted
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 061e345 commit 11b9eba

File tree

2 files changed

+152
-32
lines changed

2 files changed

+152
-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 NUM_PREEMPT_PRIORITIES
86+
help
87+
Drawing thread priority.
88+
8389
endif # SDL_DISPLAY

drivers/display/display_sdl.c

+146-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)
81+
{
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)
53107
{
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, 0, 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);
@@ -273,6 +355,7 @@ static int sdl_display_write(const struct device *dev, const uint16_t x,
273355
return -EINVAL;
274356
}
275357

358+
k_mutex_lock(&disp_data->task_mutex, K_FOREVER);
276359
if (disp_data->current_pixel_format == PIXEL_FORMAT_ARGB_8888) {
277360
sdl_display_write_argb8888(disp_data->buf, desc, buf);
278361
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_RGB_888) {
@@ -289,10 +372,14 @@ static int sdl_display_write(const struct device *dev, const uint16_t x,
289372
sdl_display_write_l8(disp_data->buf, desc, buf);
290373
}
291374

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);
375+
if (k_current_get() == &disp_data->sdl_thread) {
376+
exec_sdl_task(dev, &task);
377+
} else {
378+
k_msgq_put(disp_data->task_msgq, &task, K_FOREVER);
379+
k_sem_take(&disp_data->task_sem, K_FOREVER);
380+
}
381+
382+
k_mutex_unlock(&disp_data->task_mutex);
296383

297384
return 0;
298385
}
@@ -445,13 +532,15 @@ static int sdl_display_read(const struct device *dev, const uint16_t x, const ui
445532

446533
__ASSERT(desc->width <= desc->pitch, "Pitch is smaller than width");
447534

535+
k_mutex_lock(&disp_data->task_mutex, K_FOREVER);
448536
memset(disp_data->read_buf, 0, desc->pitch * desc->height * 4);
449537

450538
err = sdl_display_read_bottom(desc->height, desc->width, x, y, disp_data->renderer,
451539
disp_data->read_buf, desc->pitch, disp_data->mutex,
452540
disp_data->texture, disp_data->read_texture);
453541

454542
if (err) {
543+
k_mutex_unlock(&disp_data->task_mutex);
455544
return err;
456545
}
457546

@@ -470,6 +559,7 @@ static int sdl_display_read(const struct device *dev, const uint16_t x, const ui
470559
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_L_8) {
471560
sdl_display_read_l8(disp_data->read_buf, desc, buf);
472561
}
562+
k_mutex_unlock(&disp_data->task_mutex);
473563

474564
return 0;
475565
}
@@ -509,34 +599,56 @@ static int sdl_display_clear(const struct device *dev)
509599
return -EINVAL;
510600
}
511601
LOG_DBG("size: %zu, bgcolor: %hhu", size, bgcolor);
602+
k_mutex_lock(&disp_data->task_mutex, K_FOREVER);
512603
memset(disp_data->buf, bgcolor, size);
604+
k_mutex_unlock(&disp_data->task_mutex);
513605

514606
return 0;
515607
}
516608

517609
static int sdl_display_blanking_off(const struct device *dev)
518610
{
519611
struct sdl_display_data *disp_data = dev->data;
612+
struct sdl_display_task task = {
613+
.op = SDL_BLANKING_OFF,
614+
};
520615

521616
LOG_DBG("Turning display blacking off");
522-
523617
disp_data->display_on = true;
618+
k_mutex_lock(&disp_data->task_mutex, K_FOREVER);
524619

525-
sdl_display_blanking_off_bottom(disp_data->renderer, disp_data->texture,
526-
disp_data->background_texture);
620+
if (k_current_get() == &disp_data->sdl_thread) {
621+
exec_sdl_task(dev, &task);
622+
} else {
623+
k_msgq_put(disp_data->task_msgq, &task, K_FOREVER);
624+
k_sem_take(&disp_data->task_sem, K_FOREVER);
625+
}
626+
627+
k_mutex_unlock(&disp_data->task_mutex);
527628

528629
return 0;
529630
}
530631

531632
static int sdl_display_blanking_on(const struct device *dev)
532633
{
533634
struct sdl_display_data *disp_data = dev->data;
635+
struct sdl_display_task task = {
636+
.op = SDL_BLANKING_ON,
637+
};
534638

535639
LOG_DBG("Turning display blanking on");
536-
537640
disp_data->display_on = false;
641+
k_mutex_lock(&disp_data->task_mutex, K_FOREVER);
642+
643+
if (k_current_get() == &disp_data->sdl_thread) {
644+
exec_sdl_task(dev, &task);
645+
} else {
646+
k_msgq_put(disp_data->task_msgq, &task, K_FOREVER);
647+
k_sem_take(&disp_data->task_sem, K_FOREVER);
648+
}
649+
650+
k_mutex_unlock(&disp_data->task_mutex);
538651

539-
sdl_display_blanking_on_bottom(disp_data->renderer);
540652
return 0;
541653
}
542654

@@ -609,9 +721,11 @@ static DEVICE_API(display, sdl_display_api) = {
609721
* DT_INST_PROP(n, width)]; \
610722
static uint8_t sdl_read_buf_##n[4 * DT_INST_PROP(n, height) \
611723
* DT_INST_PROP(n, width)]; \
724+
K_MSGQ_DEFINE(sdl_task_msgq_##n, sizeof(struct sdl_display_task), 1, 4); \
612725
static struct sdl_display_data sdl_data_##n = { \
613726
.buf = sdl_buf_##n, \
614727
.read_buf = sdl_read_buf_##n, \
728+
.task_msgq = &sdl_task_msgq_##n, \
615729
}; \
616730
\
617731
DEVICE_DT_INST_DEFINE(n, &sdl_display_init, NULL, \

0 commit comments

Comments
 (0)