在OpenGL ES中,顶点数组对象(VAOs)可以在EAGLContext之间共享吗?

21

提示:经过一天的沉重调试,我相当有把握地回答“不行”。现在我想知道是否确实如此(如果是,我应该如何知道),或者我只是做错了什么。

这是情况。我正在使用OpenGL ES 2.0渲染从各种文件(.obj,.md2等)加载的一些网格。为了提高性能和用户体验,我将加载这些网格及其相关纹理的实际操作委托给使用GCD的后台线程。

根据Apple说明,在每个后台线程上,我创建并设置了一个具有与主渲染上下文相同的shareGroup的新EAGLContext。这允许在后台线程上创建的OpenGL对象(如纹理和缓冲区对象)立即被主线程上的上下文使用。

这一直很出色。现在,我最近学到了顶点数组对象,作为缓存与渲染某些缓冲区内容相关联的OpenGL状态的一种方式。看起来不错,并减少了渲染每个网格所需的样板状态检查和设置代码。最重要的是,Apple在其处理顶点数据的最佳实践指南中也推荐使用它们。

但是我在使用VAO方面遇到了严重的问题。像我对所有加载的内容一样,我会在后台线程将网格从文件加载到内存中,然后生成所有关联的OpenGL对象。但第一次尝试使用VAO调用glDrawElements()时,应用程序总是崩溃并出现EXC_BAD_ACCESS。没有VAO时,它可以正常渲染。

调试EXC_BAD_ACCESS非常麻烦,特别是当NSZombies无法帮助时(它们显然不会),但在分析捕获的OpenGL帧一段时间后,我意识到,虽然在后台线程上创建VAO顺利进行(没有GL_ERROR,且id非零),但当主线程绑定VAO时,会出现GL_INVALID_OPERATION,这在文档中说明当试图绑定不存在的VAO时会发生。果然,在渲染时查看当前上下文中的所有对象,没有一个VAO可以看到,但与VAO同时生成的所有VBO都存在。如果我在主线程上加载VAO,则可以正常工作。非常令人沮丧。

我将加载代码简化为更原子的形式:

- (void)generate {

    glGenVertexArraysOES(1, &_vao);
    glBindVertexArrayOES(_vao);

    _vbos = malloc(sizeof(GLuint) * 4);
    glGenBuffers(4, vbos);
}

当上述代码在另一个线程上执行,并使用与主线程相同的shareGroup参数的有效EAGLContext时,主线程将具有4个VBO但没有VAO。如果我在主线程上执行它并使用主上下文,那么它将有4个VBO和VAO。这让我得出结论,在处理VAO时,EAGLContext对象共享特性存在某种奇怪的例外情况。如果确实是这样,我真的希望苹果文档中能够有相关说明。手动发现这些小细节非常不方便。这是否属实呢,或者我遗漏了什么?


我刚刚通过艰难的方式发现了答案;-) - hanno
1个回答

22

根据这里的内容,OpenGL-ES明确禁止共享VAO对象:

在多个OpenGL ES上下文之间是否应该共享顶点数组对象?

决定:不允许。OpenGL ES工作组进行了一次投票,他们认为与OpenGL的兼容性和易于实现比创建OpenGL ES中第一个非共享命名对象更重要。

正如您所指出的,VBO仍然可以共享,因此您只需为绑定共享VBO的每个上下文创建一个VAO。


啊,太好了。这正是我在寻找的晦涩文档。很高兴知道这是预期行为。谢谢。 - Matt Wilding
太好了。我正在后台加载资源,但所有的几何体都是基于VAO的,所以我决定只在后台加载纹理,并在主线程上生成几何体。 - Nicolas Miari
一定要喜欢那些含糊其辞的话语... “我们会永久性地破坏后台加载(几何可能非常巨大),这样我们就不必在驱动程序中实现新的/更好的代码” ;). - Adam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接