【问题标题】:glGenVertexArraysOES returns a zero VAO on iOS, sometimesglGenVertexArraysOES 在 iOS 上有时会返回零 VAO
【发布时间】:2012-12-06 21:15:58
【问题描述】:

我在 iOS 上创建 VAO 时遇到问题。有时它工作得很好,glGenVertexArraysOES 通过第二个参数返回一个非零 VAO,但其他时候,它通过 glGetError() 简单地返回零并且没有错误

我有两个案例。一个有效,另一个无效。它们都在初始化代码中,它们或多或少是相同的代码:

工作:

glGenBuffers(1, &m_vertexBufferObject);
errorCheck();

GLuint vao = 0;
glGenVertexArraysOES(1, &vao);
errorCheck();
glBindVertexArrayOES(vao);
errorCheck();

(vao set up goes here)

(vao != 0)

不工作:

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArrayOES(0);

errorCheck();
GLuint vao = 0;
glGenVertexArraysOES(1, &vao);
errorCheck();
glBindVertexArrayOES(vao);
errorCheck();

(vao == 0)

非工作块中的 glBind* 函数在很大程度上只是通过减轻任何先前绑定的状态来解决问题的尝试。它没有帮助。

代码是多线程的。我有一个上下文,并且一次只允许一个线程通过互斥锁使用它。当线程获取上下文时,我锁定互斥体并调用 setCurrentContext。之后我将当前上下文恢复为零。我相信这应该是我在别处读到的可接受的多线程设置。无论如何,禁用线程并在同一线程上运行所有内容都没有区别!

成功的案例发生在开始的时候,也就是初始化的时候。这很好......另一种情况发生在加载期间,同时渲染循环正在进行(但仍被所述关键部分和上下文分配编组),这就是失败的情况。

我基本上假设 glGenVertexArrayOES 的执行必须存在某种未满足的先决条件。我不认为这真的是在后一种情况下设置的 VAO 的主体,我认为这是在成功的初始 VAO 设置和后来的尝试设置之间发生的事情。

它在 sim 卡和手机上都失败了,所以显然发生了一些事情......然而,这是一个无声的错误,所以它让我没有调查的角度。它在 OS X 的 OpenGL 上运行良好。此外,尝试复制错误或类似情况(例如,各种示例代码中的线程都失败了。

有什么想法吗?

谢谢。

【问题讨论】:

  • 我应该补充一点,相同的代码可以在 OS X 上运行(尽管去掉了 OES 后缀)
  • 失败的 glGentVertexArraysOES 之前的代码是否完全创建和初始化 VAO,然后将缓冲区和 VAO 设置为 0?如果是这样,您想注释掉 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) 行,也许通过取消绑定它会弄乱 GL 中的 VAO 流。我发现如果在取消绑定 VAO 之前取消绑定 ELEMENT_ARRAY_BUFFER,那么 VAO 和我的任何场景都将无法使用。它是一种预感,而不是答案,因此是评论(松散相关的链接:stackoverflow.com/questions/10545479/…
  • 你好,工作情况发生在启动时,然后我们进入一个循环进行渲染(我怀疑这会污染 GenVertexArray 的任何先决条件),然后是另一个一个失败。所以是的,VAO 确实被创建了,我最后绑定了一个 0 VAO.. 但我没有解除绑定任何缓冲区之前我解除绑定 VAO(就像在那个链接中一样),我相信它是在这种情况下很重要。 VAO 创建与渲染在不同的线程上,但单线程代码没有区别。另外,我试图故意破坏示例代码,但这并没有说明问题。 :-(

标签: iphone ios6 ios-simulator opengl-es-2.0


【解决方案1】:

这是从 GLKViewController 派生的视图类。

@interface IncubeViewController : GLKViewController {
      ...
}

这是我加载 vao 的方式:

- (void) loadGeometry
{
        /* Pieces */
        for (int i = ptFirst; i < ptLast; i++) {
                glGenVertexArraysOES(1, &pieceObject[i].array);
                glBindVertexArrayOES(pieceObject[i].array);

                glGenBuffers(1, &pieceObject[i].buffer);
                glBindBuffer(GL_ARRAY_BUFFER, pieceObject[i].buffer);

                glBufferData(GL_ARRAY_BUFFER, vertextData[i].vertNumber * sizeof(Vertex),
                             vertextData[i].vertArray, GL_STATIC_DRAW);

                glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_TRUE,
                                      sizeof(Vertex), (void *)offsetof(Vertex, position));
                glEnableVertexAttribArray(GLKVertexAttribPosition);
                glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_TRUE,
                                      sizeof(Vertex), (void *)offsetof(Vertex, normal));
                glEnableVertexAttribArray(GLKVertexAttribNormal);
        }

        /* Cube */
        glGenVertexArraysOES(1, &cubeObject.array);
        glBindVertexArrayOES(cubeObject.array);

        glGenBuffers(1, &cubeObject.buffer);
        glBindBuffer(GL_ARRAY_BUFFER, cubeObject.buffer);

        glBufferData(GL_ARRAY_BUFFER, CubeDataNumberOfVertices * sizeof(Vector3),
                     CubeData, GL_STATIC_DRAW);

        glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE,
                              0, (void *)0);
        glEnableVertexAttribArray(GLKVertexAttribPosition);

        /* Sphere */
        glGenVertexArraysOES(1, &sphereObject.array);
        glBindVertexArrayOES(sphereObject.array);

        glGenBuffers(1, &sphereObject.buffer);
        glBindBuffer(GL_ARRAY_BUFFER, sphereObject.buffer);

        glBufferData(GL_ARRAY_BUFFER, SphereDataNumberOfVertices * sizeof(Vertex),
                     SphereData, GL_STATIC_DRAW);

        glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE,
                              sizeof(Vertex), (void *)offsetof(Vertex, position));
        glEnableVertexAttribArray(GLKVertexAttribPosition);
        glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE,
                              sizeof(Vertex), (void *)offsetof(Vertex, normal));
        glEnableVertexAttribArray(GLKVertexAttribNormal);

        /* Diagonal grid */
        glGenVertexArraysOES(1, &diagonalGridObject.array);
        glBindVertexArrayOES(diagonalGridObject.array);

        glGenBuffers(1, &diagonalGridObject.buffer);
        glBindBuffer(GL_ARRAY_BUFFER, diagonalGridObject.buffer);

        glBufferData(GL_ARRAY_BUFFER, sizeof(diagonalGridData),
                     diagonalGridData, GL_STATIC_DRAW);

        glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE,
                              sizeof(Vector3), (void *)0);
        glEnableVertexAttribArray(GLKVertexAttribPosition);

        glBindVertexArrayOES(0);
}

- (void) unloadGeometry
{
        glDeleteBuffers(1, &diagonalGridObject.buffer);
        glDeleteVertexArraysOES(1, &diagonalGridObject.array);
        glDeleteBuffers(1, &cubeObject.buffer);
        glDeleteVertexArraysOES(1, &cubeObject.array);
        glDeleteBuffers(1, &sphereObject.buffer);
        glDeleteVertexArraysOES(1, &sphereObject.array);
        for (int i = ptFirst; i < ptLast; i++) {
                glDeleteBuffers(1, &pieceObject[i].buffer);
                glDeleteVertexArraysOES(1, &pieceObject[i].array);
        }
}

虽然它并没有表明你做错了什么,但我在这里添加它只是为了参考,如果有人需要的话。

我的一个解释是,您试图在应用程序初始化的错误时刻创建您的 vao,或者初始化不完全正确(例如,未设置上下文)。

我这里有以下堆栈:

- (void)setupGL
{
        [EAGLContext setCurrentContext:self.context];

        self.effect = [[[GLKBaseEffect alloc] init] autorelease];
        if (self.effect) {
                self.effect.useConstantColor = GL_TRUE;
                self.effect.colorMaterialEnabled = GL_TRUE;
                self.effect.light0.enabled = GL_TRUE;
                self.effect.light0.diffuseColor = GLKVector4Make(1.0f, 1.0f, 1.0f, 1.0f);
        }

        ((GLKView *)self.view).drawableMultisample = GLKViewDrawableMultisample4X;
        self.pauseOnWillResignActive = YES;
        self.resumeOnDidBecomeActive = YES;
        self.preferredFramesPerSecond = 30;

        glDisable(GL_DITHER);
        glEnable(GL_CULL_FACE);
        glEnable(GL_DEPTH_TEST);
        glLineWidth(2.0f);
        [self loadGeometry];
}

- (void)viewDidLoad
{
        [super viewDidLoad];
        self.context = [[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2] autorelease];
        if (!self.context)
                NSLog(@"Failed to create ES context");

        GLKView *view = (GLKView *)self.view;
        view.context = self.context;
        view.drawableDepthFormat = GLKViewDrawableDepthFormat24;

        [self setupGL];
}

【讨论】:

  • 谢谢 - 这给了我另一个参考例子来挖掘和比较。这通常只是一个找到显着差异的正确示例的情况:-) 如果出现任何问题,会通知您。
  • 进一步挖掘表明,与其说是创建 VAO 未能返回非零 ID,不如说是失败的第一件事是 glGenBuffers - 它什么也不做,但不返回错误;它根本无法返回一个值(尽管第一次确实可以正常工作)。
  • 你什么时候加载你的vao?在我的示例中,它是在 viewDidLoad 时间完成的。
【解决方案2】:

好的,我终于破解了。

事实证明,我有一些类似 RAII 的代码,它们会在线程上的一些 OpenGL 操作之前和之后调用 setCurrentContext。至关重要的是,当一个范围结束时它会 [EAGLContext setCurrentContext:nil]...但是这些范围可以嵌套,并且它对每个嵌套范围都这样做,而不是最后一个范围。

结果是调用 OpenGL 时当前上下文为 nil。 OpenGL 调用只是“什么都不做”,而“什么也不做”包括“不抛出错误”——你会认为 glGetError() 至少可能已经说了些什么。

所以,如果您没有设置当前上下文,那么 Mac 上的 GL 似乎崩溃了,但 IOS 上的 GLES 只是提前退出,没有错误。

【讨论】:

    猜你喜欢
    • 2015-06-02
    • 2012-01-01
    • 1970-01-01
    • 2019-04-02
    • 2013-01-06
    • 1970-01-01
    • 1970-01-01
    • 2017-11-16
    • 2017-03-20
    相关资源
    最近更新 更多