这一节主要讲 glGetError,它几乎在每一个 OpenGL 的版本中都有,所以在OpenGL的错误处理上比较常用。由于OpenGL实现与版本有一定关系,但是一般可以通过前缀来大致判断。函数的功能和版本。如果使用方法正确,但是却不能渲染出预期效果时,就可以再通过文档来判断是不是版本的问题。
代码框架:
用于清理Error
static void GLClearError()
{
while (glGetError() != GL_NO_ERROR);
}
//用于检查Error
static void GLCheckError()
{
while (GLenum error = glGetError())
{
std::cout << "[OpenGL Error](" << error << ")" << std::endl;
}
}
分析: 使用时,我们将这两个函数添加在 待检测出错代码 的上下。但是这样做的缺点是很明显的,首先我们不知道错误的具体类型。其次,我们无法精确定位错误发生的位置。 流程:模仿一个功能的方法是 找到一个与目标功能相似的参考对象,然后去分析和模仿。

目标需求分析:(1)一次错误检查需要多次 调用两个函数,过程繁琐。 封装使调用更便利。(2)错误定位不精确。 报错代码 文件路径,行数。都是报错的重要信息。
代码实现:
(1)解决办法:用宏包装可以简化我们调用的形式,处理错误使用ASSERT。
__debugbreak()是编译内置函数。
类似于DebugBreak,是一种可移植的Win32方法(不能在clang/gcc下使用)来导致断点异常。这允许调用线程向调试器发出信号以处理异常。
ps:内置函数:代码通常内联插入,避免函数调用的开销,但比等效内联函数汇编更快。
Compiler intrinsics | Microsoft Docs
(2)解决办法:补充更多打印信息。
//展示代码 #define ASSERT(x) if (!(x)) __debugbreak(); #define GLCall(x) GLClearError();x;ASSERT(GLLogCall(#x, __FILE__, __LINE__)) static void GLClearError() { while (glGetError() != GL_NO_ERROR); } static bool GLLogCall(const char* function, const char* file, int line) { while (GLenum error = glGetError()) { std::cout << "[OpenGL Error] (" << error << ")" << function << " " << file << ":" << line << std::endl; return false; } return true; } //调用 :通过用GLCall去包裹每一个需要检查错误的OpenGL函数 GLCall(glDrawElements(GL_TRIANGLES, 6, GL_INT,nullptr));
运行结果:

