SDL examples: all SDL operations in one thread

Fix video in SDL examples by invoking rendering in the same thread
(pw_loop) that created the window, renderer and texture.

At least on some systems, no video is shown without this patch. In
those error cases, SDL_RenderPresent triggers an SDL error "The
specified window has not been made current". That, in turn, has to do
with how SDL uses the current thread for determing the current window.
In general, the page linked to below states that the SDL API is not
designed to be used from multiple threads.

Reference: https://wiki.libsdl.org/CategoryRender
This commit is contained in:
David Svensson Fors 2018-01-12 13:40:01 +01:00 committed by Wim Taymans
parent 865f671195
commit 0b523e4334
3 changed files with 55 additions and 16 deletions

View file

@ -441,9 +441,10 @@ static int impl_port_use_buffers(struct spa_node *node, enum spa_direction direc
return 0; return 0;
} }
static int impl_node_process_input(struct spa_node *node) static int do_render(struct spa_loop *loop, bool async, uint32_t seq,
const void *_data, size_t size, void *user_data)
{ {
struct data *d = SPA_CONTAINER_OF(node, struct data, impl_node); struct data *d = user_data;
struct spa_buffer *buf; struct spa_buffer *buf;
uint8_t *map; uint8_t *map;
void *sdata, *ddata; void *sdata, *ddata;
@ -452,10 +453,10 @@ static int impl_node_process_input(struct spa_node *node)
uint8_t *src, *dst; uint8_t *src, *dst;
if (d->io->status != SPA_STATUS_HAVE_BUFFER) if (d->io->status != SPA_STATUS_HAVE_BUFFER)
goto done; return 0;
if (d->io->buffer_id > d->n_buffers) if (d->io->buffer_id > d->n_buffers)
goto done; return 0;
buf = d->buffers[d->io->buffer_id]; buf = d->buffers[d->io->buffer_id];
@ -493,7 +494,18 @@ static int impl_node_process_input(struct spa_node *node)
if (map) if (map)
munmap(map, buf->datas[0].maxsize + buf->datas[0].mapoffset); munmap(map, buf->datas[0].maxsize + buf->datas[0].mapoffset);
done: return 0;
}
static int impl_node_process_input(struct spa_node *node)
{
struct data *d = SPA_CONTAINER_OF(node, struct data, impl_node);
int res;
if ((res = pw_loop_invoke(pw_main_loop_get_loop(d->loop), do_render,
SPA_ID_INVALID, NULL, 0, true, d)) < 0)
return res;
handle_events(d); handle_events(d);
return d->io->status = SPA_STATUS_NEED_BUFFER; return d->io->status = SPA_STATUS_NEED_BUFFER;

View file

@ -390,9 +390,10 @@ static int impl_port_use_buffers(struct spa_node *node, enum spa_direction direc
return 0; return 0;
} }
static int impl_node_process_input(struct spa_node *node) static int do_render(struct spa_loop *loop, bool async, uint32_t seq,
const void *_data, size_t size, void *user_data)
{ {
struct data *d = SPA_CONTAINER_OF(node, struct data, impl_node); struct data *d = user_data;
struct spa_buffer *buf; struct spa_buffer *buf;
uint8_t *map; uint8_t *map;
void *sdata, *ddata; void *sdata, *ddata;
@ -436,6 +437,18 @@ static int impl_node_process_input(struct spa_node *node)
if (map) if (map)
munmap(map, buf->datas[0].maxsize + buf->datas[0].mapoffset); munmap(map, buf->datas[0].maxsize + buf->datas[0].mapoffset);
return 0;
}
static int impl_node_process_input(struct spa_node *node)
{
struct data *d = SPA_CONTAINER_OF(node, struct data, impl_node);
int res;
if ((res = pw_loop_invoke(pw_main_loop_get_loop(d->loop), do_render,
SPA_ID_INVALID, NULL, 0, true, d)) < 0)
return res;
handle_events(d); handle_events(d);
d->io->status = SPA_STATUS_NEED_BUFFER; d->io->status = SPA_STATUS_NEED_BUFFER;

View file

@ -96,20 +96,18 @@ static void handle_events(struct data *data)
} }
} }
static void static int
on_stream_new_buffer(void *_data, uint32_t id) do_render(struct spa_loop *loop, bool async, uint32_t seq,
const void *_data, size_t size, void *user_data)
{ {
struct data *data = _data; struct data *data = user_data;
struct pw_stream *stream = data->stream; struct spa_buffer *buf = ((struct spa_buffer **) _data)[0];
struct spa_buffer *buf;
uint8_t *map; uint8_t *map;
void *sdata, *ddata; void *sdata, *ddata;
int sstride, dstride, ostride; int sstride, dstride, ostride;
int i; int i;
uint8_t *src, *dst; uint8_t *src, *dst;
buf = pw_stream_peek_buffer(stream, id);
if (buf->datas[0].type == data->type.data.MemFd || if (buf->datas[0].type == data->type.data.MemFd ||
buf->datas[0].type == data->type.data.DmaBuf) { buf->datas[0].type == data->type.data.DmaBuf) {
map = mmap(NULL, buf->datas[0].maxsize + buf->datas[0].mapoffset, PROT_READ, map = mmap(NULL, buf->datas[0].maxsize + buf->datas[0].mapoffset, PROT_READ,
@ -119,11 +117,11 @@ on_stream_new_buffer(void *_data, uint32_t id)
map = NULL; map = NULL;
sdata = buf->datas[0].data; sdata = buf->datas[0].data;
} else } else
return; return -EINVAL;
if (SDL_LockTexture(data->texture, NULL, &ddata, &dstride) < 0) { if (SDL_LockTexture(data->texture, NULL, &ddata, &dstride) < 0) {
fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError()); fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError());
return; return -EIO;
} }
sstride = buf->datas[0].chunk->stride; sstride = buf->datas[0].chunk->stride;
ostride = SPA_MIN(sstride, dstride); ostride = SPA_MIN(sstride, dstride);
@ -144,6 +142,22 @@ on_stream_new_buffer(void *_data, uint32_t id)
if (map) if (map)
munmap(map, buf->datas[0].maxsize + buf->datas[0].mapoffset); munmap(map, buf->datas[0].maxsize + buf->datas[0].mapoffset);
return 0;
}
static void
on_stream_new_buffer(void *_data, uint32_t id)
{
struct data *data = _data;
struct pw_stream *stream = data->stream;
struct spa_buffer *buf;
buf = pw_stream_peek_buffer(stream, id);
pw_loop_invoke(pw_main_loop_get_loop(data->loop), do_render,
SPA_ID_INVALID, &buf, sizeof(struct spa_buffer *),
true, data);
pw_stream_recycle_buffer(stream, id); pw_stream_recycle_buffer(stream, id);
handle_events(data); handle_events(data);