调试OpenGL的最佳方法是什么?

时间:2009-02-05 21:36:27

标签: opengl debugging

我发现很多时候,OpenGL会通过不绘制任何东西来告诉你失败。我正试图通过检查转换矩阵堆栈等来找到调试OpenGL程序的方法。调试OpenGL的最佳方法是什么?如果代码外观和感觉顶点都在正确的位置,你怎么能确定它们是什么?

10 个答案:

答案 0 :(得分:29)

没有直接答案。这一切都取决于你想要了解的内容。由于OpenGL是一个状态机,有时它没有按照你所期望的那样做,因为没有设置所需的状态或类似的东西。

通常,使用glTrace / glIntercept(查看OpenGL调用跟踪),gDebugger(可视化纹理,着色器,OGL状态等)和纸/铅笔等工具。有时它有助于理解你如何设置相机以及它在哪里看,被剪裁的内容等等。我个人更多地依赖于前两种方法。但是,当我认为深度是错误的时候,那么查看迹线会有所帮助。 gDebugger也是 唯一的工具,可以有效地用于分析和优化您的OpenGL应用程序。

除了这个工具之外,大部分时间都是数学,人们出错并且使用任何工具无法理解。在OpenGL.org新闻组上发布针对特定代码的评论,您将永远不会失望。

答案 1 :(得分:10)

GLIntercept是您最好的选择。从他们的网页:

  • 使用选项记录单个帧,将所有OpenGL函数调用保存为文本或XML格式。
  • 免费相机。围绕发送到图形卡的几何体飞行并启用/禁用线框/背面剔除/查看视锥体渲染
  • 保存并跟踪显示列表。 在渲染调用之前和之后保存OpenGL帧缓冲区(颜色/深度/模板)。还可以保存前后图像的“差异”。

答案 2 :(得分:8)

Apitrace是Valve的一些相对较新的工具,但效果很好!试一试:https://github.com/apitrace/apitrace

答案 3 :(得分:7)

我发现你可以在我怀疑错误的每行代码后使用glGetError进行检查,但在执行此操作后,代码看起来不是很干净但是有效。

答案 4 :(得分:7)

  

调试OpenGL的最佳方法是什么?

不考虑其他和外部工具(其他答案已经做过)。

然后一般的方法是广泛呼叫glGetError()。但是,更好的选择是使用Debug OutputKHR_debugARB_debug_output)。这为您提供了为不同严重性级别的消息设置回调的功能。

为了使用调试输出,必须使用WGL/GLX_DEBUG_CONTEXT_BIT标志创建上下文 With GLFW this can be set with the GLFW_OPENGL_DEBUG_CONTEXT window hint

glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);

请注意,如果上下文不是调试上下文,则无法保证接收所有或甚至任何消息。

检查GL_CONTEXT_FLAGS

是否可以检测到是否有调试上下文
GLint flags;
glGetIntegerv(GL_CONTEXT_FLAGS, &flags);

if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
    // It's a debug context

然后你会继续并指定一个回调:

void debugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
                  const GLchar *message, const void *userParam)
{
    // Print, log, whatever based on the enums and message
}

枚举can be seen on here的每个可能值。特别记得检查严重性,因为某些消息可能只是通知而不是错误。

您现在可以提前注册回调。

glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback(debugMessage, NULL);

glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);

您甚至可以使用glDebugMessageInsert()注入自己的消息。

glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0,
                     GL_DEBUG_SEVERITY_NOTIFICATION, -1, "Vary dangerous error");

对于着色器和程序,您始终要检查GL_COMPILE_STATUSGL_LINK_STATUSGL_VALIDATE_STATUS。如果其中任何一个反映出有问题,那么另外请务必检查glGetShaderInfoLog() / glGetProgramInfoLog()

GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);

if (!linkStatus)
{
    GLchar *infoLog = new GLchar[infoLogLength + 1];
    glGetProgramInfoLog(program, infoLogLength * sizeof(GLchar), NULL, infoLog); 

    ...

    delete[] infoLog;
}

glGetProgramInfoLog()返回的字符串将以空值终止。

您还可以更加极端,并在调试版本中使用一些调试宏。因此,使用glIs*()函数来检查期望的类型是否也是实际类型。

assert(glIsProgram(program) == GL_TRUE);
glUseProgram(program);

如果调试输出不可用且您只想使用glGetError(),那么您当然可以自由地这样做。

GLenum err;
while ((err = glGetError()) != GL_NO_ERROR)
    printf("OpenGL Error: %u\n", err);

由于数字错误代码没有帮助,我们可以通过将数字错误代码映射到邮件来使其更具人性化。

const char* glGetErrorString(GLenum error)
{
    switch (error)
    {
    case GL_NO_ERROR:          return "No Error";
    case GL_INVALID_ENUM:      return "Invalid Enum";
    case GL_INVALID_VALUE:     return "Invalid Value";
    case GL_INVALID_OPERATION: return "Invalid Operation";
    case GL_INVALID_FRAMEBUFFER_OPERATION: return "Invalid Framebuffer Operation";
    case GL_OUT_OF_MEMORY:     return "Out of Memory";
    case GL_STACK_UNDERFLOW:   return "Stack Underflow";
    case GL_STACK_OVERFLOW:    return "Stack Overflow";
    case GL_CONTEXT_LOST:      return "Context Lost";
    default:                   return "Unknown Error";
    }
}

然后像这样检查:

printf("OpenGL Error: [%u] %s\n", err, glGetErrorString(err));

这仍然不是非常有用或者说直观,好像你已经在这里和那里撒了一些glGetError()。然后找出哪一个记录错误可能会很麻烦。

再次宏来救援。

void _glCheckErrors(const char *filename, int line)
{
    GLenum err;
    while ((err = glGetError()) != GL_NO_ERROR)
        printf("OpenGL Error: %s (%d) [%u] %s\n", filename, line, err, glGetErrorString(err));
}

现在只需定义一个这样的宏:

#define glCheckErrors() _glCheckErrors(__FILE__, __LINE__)

现在你可以在你需要的所有内容之后调用glCheckErrors(),如果有错误,它会告诉你确切的文件和检测到的行。

答案 5 :(得分:4)

对于Mac上的用户,内置的OpenGL调试器也很棒。它允许您检查缓冲区,状态,并帮助您发现性能问题。

答案 6 :(得分:4)

gDebugger是一款优秀的免费工具,但不再受支持。但是,AMD已经开始了它的开发,这个调试器现在被称为CodeXL。它既可以作为独立应用程序使用,也可以作为Visual Studio插件使用 - 既适用于本机C ++应用程序,也适用于使用OpenGL绑定的Java / Python应用程序,适用于NVidia和AMD GPU。这是一个神奇的工具。

答案 7 :(得分:2)

还有免费的glslDevil:http://www.vis.uni-stuttgart.de/glsldevil/

它允许您广泛地调试glsl着色器。它还显示了失败的OpenGL调用。

然而,它缺少检查纹理和屏幕外缓冲区的功能。

答案 8 :(得分:0)

如果您有NVidia卡,

Nsight是一个很好的调试工具。

答案 9 :(得分:0)

动态更新窗口标题对我来说很方便。

示例(使用GLFW,C ++ 11):

glfwSetWindowTitle(window, ("Now Time is " + to_string(glfwGetTime())).c_str());