当我在我的 OpenGL 游戏中实现程序对象的并行初始化和更新时,我必须使用共享对象创建多个 OpenGL 上下文,并为每个线程绑定(bind)一个,这样我就可以并行创建/更新 VBO。
我从 this blog post 得到了如何做到这一点的想法,并像这样进行了我的第一个实现(在 C++ 中,但这个问题也与 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
});
/* ... */
这段代码在 Linux 下开发时运行了好几个月,直到我将游戏移植到 Windows。然后事情就出了问题:在 Intel 和 AMD GPU 上,总是在启动时崩溃。在 Nvidia 上,它大部分时间都可以工作,但运行了几次,它也在同一个地方崩溃:由其中一个池线程发出的第一个 OpenGL 调用,即 glGenBuffers()
。 .最终我们发现
wglGetCurrentContext()
返回 0
在有问题的线程上,是什么导致我们发现 SDL_GL_MakeCurrent()
某些线程失败,错误如下:问题:如何使用 SDL2 在不同线程上使用共享对象正确设置多个 OpenGL 上下文?
最佳答案
我不知道我们找到的解决方案是否适用于 SDL 支持的每个平台,但它至少适用于 Windows 和 Linux/X11。
问题是 SDL_GL_MakeCurrent()
一般不是线程安全的(它在 Linux/X11 上似乎是线程安全的,但这是偶然的,因为 SDL 是一个多平台库(问题确实是 wglMakeCurrent()
,而不是 SDL,因为旧代码也有效在葡萄酒下))。
所以我们只需要使用互斥锁来保护调用。在我们的 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.
std::mutex mtx;
globalThreadPool.run_in_every_pool_thread([&](unsigned thread_idx) {
std::lock_guard<std::mutex> lock(mtx); // ← ↓ WORKINING CODE
SDL_GL_MakeCurrent(window, threads_glcontexts[thread_idx]);
});
/* ... */
关于c++ - 如何使用 SDL2 为每个线程设置一个共享的 OpenGL 上下文?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64484835/