When I implemented parallel initialization and update of procedural objects in my OpenGL game, I had to create multiple OpenGL contexts with shared objects, and bind one per thread, so I could create/update the VBOs in parallel.
I got the idea of how to do that from this blog post, and made my first implementation like this (in C++, but this question is also relevant for C):
/* ... */
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
SDL_Window* window = SDL_CreateWindow("Title",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
Options::width, Options::height, video_flags);
// Create one SDL context per thread
std::vector<SDL_GLContext> threads_glcontexts(globalThreadPool.get_num_threads());
for(auto& t_ctx: threads_glcontexts) {
t_ctx = SDL_GL_CreateContext(window);
}
// Main thread context
SDL_GLContext main_glcontext = SDL_GL_CreateContext(window);
// Setup one context per thread
//
// This function only returns when all threads
// in the pool have executed the given function.
globalThreadPool.run_in_every_pool_thread([&](unsigned thread_idx) {
SDL_GL_MakeCurrent(window, threads_glcontexts[thread_idx]); // ← BROKEN CODE
});
/* ... */
This code worked wonderfully for various months while developing it under Linux, until I ported the game to Windows. Then things went wrong: on Intel and AMD GPUs, is always crashed at startup. On Nvidia, it worked most of the times, but run it a few times and it also crashed on the same place: the first OpenGL call issued by one of the pool threads, which was glGenBuffers().
Eventually we found that wglGetCurrentContext() returned 0 on the offending thread, what lead us to discover that SDL_GL_MakeCurrent() failed for some threads with errors like:
- wglMakeCurrent(): The handle is invalid
- wglMakeCurrent(): The requested transformation operation is not supported
The question: how to properly setup multiple OpenGL contexts with shared objects on different threads with SDL2?