SDL icon indicating copy to clipboard operation
SDL copied to clipboard

EGL error when using render thread on Wayland

Open slembcke opened this issue 1 year ago • 4 comments

I have a threaded GL setup where I create a pair of shared GL contexts on my main thread. Then I start a render thread and bind the second context there. When I do so (on Fedora 39 / Wayland) I consistently get an EGL error:

Failed to bind OpenGL context: Unable to make EGL context current (call to eglMakeCurrent failed, reporting an error of EGL_BAD_ACCESS)

It works fine if I disable the render thread. It also works fine with SDL_VIDEODRIVER=X11. If I move the creation of the second context to the render thread it fails with the same error. (IIRC this is a no-no on other platforms too) I might be able to help look into this deeper, but it's been a while since I've touched EGL, and I've never worked with Wayland directly.

Here's a minimal replication of the error:

#include <assert.h>
#include <SDL.h>

SDL_Window* WINDOW;

static int render_thread(void* user_data){
  SDL_GLContext* gl_context = user_data;
  int err = SDL_GL_MakeCurrent(WINDOW, gl_context);

  if(err != 0) SDL_Log(SDL_GetError());
  return 0;
}

int main(void){
  int err = SDL_Init(SDL_INIT_VIDEO);
  assert(err == 0);
  
  SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);

  WINDOW = SDL_CreateWindow("What's in a name", 0, 0, 800, 600, SDL_WINDOW_OPENGL);
  assert(WINDOW);
  
  // GL context for the render thread
  SDL_GLContext* gl_context = SDL_GL_CreateContext(WINDOW);
  // GL context for the main thread to sync to
  SDL_GLContext* sync_context = SDL_GL_CreateContext(WINDOW);
  assert(gl_context && sync_context);
  
  SDL_CreateThread(render_thread, "render_thread", gl_context);
  return 0;
}

Compile with: cc `sdl2-config --cflags --libs` test.c or whatnot.

slembcke avatar Feb 15 '24 20:02 slembcke

The eglMakeCurrent docs page says this:

If context is current to some other thread, or if either draw or read are bound to contexts in another thread, an EGL_BAD_ACCESS error is generated.

If binding context would exceed the number of current contexts of that client API type supported by the implementation, an EGL_BAD_ACCESS error is generated.

So probably one of those two things is happening?

slime73 avatar Feb 15 '24 20:02 slime73

I did try explicitly unbinding the first context from the main thread, and that didn't work. (Unsurprising since creating the second context should unbind it)

On a whim, I just tried unbinding both contexts from the main thread. Then the render thread is able to bind it's context and render a single frame before the main thread tries to sync without a GL context bound and crashes. If I wait and bind the second context on the main thread later it still gets that EGL_BAD_ACCESS crash though. So it seems whichever thread binds last gets stuck.

Are there any other examples of games using shared contexts that do work?

slembcke avatar Feb 15 '24 23:02 slembcke

Looking more closely at that first case and eglMakeCurrent's parameters and SDL's use of them, I don't think SDL's current API allows having two OpenGL/EGL contexts active in different threads at the same time if they reference the same window.

SDL only exposes a context parameter for its MakeCurrent API, so the backends that use EGL have to pass the surface of the window associated with that context to every eglMakeCurrent call. Doing so with two contexts associated with the same window in different threads would hit this case:

if either draw or read [surface parameters] are bound to contexts in another thread, an EGL_BAD_ACCESS error is generated.

This doesn't really help solve your issue but I'm curious what sort of things you're using two contexts at once for - when I looked into it a long time ago, I got the impression the overall idea wasn't great because it could slow down calls in both contexts due to drivers sometimes needing internal mutex locks (not to mention any possible driver bugs).

slime73 avatar Feb 16 '24 00:02 slime73

In my case I'm really just using it for synchronization. The main thread gets a render queue object, waits for it's fence and fills it up with commands and data. Meanwhile the render thread is submitting GL calls for the previous frame's queue and then a fence for the main thread to wait for so it knows when it's ready. Flip the queues and continue endlessly. Basic double buffering. I've written several renderers in the past 10 years that do that. Works great. I've also read that shared context have some additional cost. It's not bad enough I've ever noticed it when not actively measuring it anyway. It's certainly not worse than the boost you get from decoupling rendering. (shrug)

I've sort of been ignoring this bug for a couple years now assuming that there was just something that wasn't implemented for Wayland yet. The GL3 renderer was kind of just a fallback for the Vulkan renderer so I didn't really invest a lot of thought. SDL on Haiku OS has a mildly similar issue where it can't even create a shared context, and my workaround was to just disable threading. I was surprised to see it fixed the GL on Wayland issue and figured it's probably time to help get it fixed.

slembcke avatar Feb 16 '24 05:02 slembcke

I am running into the same issue on Linux Fedora 40 using the "wayland" video driver, even without a render thread

esohns avatar May 25 '24 12:05 esohns

Doing SDL_GL_MakeCurrent(WINDOW, NULL); before SDL_CreateThread makes the error go away. I'm not sure you can create 2 gl contexts for the same window.

madebr avatar May 25 '24 14:05 madebr

To note, this example flat-out segfaults on XWayland for me (Fedora 40/GNOME/Nvidia 550).

Kontrabant avatar May 25 '24 16:05 Kontrabant

I am running into the same issue on Linux Fedora 40 using the "wayland" video driver, even without a render thread

Doing SDL_GL_MakeCurrent(WINDOW, NULL); before SDL_CreateThread makes the error go away. I'm not sure you can create 2 gl contexts for the same window.

This hint resolved my issues. Run SDL_GL_MakeCurrent(WINDOW, NULL); in the main thread before issuing draws in other threads.

esohns avatar May 26 '24 00:05 esohns