在GLFW FAQ的第 2.9 项中指出:
[...]强烈建议所有 OpenGL 和 GLFW 调用 (线程管理和同步调用除外)都从主线程进行,这应该不是什么大问题,因为只支持单个窗口。这种方法也与 GLFW 的未来方向兼容。
重点是我的。
那么,主线程和其他线程有什么区别呢?
在GLFW FAQ的第 2.9 项中指出:
[...]强烈建议所有 OpenGL 和 GLFW 调用 (线程管理和同步调用除外)都从主线程进行,这应该不是什么大问题,因为只支持单个窗口。这种方法也与 GLFW 的未来方向兼容。
重点是我的。
那么,主线程和其他线程有什么区别呢?
该问题涉及旧的 GLFW API 和常见问题解答,请参阅更新的 GLFW 常见问题解答和GLFW 线程安全文档。
一些限制仍然存在,许多 GLFW 调用必须从主线程进行。主线程和其他线程之间的区别取决于平台特定的窗口创建行为、GLFW 处理的事件等。有关详细信息,请参阅官方 GLFW 论坛上的此帖子。
一旦创建了 OpenGL 窗口,就可以使上下文在另一个线程上处于当前状态,并且可以从该线程进行 OpenGL 调用。
The statement
"Is … thread safe? No. However, neither is OpenGL."
is wrong. OpenGL is of course thread safe.
Here's the deal: For each thread either one or no OpenGL context can be bound to a drawable (made current). OpenGL calls operate on the context that is active in the thread the calls are made from. It is perfectly possible to transfer a OpenGL context between threads. For this the context to be transfered first must be unbound, then it can be rebound in another thread.
Each OpenGL context manages its own set of state variable and objects (textures, buffers). However context can be "entangled", i.e. share their object space. State is still individual though.
A single drawable (window, PBuffer) can have multiple contexts from different threads being bound to. If contexts from different threads draw to the same drawable a race condition occours and the results are undefined. However in the case of depth tested drawing the outcome should be reasonable. However simultanous drawing to a single drawable will strongly impair performance, so it better is avoided.
The main use for multiple OpenGL contexts in multiple threads is to share their objects so that one thread can load and update data for the other context. It makes sense to bind the helper contexts to off-screen or hidden drawables to prevent race conditions to happen.
There's no technical difference between the threads. From a programming point of view each thread will have a slightly different semantic, which is imposed by the programm running, not by the system architecture. In the case of most OpenGL applications the conventional semantics are, that the main thread will create the window, draw all elements visible to the user (including OpenGL operations) and collect user input. The threads launched from the main thread are worker threads without direct user interaction. However this task distribution is purely by choice and because it turned out to work well. But it's perfectly possible, and sometimes advisable, to use a different scheme. And like already said, there is no technical difference about the threads within a program. All threads are equal rights citizens within a process.
该文档的措辞可能有点误导。更好的措辞是:
强烈建议所有 OpenGL 和 GLFW 调用(线程管理和同步调用除外)都从单个线程进行,最好是调用
glfwInit
andglfwOpenWindow
的同一个线程,这应该不是大问题,因为只支持单个窗口。这种方法也与 GLFW 的未来方向兼容。
这样做的原因是 OpenGL 对其上下文具有“当前线程”的概念,这是一个可以在给定时间合法修改或使用该上下文的线程。上下文最初属于创建它的线程。wglMakeCurrent
您可以通过调用or使其在其他线程中成为“当前” glxMakeCurrent
,这与 GLFW 不同的是不可移植(但 GLFW 可能有一个包装器,我不确定)。
当然,很可能有几个独立的上下文,并且可以通过在每个线程中使用相同的上下文在使用它之前从多个线程访问相同的上下文。最后,可以在共享状态的多个线程中拥有多个上下文。
但是,这些选项都不是常规情况,因为它要么涉及不可忽略的同步开销,要么不适合 OpenGL 的常见用法。通常,除了“一个线程,一个上下文”之外的任何其他事情,除了极少数例外,都不会提供任何优势,但会带来不必要的复杂性。
因此,常规情况是只有一个上下文由一个线程使用,并且可以选择一些有助于将数据混洗到映射缓冲区的工作线程。
至于“主线程”与“任何线程”,没有区别。大多数时候,主线程只是偶然地初始化 GLFW(以及因此 OpenGL)的线程。