glGetError() 直到下一帧才工作

glGetError() doesn't work until next frame

我正在尝试调试这个不是我写的渲染循环。某处出错导致程序崩溃,但 glGetError() 似乎表现得很滑稽。

这在 iOS 上,我正在使用 GLKViewControllerGLKViewEAGLContext 进行绘图。

渲染循环的一个总结版本是这样的:

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
   // At this point, GLKView's EAGLContext should be the active context

   checkGlGetError();

   if (!isTextureInit || geometryChanged)
   {
        setupRenderTextureAndRenderbuffer();
   } 
    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_originalFramebufferId);
    glBindFramebuffer(GL_FRAMEBUFFER, _framebufferId);

    // a. Some complex operations
    // b. Some rendering on the texture framebuffer

    glBindFramebuffer(GL_FRAMEBUFFER, _originalFramebufferId);

    // c. Some additional complex operations
    // d. Render the texture on screen

    checkGlGetError();
}

这会使应用程序崩溃。问题是第一个渲染帧的最后 checkGlGetError() 调用没有产生任何错误(屏幕上没有任何显示)。

第二个渲染帧的第一个 checkGlGetError() 调用给出了一个神秘的 GL_INVALID_ENUM,此后不久应用程序崩溃了。

如果我用这个替换我的渲染循环:

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    checkGlGetError();

    // a. Some complex operations
    // b. Some rendering on the screen

    checkGlGetError();
}

一切正常,没有报错。但是:为什么 glGetError() 在错误的 OpenGL 调用之后没有立即捕获错误?为什么它只在下一帧开始时报告它?

错误的代码很长,而且没有更多的迹象表明错误的确切位置,很难调试。


更新

我上传了所有代码 here. It's a work-in-progress port of Google's CardboardSDK (decompiled) 从 Java 到 Objective-C++ 我正在尝试完成。

主渲染循环在 CardboardViewController class 上。导致崩溃的 OpenGL 命令应该在 DistortionRenderer class 上(其功能是采用普通立体视口并将它们渲染到纹理上,以便对每个视口应用镜头失真)。

如果将 CardboardViewControllerdistortionCorrectionEnabled 设置为 NO,崩溃就会消失。

这里没有足够的信息来调试您的问题,因此,关于调试的一般说明...

glGetError 通常是调试 GL 问题的糟糕方法,但在 iOS 中尤其如此,当您使用 GLKView 或其他执行 GL 的系统时更是如此代表你工作。很可能你正在设置一些不会导致错误的状态,直到 GLKView 开始向 GPU 提交内容(当你的 drawRect:/glkView:drawInRect: returns 时)。

请尝试使用 Xcode Frame Capture tool。它不需要您在整个代码中粘贴 glGetError 检查(并确保它们在发布版本中被禁用)然后尝试理解结果,它会向您显示错误(至少在某种程度上解释)对于每次调用,包括那些在系统代码中代表您进行的调用。它显示了完整的状态图,以及逐个调用呈现的帧的快照,因此您可以更早地判断您是否正在设置导致问题的状态。


好的,有人认为这可能与您的问题有关:尝试在 GLKView 上使用 bindDrawable,而不是直接将其帧缓冲区与 glBindFramebuffer 重新绑定。