Is it thread-safe to render inside event watcher?

Hello everyone!

I have read the github discussion about the main thread being blocked while moving or resizing the window on some platforms. If I understand correctly this will not be an issue in SDL3 if you use the main callbacks.

My question is about the proposed workaround when using the traditional approach where SDL_PollEvent is called manually (which is the only option in SDL2).

slouken wrote:
I’ve added a solution that dovetails nicely with the new main callbacks in SDL 3.0 and if you’re not using that you can set an event watcher to handle expose events and draw then.

There is also an example that uses this approach. It uses SDL_AddEventWatch to register a callback that ends up calling a bunch of render functions (including SDL_RenderPresent).

The wiki page for SDL_RenderPresent says:

“You may only call this function on the main thread.”

The wiki page for SDL_AddEventWatch says:

“WARNING: Be very careful of what you do in the event filter function, as it may run in a different thread!”

Am I missing something, is there perhaps an undocumented guarantee that the event watcher will always be invoked on the main thread when dealing with window events, or is this simply not thread-safe?

1 Like

That particular event will only happen on the main thread, so it’s safe to render in response to that event. Other events may happen on other threads, so it’s not safe in general to render from an event callback.

1 Like

Thank you for the clarification.

Is somewhere a list of events that can only happen in the main thread?

One reason why window rendering may be done in an event watcher is because the window is repainted as it stretches. One of the solutions is the SDL_WINDOWEVENT_RESIZED event watcher and rerendering of the window content from a callback (example). Even though this works properly, it is difficult to know whether it is completely safe.

It would be useful to have a table in the documentation describing which types of events may come from which threads, what is safe and what’s not.

2 Likes
Summary

yay I made an event filter and now I can paint my windows as it resizes on Windows!!! S2 S2

to be sure I’m on the main thread, I created a global variable called tid, then during startup I assign tid = SDL_GetThreadID(NULL), then in every single exposure event I filter I call SDL_assert(SDL_GetThreadID(NULL) == tid)

regarding getting the new size during exposure… yeah, my stuff is stretching because I don’t know the new size. I can catch resize events while the resize happens, so I see I have to work inside an event filter. I see two options:

  1. use atomics, such as C11+ _Atomic or SDL atomic API
  2. resize stuff as if in main thread, using SDL_assert() again to ensure this

now I wonder which one is more portable and robust… brb

edit: I decided to place this in my event filter:

case SDL_WINDOWEVENT_RESIZED: // Fall through.
case SDL_WINDOWEVENT_SIZE_CHANGED:
    if (SDL_GetThreadID(NULL) == tid)
    {
        resize(event);
        return 0;
    }
break;

I’ll keep it like this until problems arise hehe

edit: I’ve run into problems. returning zero inside event filter for resize events breaks SDL_RenderCopy and that is the intended consequence when returning zero. returning one makes it work, but the result is sluggish.