问题 对于具有不同上下文的多个线程,OpenGL线程是否安全?


我知道在线程之间共享一个上下文是坏消息。我知道当主线程上的GL没有发生任何事情时,我可以在辅助线程上安全地创建和使用带有屏幕外帧缓冲的上下文。

我还没有找到一个明确的答案,我是否可以安全地在两个不同的线程上创建两个上下文(例如,绘制到屏幕的主线程,以及执行屏幕外绘制工作的辅助线程)并且拥有它们同时进行GL函数调用。

换句话说,只要上下文不同,两个线程可以“共享”C API,从而“共享”GPU吗?或者这本身就是不可分享的东西?或者这是特定于实现的?

在iOS上专门询问OpenGL ES,但它可能是一个普遍的GL问题。


5943
2017-10-14 20:27


起源

有关: 我应该在我的OpenGL ES游戏中使用多个线程吗? - bobobobo


答案:


是的,您需要为要使用OpenGL的每个线程使用一个上下文,也可以在上下文之间共享对象。这是要走的路 :)


9
2017-10-14 20:35



不太正确:每个线程不需要一个上下文,只要你不同时在多个线程中使用相同的上下文,例如通过锁定对上下文的所有访问,并且只要此锁定在需要一个锁定的系统上包含内存屏障(通常情况下锁定就是这种情况)。 - Mecki
@Mecki你能提供一个关于这个概念的参考吗?是使用gl上下文 任何 调用gl函数?例如,我可以创建一个新的Texture对象/调用 glTexImage2D 在gl上下文同时从另一个线程上的相同gl上下文中绘制? - bobobobo
@bobobobo是的,任何gl *函数调用都使用当前为线程设置的上下文;否则,必须为每个gl函数提供所需的上下文。在过去,OpenGL只支持每个进程一个上下文,因为上下文是特定于线程的,并且今天为一个线程隐式设置。不,你不能同时在两个线程上使用相同的上下文。上下文只能由一个线程随时使用。您只能切换上下文绑定的线程。 - Mecki
@bobobobo你可以将一个上下文绑定到线程A,在那里使用它,从线程A解除绑定,将它绑定到线程B然后在线程B上使用它;这是允许的。如果你将一个上下文绑定到多个线程,甚至同时使用多个线程的上下文,那么所有gl *函数调用的结果都是未定义的(它可能会起作用,它可能会引起奇怪的事情,它可能会崩溃,随你)。绑定和解除绑定是特定于操作系统的功能,它们不是OpenGL标准的一部分(不同的操作系统为此任务提供不同的功能)。 - Mecki
@bobobobo一些操作系统提供共享上下文。如果共享了contextA和contextB,则可以在threadB上使用contextA,在threadB上使用contextB,但上下文共享相同的资源池。因此,在contextA中创建的纹理可用,并且可以在contextB中使用,反之亦然。因此,当contextA正在绘制某些东西时,contextB可以加载一个新的纹理,然后contextA可以使用它。如果您想获得更详细的解释,或者您想获得示例代码,请提出自己的问题,毕竟这是Stackoverflow的用途。 - Mecki


选项1:如果不同时使用两个线程的上下文,则一个上下文就足够了。

选项2:如果需要同时使用多个线程的OpenGL,则需要多个上下文。然后,如果上下文分享他们的 Sharegroup,他们分享他们的OpenGL内容,如纹理。这样,您可以在后台线程上加载纹理或执行繁重的帧缓冲处理。

在这里看一下关于Sharegroups的最后一节: http://developer.apple.com/library/ios/#documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/WorkingwithOpenGLESContexts/WorkingwithOpenGLESContexts.html

选项3:GLKit提供了一些内置的后台处理,例如异步纹理加载 GLKTextureLoader小号 - textureWithContentsOfFile。我不知道所有选项,但它肯定简化了异步OpenGL的一些使用案例。


1
2018-05-20 23:20