首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

通过 GL_KHR_debug 在 ARM Mali GPU 上更轻松地进行 OpenGL ES 调试-1

通过 GL_KHR_debug 在 ARM Mali GPU 上更轻松地进行 OpenGL ES 调试-1

最近,我们向 Midgard 架构
OpenGL ES 驱动程序增加了对该扩展的支持。在本文中,我将介绍如何用该扩展来改善错误报告,并使其更易调试 OpenGL ES 应用程序。
管理状态
OpenGL ES 保有大量状态,而当前错误是这种状态的组成部分。这有两个后果:可能因状态组合而出现错误,且只可以记录一个错误。
如果仅因 API 调用中的无效参数而发生错误,则它们的原因可能相对明显。不过,由于状态组合而产生可能错误,结合两个合法的命令序列可能会导致原因往往不太明显的错误。
例如:
// This does not generate any errors.
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);
GLenum error = glGetError(); // GL_NO_ERROR
// This does not generate any errors either.
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
GLenum error = glGetError(); // GL_NO_ERROR
// But repeating the first sequence now, does generate an error.
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);
GLenum error = glGetError(); // GL_INVALID_FRAMEBUFFER_OPERATION
OpenGL ES 状态仅存储单个错误,指定为产生的第一个错误。后续错误会被检测到,但对错误状态没有影响且不会进行报告。没有有关错误产生时间的任何信息。这些限制相结合使得难以确定错误原因,因此需要较长时间才能发现和解决问题。
更为糟糕的是,OpenGL ES API 返回的错误非常广泛,并不总是指向明显的原因。在 OpenGL ES 3.0 中,可用错误代码是:
  • GL_INVALID_ENUM: enum argument out of range
  • GL_INVALID_VALUE: Numeric argument out of range
  • GL_INVALID_OPERATION: Operation illegal in current state
  • GL_INVALID_FRAMEBUFFER_OPERATION: Framebuffer is incomplete
  • GL_OUT_OF_MEMORY: Not enough memory left to execute command
每个 API 调用可能触发这些错误中的一个或多个。单个 API 调用也可能因多种原因而触发相同的错误。
最极端的例子是 GL_OUT_OF_MEMORY
错误,其可由 任意 API 调用产生,虽然其名称暗示内存不足条件,但其有时会由驱动程序用来报告其他错误条件(如 GPU 超时)。
OpenGL ES 规范不记录哪些错误可以由哪个 API 调用所产生。相反,它将所有 API 调用的大多数错误保留为隐含状态,仅记录这些隐含错误的例外和附加内容。这使得非常难以确定为何错误由特定的 API 调用设置。
确实记录每个 API 调用的错误,但这些页面并非权威参考。最近重组的 已使这一情况更为清晰,但该重组尚未应用到 OpenGL ES 规范。
部分解决方案
上述问题的部分解决方案一般归结为每隔一段时间检查错误 - 至少在调试版本中。这可以是少到每帧一次,多到每个 API 调用一次,或介于两者之间。
例如,错误检查可以用作某个函数的前和后置条件:
#ifdef _DEBUG
#define CHECK_GL_ERROR() check_gl_error_and_print()
#else
#define CHECK_GL_ERROR()
#endif
void check_gl_error_and_print(void)
{
GLenum error = glGetError();
if (error != GL_NO_ERROR)
{
printf("GL error detected: 0x%04x\n", error);
}
}
void load_texture(GLsizei width, GLsizei height, GLvoid *data)
{
CHECK_GL_ERROR();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
CHECK_GL_ERROR();
}
返回列表