如何使用 GLEW 进行自动 OpenGL 错误检查?
How to do automatic OpenGL error checking using GLEW?
我最近试图在每次 OpenGL 函数调用后实现自动错误检查。我考虑过将每个 OpenGL 函数包装在这样的调用者中:
CheckForErrors(glCreateBuffers(1, &VBO));
但我看到 GLEW 已经使用了它自己的函数包装器:
#define GLEW_GET_FUN(x) x
所以我决定编辑它而不是编写我自己的函数包装器:
#ifndef GLEW_GET_FUN
#ifdef DEBUG
#define GLEW_GET_FUN(x) while (glGetError() != GL_NO_ERROR);\
x; {\
GLenum error = glGetError();\
if (error != GL_NO_ERROR) {\
printf("[GLEW]: OpenGL error(s) occured while calling %s in %s (line %s):", #x, __FILE__, __LINE__);\
do printf(" %d", error); while (error = glGetError());\
printf("\n");\
__debugbreak();\
}
#else
#define GLEW_GET_FUN(x) x
#endif
#endif
不幸的是,这无法编译。例如这个函数调用:
GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
预处理器更改为:
GLuint vertexShaderID = while (glGetError() != GL_NO_ERROR); __glewCreateShader; { GLenum error = glGetError(); if (error != 0) { printf("[GLEW]: OpenGL error(s) occured while calling %s in %s (line %s):", "__glewCreateShader", "main.cpp", 51); do printf(" %d", error); while (error = glGetError()); printf("\n"); __debugbreak(); }(GL_VERTEX_SHADER);
这里有2个问题:
- 该语句以 while 循环开始,因此它不能 return 值。
- 带有函数参数的圆括号放在整个东西之后,而不是紧跟在函数调用之后。
我不知道如何克服这些问题,我将不胜感激。
备注
- 我知道
glDebugMessageCallback()
函数,但它仅在 OpenGL 4.3+ 中可用,这是一个相当新且部分不受支持的版本。
- 我无法删除开头的 while 循环,因为我必须在调用该函数之前清除所有错误(除非有不同的方法来执行此操作)。
- 我正在尝试做类似 this 的事情,但没有使用单独的函数包装器。
I don't know how to overcome those problems
你不能。您想做的事情根本无法按照您想要的方式行事。你不能把一个表达式(函数调用就是这样)变成一个语句(或者更确切地说,一系列语句)并且让它在任何地方都有效。它只在表达式用作语句的情况下有效。
如果您不愿意定期将错误检查代码插入您的应用程序,并且无法使用现代调试消息API,那么标准的解决方案是使用外部工具来查找和报告错误.例如,RenderDoc 可以检测 OpenGL 错误。它允许您记录每个 OpenGL 调用,并可以在错误发生时随时报告错误。
正如尼可波拉斯所说,不可能按照我最初想要的方式去做,但我会描述为什么会这样,以及可以做些什么。
问题
GLEW 仅用 GLEW_GET_FUN() 包装函数的 name,因此函数参数将始终放置在定义结束之后,因为它们不包括在内其中:
//In code:
glGenBuffers(1, &VBO);
//After preprocessing:
{stuff generated by GLEW_GET_FUN}(1, &VBO);
预处理不是很智能,所以它只会将函数参数放在最后。
其他解决方案
- 如问题中所述,如果可用,可以使用
glDebugMessageCallback()
。
- 用自定义包装器包装每个函数。根本不是自动的,但如果有人感兴趣 here 是关于如何制作一个的很棒的教程。
我最近试图在每次 OpenGL 函数调用后实现自动错误检查。我考虑过将每个 OpenGL 函数包装在这样的调用者中:
CheckForErrors(glCreateBuffers(1, &VBO));
但我看到 GLEW 已经使用了它自己的函数包装器:
#define GLEW_GET_FUN(x) x
所以我决定编辑它而不是编写我自己的函数包装器:
#ifndef GLEW_GET_FUN
#ifdef DEBUG
#define GLEW_GET_FUN(x) while (glGetError() != GL_NO_ERROR);\
x; {\
GLenum error = glGetError();\
if (error != GL_NO_ERROR) {\
printf("[GLEW]: OpenGL error(s) occured while calling %s in %s (line %s):", #x, __FILE__, __LINE__);\
do printf(" %d", error); while (error = glGetError());\
printf("\n");\
__debugbreak();\
}
#else
#define GLEW_GET_FUN(x) x
#endif
#endif
不幸的是,这无法编译。例如这个函数调用:
GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
预处理器更改为:
GLuint vertexShaderID = while (glGetError() != GL_NO_ERROR); __glewCreateShader; { GLenum error = glGetError(); if (error != 0) { printf("[GLEW]: OpenGL error(s) occured while calling %s in %s (line %s):", "__glewCreateShader", "main.cpp", 51); do printf(" %d", error); while (error = glGetError()); printf("\n"); __debugbreak(); }(GL_VERTEX_SHADER);
这里有2个问题:
- 该语句以 while 循环开始,因此它不能 return 值。
- 带有函数参数的圆括号放在整个东西之后,而不是紧跟在函数调用之后。
我不知道如何克服这些问题,我将不胜感激。
备注
- 我知道
glDebugMessageCallback()
函数,但它仅在 OpenGL 4.3+ 中可用,这是一个相当新且部分不受支持的版本。 - 我无法删除开头的 while 循环,因为我必须在调用该函数之前清除所有错误(除非有不同的方法来执行此操作)。
- 我正在尝试做类似 this 的事情,但没有使用单独的函数包装器。
I don't know how to overcome those problems
你不能。您想做的事情根本无法按照您想要的方式行事。你不能把一个表达式(函数调用就是这样)变成一个语句(或者更确切地说,一系列语句)并且让它在任何地方都有效。它只在表达式用作语句的情况下有效。
如果您不愿意定期将错误检查代码插入您的应用程序,并且无法使用现代调试消息API,那么标准的解决方案是使用外部工具来查找和报告错误.例如,RenderDoc 可以检测 OpenGL 错误。它允许您记录每个 OpenGL 调用,并可以在错误发生时随时报告错误。
正如尼可波拉斯所说,不可能按照我最初想要的方式去做,但我会描述为什么会这样,以及可以做些什么。
问题
GLEW 仅用 GLEW_GET_FUN() 包装函数的 name,因此函数参数将始终放置在定义结束之后,因为它们不包括在内其中:
//In code:
glGenBuffers(1, &VBO);
//After preprocessing:
{stuff generated by GLEW_GET_FUN}(1, &VBO);
预处理不是很智能,所以它只会将函数参数放在最后。
其他解决方案
- 如问题中所述,如果可用,可以使用
glDebugMessageCallback()
。 - 用自定义包装器包装每个函数。根本不是自动的,但如果有人感兴趣 here 是关于如何制作一个的很棒的教程。