20

剧透:我相当有信心答案是NO,但这只是在经过一天非常沮丧的调试之后。现在我想知道是否确实如此(如果是这样,我可能怎么知道),或者我是否只是在做完全错误的事情。

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

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

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

但是我在让 VAO 为我工作时遇到了严重的问题。就像我处理所有加载一样,我会将网格从文件加载到后台线程的内存中,然后生成所有关联的 OpenGL 对象。毫无疑问,当我第一次尝试glDrawElements()使用 VAO 调用时,应用程序崩溃并显示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);
}

当上述在后台线程上执行时,与主上下文EAGLContext相同的有效shareGroup,主上下文将有4个VBO,但没有VAO。如果我在主线程上使用主上下文执行它,它将有 4 个 VBO 和 VAO。EAGLContext这使我得出结论,在处理 VAO 时,s 的对象共享性质存在一些奇怪的例外。如果情况确实如此,我真的希望 Apple 文档在某处注意到这一点。不得不手动发现这样的小花絮非常不方便。是这样吗,还是我错过了什么?

4

1 回答 1

21

据此 OpenGL-ES 明确禁止共享 VAO 对象:

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

解决:不。OpenGL ES 工作组进行了一次投票,并同意与 OpenGL 的兼容性和易于实现比在 OpenGL ES 中创建第一个非共享命名对象更重要。

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

于 2011-08-19T17:40:49.010 回答