我是不是允许在 OpenGL 2.1 的多个共享上下文中同时从同一个缓冲区对象进行渲染?

Posted

技术标签:

【中文标题】我是不是允许在 OpenGL 2.1 的多个共享上下文中同时从同一个缓冲区对象进行渲染?【英文标题】:Am I allowed to simultaneously render from the same buffer object on multiple shared contexts in OpenGL 2.1?我是否允许在 OpenGL 2.1 的多个共享上下文中同时从同一个缓冲区对象进行渲染? 【发布时间】:2016-01-07 18:17:31 【问题描述】:

在 Apple 的文档中,我读到:

1 — “共享上下文共享所有纹理对象、显示列表、顶点程序、片段程序和在共享开始之前和之后创建的缓冲区对象。” 2 — “不同线程上的上下文可以共享对象资源。例如,一个线程中的一个上下文可以修改纹理,而第二个线程中的第二个上下文可以修改同一个纹理。共享对象Apple API 提供的处理自动防止线程错误。”

所以我希望能够创建我的缓冲区对象一次,然后使用它们在多个上下文中同时呈现。但是,如果我这样做,我的 NVIDIA GeForce GT 650M 就会崩溃,回溯如下:

Crashed Thread:        10  Dispatch queue: com.apple.root.default-qos
Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       EXC_I386_GPFLT
…
Thread 10 Crashed:: Dispatch queue: com.apple.root.default-qos
0  GLEngine  0x00007fff924111d7 gleLookupHashObject + 51
1  GLEngine  0x00007fff925019a9 gleBindBufferObject + 52
2  GLEngine  0x00007fff9243c035 glBindBuffer_Exec + 127

我已在https://gist.github.com/jlstrecker/9df10ef177c2a49bae3e 上发布了我的完整代码。在顶部,有 #define SHARE_BUFFERS — 注释掉它可以正常工作,但取消注释它会崩溃。

我不想争论我是否应该使用 OpenGL 2.1 — 这是我正在与之交互的其他软件的要求。我也不想争论我是否应该使用 GLUT——我的示例代码只是使用它,因为它包含在 Mac 上并且没有任何外部依赖项。我也不是在寻找有关性能/优化的反馈。

我只是想知道我是否可以期望能够在多个上下文中同时从单个共享缓冲区对象进行渲染——如果可以,为什么我的代码会崩溃。

【问题讨论】:

你要渲染什么?你渲染到同一个目标吗? @NicolBolas:您可以在源代码中看到每个线程创建自己的带有纹理颜色附件的帧缓冲区。 不幸的是,我并不完全惊讶于从多个线程访问 OpenGL 的代码会暴露出一些错误,即使它应该可以工作。我看不出代码有什么问题,Apple 的文档似乎支持您的使用。 据我所知,通过查看链接代码,您正在同一上下文中进行所有 OpenGL 调用。当您为每个线程创建额外的上下文时,您实际上从未将它们设为当前,因此 GLUT 创建的默认上下文用于所有内容。 另外,可能与问题无关:您没有使用 OpenGL 2.1。链接代码中使用了大量 3.x 功能,例如 FBO 和 VAO。 【参考方案1】:

我们还遇到了“gleLookupHashObject”崩溃并制作了一个小型重现案例(与您的非常相似),该案例发布在 Apple 支持的“事件”中。经过调查,一位 Apple DTS 工程师返回了以下信息,并引用:

“我注意到 glFlush() 在主线程和绑定位置数据的辅助线程上都被调用。这确实会引入问题,虽然很微妙,但确实表明我们施加的约束线程和 GL 上下文没有得到充分尊重。 此时,您应该进一步调查您的实现以确保避免此类情况,或者更好的是,使用显式同步机制(例如我们提供的 GCD)扩展您的实现。 "

因此,如果您遇到此崩溃,您将需要在应用程序端进行显式同步(等待驱动程序端的修复)。

Apple 官方文档中与“OpenGL, Contexts and Threading”相关的相关sn-ps总结:

[0] Section: "Use Multiple OpenGL Contexts"
If your application has multiple scenes that can be rendered in parallel, you can use a context for each scene you need to render. Create one context for each scene and assign each context to an operation or task. Because each task has its own context, all can submit rendering commands in parallel.
https://developer.apple.com/library/mac/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_threading/opengl_threading.html#//apple_ref/doc/uid/TP40001987-CH409-SW6

[1] Section: Guidelines for Threading OpenGL Applications
(a) Use only one thread per context. OpenGL commands for a specific context are not thread safe. You should never have more than one thread accessing a single context simultaneously.
(b) Contexts that are on different threads can share object resources. For example, it is acceptable for one context in one thread to modify a texture, and a second context in a second thread to modify the same texture. The shared object handling provided by the Apple APIs automatically protects against thread errors. And, your application is following the "one thread per context" guideline.
https://developer.apple.com/library/mac/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_threading/opengl_threading.html

[2] OpenGL Restricts Each Context to a Single Thread
Each thread in an OS X process has a single current OpenGL rendering context. Every time your application calls an OpenGL function, OpenGL implicitly looks up the context associated with the current thread and modifies the state or objects associated with that context.
OpenGL is not reentrant. If you modify the same context from multiple threads simultaneously, the results are unpredictable. Your application might crash or it might render improperly. If for some reason you decide to set more than one thread to target the same context, then you must synchronize threads by placing a mutex around all OpenGL calls to the context, such as gl* and CGL*. OpenGL commands that blockâsuch as fence commandsâdo not synchronize threads.
https://developer.apple.com/library/mac/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_threading/opengl_threading.html

【讨论】:

等等,Apple DTS 是否只是说您不能同时在 2 个线程上的同一 OpenGL 上下文中调用 glFlush()?还是说glFlush()在整个过程中只能在一个线程上同时调用,即使每个线程都有自己的OpenGL上下文? 我们的示例有 2 个线程,每个线程都有自己的上下文......据我所知,他们说的是后者,即“glFlush() 只能在整个线程中同时调用一个线程进程,即使每个线程都有自己的 OpenGL 上下文”。因此,他们建议(解决方法)使用“显式同步”。

以上是关于我是不是允许在 OpenGL 2.1 的多个共享上下文中同时从同一个缓冲区对象进行渲染?的主要内容,如果未能解决你的问题,请参考以下文章

在 OS X 上的 OpenGL 上下文之间共享数据(不同的版本/配置文件)

OpenGL着色器 - 重叠多个纹理

如何在 Visual Studio 2017 的单个表单上打开多个 OpenGL 窗口?

bitnami wordpress 堆栈是不是允许多个 wordpress 安装

Qt & OpenGL:如何强制使用 OpenGL 2.1?

OpenGL ES 可不可以实现多线程共享 纹理