每当我在OpenGL中出现语义或语法错误时,就会出现黑屏或程序崩溃。我上网查询了如何在OpenGL中执行错误处理以及在发现的文档glGetError()中。据我了解,如果我在调用“正常” OpenGL函数后再调用它,则glGetError()将返回一个或多个错误代码,前提是我犯了一些错误。另外,我必须在while循环中调用它以获取所有错误。

我对此有多个问题。一个我找不到发生错误的行号,第二个它不能正确告诉我为什么会发生错误(虽然这不是一个大问题),最后我必须在每个OpenGL函数调用之后添加一个while循环。

下面是一个例子,

unsigned int buffer = 0;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(float), vertices, GL_STATIC_DRAW); 


现在,如果我用glGetError()编写它,它看起来就像

unsigned int err = 0;
glGenBuffers(1, &buffer);
while( !(err = glGetError()) ){
    std::cout << err;
}  
glBindBuffer(GL_ARRAY_BUFFER, buffer);
while( !(err = glGetError()) ){
    std::cout << err;
}  
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(float), vertices, GL_STATIC_DRAW); 
while( !(err = glGetError()) ){
    std::cout << err;
}  


当然不是这样,对吧?源代码看起来很丑。

我该如何使用OpenGL进行正确的错误处理?

我的图形卡支持OpenGL 4.4,并且我正在使用C ++。

评论

我最近部分回答了类似的问题。请参阅computergraphics.stackexchange.com/a/5773/182

不应该在while(err = glGetError())读取)

它返回GL_NO_ERROR,我假定它的值为0,没有错误时,这就是为什么我有!=的原因。无论如何都应该是while((err = glGetError())!= GL_NO_ERROR)。

#1 楼

是的,有更好的方法! 😊OpenGL 4.3和更高版本支持glDebugMessageCallback API,该API允许您在应用程序中指定GL将调用以发出警告或错误的功能。在此功能中,您可以执行任何操作,例如在调试器中设置断点,或将错误打印到日志文件中。这样,您只需要在初始化期间设置回调即可,这比将glGetError调用无处不在要好得多。

要启用此功能,您的GL上下文也需要是一个“调试上下文”,由创建上下文时设置标志。详细信息将取决于您所使用的OS /窗口系统/框架。调试上下文(在CPU上)可能比常规上下文要慢,但这就是您为更详细的调试信息所付出的代价,就像在编译器中关闭优化一样。

另请参阅此Wiki页面欲获得更多信息。还有很多其他与调试相关的功能。例如,您可以使用glObjectLabel为纹理,缓冲区,帧缓冲区等提供易于理解的名称,然后(我假设)它们将用于错误消息中。还有一些API可用于关闭某些消息或某些类别的消息,以防因您不关心或类似的警告而被垃圾邮件感染。

#2 楼

尽管“调试输出”很好,并且可以手动使用glGetError,但通常最好使用更专用的工具来精确查找OpenGL错误的来源。

RenderDoc可能是最新的工具用于此过程,但是有很多处于各种功能状态。这些工具还可以为您提供每个OpenGL调用的详细日志。

#3 楼

如果您无法使用OpenGL 4.3(或者您的实现不支持glDebugMessageCallback),则可以通过多种方式简化代码。

第一个方法是将对glGetError()的调用移至这样的函数:

void checkGLError()
{
    GLenum err;
    while((err = glGetError()) != GL_NO_ERROR){
        std::cout << err;
    }  
}


将代码减少为:

unsigned int buffer = 0;
glGenBuffers(1, &buffer);
checkGLError();
glBindBuffer(GL_ARRAY_BUFFER, buffer);
checkGLError();
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(float), vertices, GL_STATIC_DRAW); 
checkGLError();


但是,经常调用glGetError()可能会损害性能,因此最好对其进行条件化,以便仅通过执行以下操作在调试版本中对其进行调用:

#if DEBUG
#define checkGLError() debugCheckGLError()
#else
#define checkGLError()
#endif


,然后将实际函数命名为debugCheckGLError()。它会在调试版本中被调用,但不会在发布版本中被调用。

评论


$ \ begingroup $
我将debug宏与其他答案一起使用。谢谢。
$ \ endgroup $
–user8277998
17年4月4日在16:23

$ \ begingroup $
您可以对宏进行更进一步的操作,例如:github.com/bkaradzic/bgfx/blob/…这样您的代码就变成了:GL_CHECK(glGenBuffers(1,&buffer));并报告您需要的一切。
$ \ endgroup $
–朱利安·盖尔特(Julien Guertault)
17年12月6日在2:47

$ \ begingroup $
我不明白while(!(err = glGetError())为什么!?不应该是:while(err = glGetError())使它循环并输出错误消息吗?否则,不是吗?它是一个无限循环,在第一个成功调用中反复显示0吗?
$ \ endgroup $
–维克
20 Mar 4 '20 at 5:49

$ \ begingroup $
@Wyck是的,您是正确的。我已经更新了它,使其与正确的错误值进行比较,使其更加明确。
$ \ endgroup $
–user1118321
20 Mar 7 '20 at 21:07