Skip to content

Commit bb5674d

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 bb5674d

File tree

2 files changed

+196
-71
lines changed

2 files changed

+196
-71
lines changed

drivers/display/Kconfig.sdl

+12
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,16 @@ 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_STACK_SIZE
84+
int "Stack size for SDL display thread"
85+
default 1024
86+
help
87+
The size of the thread stack used for dispatching drawing operations.
88+
89+
config SDL_DISPLAY_THREAD_PRIORITY
90+
int "SDL display thread priority"
91+
default 0
92+
help
93+
The thread priority of the drawing thread.
94+
8395
endif # SDL_DISPLAY

drivers/display/display_sdl.c

+184-71
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#define DT_DRV_COMPAT zephyr_sdl_dc
99

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

1213
#include <string.h>
@@ -22,6 +23,26 @@ LOG_MODULE_REGISTER(display_sdl);
2223

2324
static uint32_t sdl_display_zoom_pct;
2425

26+
enum sdl_display_op {
27+
SDL_WRITE,
28+
SDL_BLANKING_OFF,
29+
SDL_BLANKING_ON,
30+
};
31+
32+
struct sdl_display_write {
33+
uint16_t x;
34+
uint16_t y;
35+
const struct display_buffer_descriptor *desc;
36+
};
37+
38+
struct sdl_display_task {
39+
enum sdl_display_op op;
40+
union {
41+
struct sdl_display_write write;
42+
};
43+
};
44+
45+
2546
struct sdl_display_config {
2647
uint16_t height;
2748
uint16_t width;
@@ -38,6 +59,13 @@ struct sdl_display_data {
3859
enum display_pixel_format current_pixel_format;
3960
uint8_t *buf;
4061
uint8_t *read_buf;
62+
63+
struct k_spinlock lock;
64+
struct k_thread sdl_thread;
65+
66+
K_KERNEL_STACK_MEMBER(sdl_thread_stack, CONFIG_SDL_DISPLAY_THREAD_STACK_SIZE);
67+
struct k_msgq *task_msgq;
68+
struct k_sem task_sem;
4169
};
4270

4371
static inline uint32_t mono_pixel_order(uint32_t order)
@@ -49,32 +77,42 @@ 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
{
54-
const struct sdl_display_config *config = dev->config;
5582
struct sdl_display_data *disp_data = dev->data;
56-
bool use_accelerator = true;
57-
LOG_DBG("Initializing display driver");
5883

59-
IF_DISABLED(CONFIG_SDL_DISPLAY_USE_HARDWARE_ACCELERATOR, (use_accelerator = false));
84+
K_SPINLOCK(&disp_data->lock) {
85+
switch (task->op) {
86+
case SDL_WRITE:
87+
sdl_display_write_bottom(task->write.desc->height, task->write.desc->width,
88+
task->write.x, task->write.y, disp_data->renderer,
89+
disp_data->mutex, disp_data->texture,
90+
disp_data->background_texture, disp_data->buf,
91+
disp_data->display_on,
92+
task->write.desc->frame_incomplete);
93+
break;
94+
case SDL_BLANKING_OFF:
95+
sdl_display_blanking_off_bottom(disp_data->renderer, disp_data->texture,
96+
disp_data->background_texture);
97+
break;
98+
case SDL_BLANKING_ON:
99+
sdl_display_blanking_on_bottom(disp_data->renderer);
100+
break;
101+
default:
102+
LOG_ERR("Unknown SDL task");
103+
break;
104+
}
105+
}
106+
}
60107

61-
disp_data->current_pixel_format =
62-
#if defined(CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_RGB_888)
63-
PIXEL_FORMAT_RGB_888
64-
#elif defined(CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_MONO01)
65-
PIXEL_FORMAT_MONO01
66-
#elif defined(CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_MONO10)
67-
PIXEL_FORMAT_MONO10
68-
#elif defined(CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_RGB_565)
69-
PIXEL_FORMAT_RGB_565
70-
#elif defined(CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_BGR_565)
71-
PIXEL_FORMAT_BGR_565
72-
#elif defined(CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_L_8)
73-
PIXEL_FORMAT_L_8
74-
#else /* SDL_DISPLAY_DEFAULT_PIXEL_FORMAT */
75-
PIXEL_FORMAT_ARGB_8888
76-
#endif /* SDL_DISPLAY_DEFAULT_PIXEL_FORMAT */
77-
;
108+
static void sdl_task_thread(void *p1, void *p2, void *p3)
109+
{
110+
const struct device *dev = p1;
111+
struct sdl_display_data *disp_data = dev->data;
112+
const struct sdl_display_config *config = dev->config;
113+
struct sdl_display_task task;
114+
bool use_accelerator =
115+
IS_ENABLED(CONFIG_SDL_DISPLAY_USE_HARDWARE_ACCELERATOR);
78116

79117
if (sdl_display_zoom_pct == UINT32_MAX) {
80118
sdl_display_zoom_pct = CONFIG_SDL_DISPLAY_ZOOM_PCT;
@@ -91,11 +129,48 @@ static int sdl_display_init(const struct device *dev)
91129

92130
if (rc != 0) {
93131
LOG_ERR("Failed to create SDL display");
94-
return -EIO;
132+
return;
95133
}
96134

97135
disp_data->display_on = false;
98136

137+
while (1) {
138+
k_msgq_get(disp_data->task_msgq, &task, K_FOREVER);
139+
exec_sdl_task(dev, &task);
140+
k_sem_give(&disp_data->task_sem);
141+
}
142+
}
143+
144+
static int sdl_display_init(const struct device *dev)
145+
{
146+
struct sdl_display_data *disp_data = dev->data;
147+
148+
LOG_DBG("Initializing display driver");
149+
150+
disp_data->current_pixel_format =
151+
#if defined(CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_RGB_888)
152+
PIXEL_FORMAT_RGB_888
153+
#elif defined(CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_MONO01)
154+
PIXEL_FORMAT_MONO01
155+
#elif defined(CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_MONO10)
156+
PIXEL_FORMAT_MONO10
157+
#elif defined(CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_RGB_565)
158+
PIXEL_FORMAT_RGB_565
159+
#elif defined(CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_BGR_565)
160+
PIXEL_FORMAT_BGR_565
161+
#elif defined(CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_L_8)
162+
PIXEL_FORMAT_L_8
163+
#else /* SDL_DISPLAY_DEFAULT_PIXEL_FORMAT */
164+
PIXEL_FORMAT_ARGB_8888
165+
#endif /* SDL_DISPLAY_DEFAULT_PIXEL_FORMAT */
166+
;
167+
168+
k_sem_init(&disp_data->task_sem, 0, 1);
169+
k_thread_create(&disp_data->sdl_thread, disp_data->sdl_thread_stack,
170+
K_KERNEL_STACK_SIZEOF(disp_data->sdl_thread_stack),
171+
sdl_task_thread, (void *)dev, NULL, NULL,
172+
CONFIG_SDL_DISPLAY_THREAD_PRIORITY, 0, K_NO_WAIT);
173+
99174
return 0;
100175
}
101176

@@ -253,6 +328,14 @@ static int sdl_display_write(const struct device *dev, const uint16_t x,
253328
{
254329
const struct sdl_display_config *config = dev->config;
255330
struct sdl_display_data *disp_data = dev->data;
331+
struct sdl_display_task task = {
332+
.op = SDL_WRITE,
333+
.write = {
334+
.x = x,
335+
.y = y,
336+
.desc = desc,
337+
},
338+
};
256339

257340
LOG_DBG("Writing %dx%d (w,h) bitmap @ %dx%d (x,y)", desc->width,
258341
desc->height, x, y);
@@ -273,26 +356,30 @@ static int sdl_display_write(const struct device *dev, const uint16_t x,
273356
return -EINVAL;
274357
}
275358

276-
if (disp_data->current_pixel_format == PIXEL_FORMAT_ARGB_8888) {
277-
sdl_display_write_argb8888(disp_data->buf, desc, buf);
278-
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_RGB_888) {
279-
sdl_display_write_rgb888(disp_data->buf, desc, buf);
280-
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_MONO10) {
281-
sdl_display_write_mono(disp_data->buf, desc, buf, true);
282-
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_MONO01) {
283-
sdl_display_write_mono(disp_data->buf, desc, buf, false);
284-
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_RGB_565) {
285-
sdl_display_write_rgb565(disp_data->buf, desc, buf);
286-
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_BGR_565) {
287-
sdl_display_write_bgr565(disp_data->buf, desc, buf);
288-
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_L_8) {
289-
sdl_display_write_l8(disp_data->buf, desc, buf);
359+
K_SPINLOCK(&disp_data->lock) {
360+
if (disp_data->current_pixel_format == PIXEL_FORMAT_ARGB_8888) {
361+
sdl_display_write_argb8888(disp_data->buf, desc, buf);
362+
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_RGB_888) {
363+
sdl_display_write_rgb888(disp_data->buf, desc, buf);
364+
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_MONO10) {
365+
sdl_display_write_mono(disp_data->buf, desc, buf, true);
366+
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_MONO01) {
367+
sdl_display_write_mono(disp_data->buf, desc, buf, false);
368+
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_RGB_565) {
369+
sdl_display_write_rgb565(disp_data->buf, desc, buf);
370+
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_BGR_565) {
371+
sdl_display_write_bgr565(disp_data->buf, desc, buf);
372+
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_L_8) {
373+
sdl_display_write_l8(disp_data->buf, desc, buf);
374+
}
290375
}
291376

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

297384
return 0;
298385
}
@@ -438,40 +525,41 @@ static int sdl_display_read(const struct device *dev, const uint16_t x, const ui
438525
const struct display_buffer_descriptor *desc, void *buf)
439526
{
440527
struct sdl_display_data *disp_data = dev->data;
441-
int err;
528+
int err = 0;
442529

443530
LOG_DBG("Reading %dx%d (w,h) bitmap @ %dx%d (x,y)", desc->width,
444531
desc->height, x, y);
445532

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

448-
memset(disp_data->read_buf, 0, desc->pitch * desc->height * 4);
535+
K_SPINLOCK(&disp_data->lock) {
536+
memset(disp_data->read_buf, 0, desc->pitch * desc->height * 4);
449537

450-
err = sdl_display_read_bottom(desc->height, desc->width, x, y, disp_data->renderer,
451-
disp_data->read_buf, desc->pitch, disp_data->mutex,
452-
disp_data->texture, disp_data->read_texture);
538+
err = sdl_display_read_bottom(desc->height, desc->width, x, y, disp_data->renderer,
539+
disp_data->read_buf, desc->pitch, disp_data->mutex,
540+
disp_data->texture, disp_data->read_texture);
453541

454-
if (err) {
455-
return err;
456-
}
542+
if (err) {
543+
K_SPINLOCK_BREAK;
544+
}
457545

458-
if (disp_data->current_pixel_format == PIXEL_FORMAT_ARGB_8888) {
459-
sdl_display_read_argb8888(disp_data->read_buf, desc, buf);
460-
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_RGB_888) {
461-
sdl_display_read_rgb888(disp_data->read_buf, desc, buf);
462-
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_MONO10) {
463-
sdl_display_read_mono(disp_data->read_buf, desc, buf, true);
464-
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_MONO01) {
465-
sdl_display_read_mono(disp_data->read_buf, desc, buf, false);
466-
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_RGB_565) {
467-
sdl_display_read_rgb565(disp_data->read_buf, desc, buf);
468-
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_BGR_565) {
469-
sdl_display_read_bgr565(disp_data->read_buf, desc, buf);
470-
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_L_8) {
471-
sdl_display_read_l8(disp_data->read_buf, desc, buf);
546+
if (disp_data->current_pixel_format == PIXEL_FORMAT_ARGB_8888) {
547+
sdl_display_read_argb8888(disp_data->read_buf, desc, buf);
548+
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_RGB_888) {
549+
sdl_display_read_rgb888(disp_data->read_buf, desc, buf);
550+
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_MONO10) {
551+
sdl_display_read_mono(disp_data->read_buf, desc, buf, true);
552+
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_MONO01) {
553+
sdl_display_read_mono(disp_data->read_buf, desc, buf, false);
554+
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_RGB_565) {
555+
sdl_display_read_rgb565(disp_data->read_buf, desc, buf);
556+
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_BGR_565) {
557+
sdl_display_read_bgr565(disp_data->read_buf, desc, buf);
558+
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_L_8) {
559+
sdl_display_read_l8(disp_data->read_buf, desc, buf);
560+
}
472561
}
473-
474-
return 0;
562+
return err;
475563
}
476564

477565
static int sdl_display_clear(const struct device *dev)
@@ -509,34 +597,57 @@ static int sdl_display_clear(const struct device *dev)
509597
return -EINVAL;
510598
}
511599
LOG_DBG("size: %zu, bgcolor: %hhu", size, bgcolor);
512-
memset(disp_data->buf, bgcolor, size);
600+
601+
K_SPINLOCK(&disp_data->lock) {
602+
memset(disp_data->buf, bgcolor, size);
603+
}
513604

514605
return 0;
515606
}
516607

517608
static int sdl_display_blanking_off(const struct device *dev)
518609
{
519610
struct sdl_display_data *disp_data = dev->data;
611+
struct sdl_display_task task = {
612+
.op = SDL_BLANKING_OFF,
613+
};
520614

521615
LOG_DBG("Turning display blacking off");
522616

523-
disp_data->display_on = true;
617+
K_SPINLOCK(&disp_data->lock) {
618+
disp_data->display_on = true;
619+
}
524620

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

528628
return 0;
529629
}
530630

531631
static int sdl_display_blanking_on(const struct device *dev)
532632
{
533633
struct sdl_display_data *disp_data = dev->data;
634+
struct sdl_display_task task = {
635+
.op = SDL_BLANKING_ON,
636+
};
534637

535638
LOG_DBG("Turning display blanking on");
536639

537-
disp_data->display_on = false;
640+
K_SPINLOCK(&disp_data->lock) {
641+
disp_data->display_on = false;
642+
}
643+
644+
if (k_current_get() == &disp_data->sdl_thread) {
645+
exec_sdl_task(dev, &task);
646+
} else {
647+
k_msgq_put(disp_data->task_msgq, &task, K_FOREVER);
648+
k_sem_take(&disp_data->task_sem, K_FOREVER);
649+
}
538650

539-
sdl_display_blanking_on_bottom(disp_data->renderer);
540651
return 0;
541652
}
542653

@@ -609,9 +720,11 @@ static DEVICE_API(display, sdl_display_api) = {
609720
* DT_INST_PROP(n, width)]; \
610721
static uint8_t sdl_read_buf_##n[4 * DT_INST_PROP(n, height) \
611722
* DT_INST_PROP(n, width)]; \
723+
K_MSGQ_DEFINE(sdl_task_msgq_##n, sizeof(struct sdl_display_task), 1, 4); \
612724
static struct sdl_display_data sdl_data_##n = { \
613725
.buf = sdl_buf_##n, \
614726
.read_buf = sdl_read_buf_##n, \
727+
.task_msgq = &sdl_task_msgq_##n, \
615728
}; \
616729
\
617730
DEVICE_DT_INST_DEFINE(n, &sdl_display_init, NULL, \

0 commit comments

Comments
 (0)