【问题标题】:OpenGL debug or verbose information to consoleOpenGL 调试或详细信息到控制台
【发布时间】:2021-05-27 17:35:58
【问题描述】:

是否有某种调试模式可以运行 OpenGL,将信息输出到控制台?我有一个应用程序在许多机器上都能正常工作,但在一台真正重要的机器上却惨遭失败。我无法直接访问那台机器,所以我试图弄清楚它是如何失败的。目前我在控制台中看不到任何输出。请注意,该应用程序最初是一个没有控制台的 Windows 应用程序,我通过项目属性将其切换到控制台。此外,如果重要的是某些对象不显示,而另一个对象被卡住并且没有动画 - 这对我来说没有任何意义。

【问题讨论】:

    标签: opengl


    【解决方案1】:

    不,不是真的。如果你真的想要一些详细的输出,你将不得不为 OpenGL 编写一个钩子并记录它所做的所有调用(这是像 gDEBugger 这样的工具所做的),但这需要相当多的工作(你可以使用类似GLIntercept 的东西那个。)根据个人经验:最简单的方法可能是访问有问题的机器并在那里运行 gDEBugger ...

    或者,您可以尝试使用 ARB_debug_output 扩展名,理论上该扩展名应该为您提供更多输出。在实践中,你得到的只是在每次 OpenGL API 调用之后调用glGetError,这对于你的用例来说可能已经足够好了(即你只是做一些破坏 GL 状态的事情。)为了使用调试输出扩展,你必须修改您的应用程序以创建调试上下文。

    【讨论】:

    • ARB_debug_output 的实用性取决于 OpenGL 实现。 NVIDIA 基本上是glGetError 版本,但 AMD 的版本更有用。它不会简单地向你反刍“GL_INVALID_OPERATION”;它通常会告诉您有用的信息,例如导致它的功能等等。我已经看到它专门识别核心上下文中不推荐使用的函数调用。着色器编译和链接错误将在失败时转储相应的日志。等等。
    • ARG_debug_ouput 是自版本 4.3 以来核心规范的一部分。
    【解决方案2】:

    这是在 Windows 10 上使用 C++/GLEW/GLFW 和 Visual Studio 2019 的方法,只是相关部分:

    /** Necessary includes */
    
    #include <map>
    #include <GL/glew.h>
    #include <GLFW/glfw3.h>
    
    /** Debug callback prototype */
    
    void GLAPIENTRY GLDebugMessageCallback(GLenum Source,
        GLenum Type,
        GLuint Id,
        GLenum Severity,
        GLsizei Length,
        const GLchar* Message,
        const void* UserParam);
    
    /** Create the window and set the OpenGL context */
    
    int main(void)
    {
        if (glfwInit() != GLFW_TRUE)
        {
            printf("Unable to initialize GLFW\n");
            return EXIT_FAILURE;
        }
    
        /** Set the OpenGL Debug Context hint */
    
        glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
    
        GLFWwindow* Window = glfwCreateWindow(800, 600, "OpenGL", nullptr, nullptr);
    
        if (!Window)
        {
            glfwTerminate();
            printf("Unable to create a GLFW window\n");
            return EXIT_FAILURE;
        }
    
        glfwMakeContextCurrent(Window);
    
        if (glewInit() != GLEW_OK)
        {
            printf("Unable to initialize GLEW\n");
            return EXIT_FAILURE;
        }
    
        /** Check whether debug context is enabled and set the debug callback */
    
        GLint ContextFlags;
        glGetIntegerv(GL_CONTEXT_FLAGS, &ContextFlags);
    
        if (ContextFlags & GL_CONTEXT_FLAG_DEBUG_BIT)
        {
            printf("OpenGL : Debug Context Is Enabled");
    
            glEnable(GL_DEBUG_OUTPUT);
            glDebugMessageCallback(GLDebugMessageCallback, 0);
        }
    
        while (!glfwWindowShouldClose(Window))
        {
            glfwPollEvents();
    
            // Edit here...
    
            glfwSwapBuffers(Window);
        }
    
        glfwDestroyWindow(Window);
        glfwTerminate();
    
        return EXIT_SUCCESS;
    }
    
    /** Debug callback definition */
    
    void GLAPIENTRY GLDebugMessageCallback(GLenum Source,
        GLenum Type,
        GLuint Id,
        GLenum Severity,
        GLsizei Length,
        const GLchar* Message,
        const void* UserParam)
    {
        static std::map<GLenum, const GLchar*> Sources =
        {
            {GL_DEBUG_SOURCE_API, "API"},
            {GL_DEBUG_SOURCE_WINDOW_SYSTEM, "WINDOW_SYSTEM"},
            {GL_DEBUG_SOURCE_SHADER_COMPILER, "SHADER_COMPILER"},
            {GL_DEBUG_SOURCE_THIRD_PARTY, "THIRD_PARTY"},
            {GL_DEBUG_SOURCE_APPLICATION, "APPLICATION"},
            {GL_DEBUG_SOURCE_OTHER, "OTHER"}
        };
    
        static std::map<GLenum, const GLchar*> Severities =
        {
            {GL_DEBUG_SEVERITY_HIGH, "HIGH"},
            {GL_DEBUG_SEVERITY_MEDIUM, "MEDIUM"},
            {GL_DEBUG_SEVERITY_LOW, "LOW"},
            {GL_DEBUG_SEVERITY_NOTIFICATION, "NOTIFICATION"}
        };
    
        static std::map<GLenum, const GLchar*> Types =
        {
            {GL_DEBUG_TYPE_ERROR, "ERROR"},
            {GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, "DEPRECATED_BEHAVIOR"},
            {GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, "UNDEFINED_BEHAVIOR"},
            {GL_DEBUG_TYPE_PORTABILITY, "PORTABILITY"},
            {GL_DEBUG_TYPE_PERFORMANCE, "PERFORMANCE"},
            {GL_DEBUG_TYPE_MARKER, "MARKER"},
            {GL_DEBUG_TYPE_PUSH_GROUP, "PUSH_GROUP"},
            {GL_DEBUG_TYPE_POP_GROUP, "POP_GROUP"},
            {GL_DEBUG_TYPE_OTHER, "OTHER"}
        };
    
        printf("[OpenGL %s] - SEVERITY: %s, SOURCE: %s, ID: %d: %s\n", Types[Type], Severities[Severity], Sources[Source], Id, Message);
    }
    

    样本输出

    [OpenGL ERROR] - SEVERITY: HIGH, SOURCE: API, ID: 1282: GL_INVALID_OPERATION error generated. Function glColor4fv is deprecated and not available in preview contexts.
    [OpenGL ERROR] - SEVERITY: HIGH, SOURCE: API, ID: 1282: GL_INVALID_OPERATION error generated. Array object is not active.
    [OpenGL OTHER] - SEVERITY: NOTIFICATION, SOURCE: API, ID: 131185: Buffer detailed info: Buffer object 1 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_DYNAMIC_DRAW) will use SYSTEM HEAP memory as the source for buffer object operations.
    [OpenGL OTHER] - SEVERITY: NOTIFICATION, SOURCE: API, ID: 131185: Buffer detailed info: Buffer object 1 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_DYNAMIC_DRAW) has been mapped WRITE_ONLY in SYSTEM HEAP memory (fast).
    

    经测试

    OpenGL 4.6
    GLSL 4.60 英伟达
    渲染器:采用 Max-Q 设计/PCIe/SSE2 的 GeForce RTX 2070
    供应商:NVIDIA Corporation

    Printing to the Visual Studio Output window

    #include <windows.h> // For OutputDebugStringA 
    

    将调试回调定义末尾的printf 替换为以下内容:

    char ErrorString[512];
    sprintf_s(ErrorString, "[OpenGL %s] - SEVERITY: %s, SOURCE: %s, ID: %d: %s\n", Types[Type], Severities[Severity], Sources[Source], Id, Message);
    OutputDebugStringA(ErrorString);
    

    关于调试上下文的通知

    简而言之,当在调试上下文模式下创建 OpenGL 上下文时,会在应用程序、驱动程序和 GPU 之间的路径中激活附加层。 这些附加层执行错误检查、参数分析等,并通过调试消息回调将其作为格式正确的消息报告回来。

    启用 OpenGL 调试上下文是特定于平台的,因此 GLFW 在这个意义上很有帮助,因为它提供了一种通过 glfwWindowHint 配置 OpenGL 上下文的方法,应该在创建 GLFW 窗口之前进行配置。

    来自 OpenGL Wiki - Enabling Debug Output

    除非启用调试输出,否则不会生成、检索或记录任何消息。它是通过使用带有 GL_DEBUG_OUTPUT 枚举器的 glEnable 来启用的。

    在调试上下文中,调试输出开始启用。在非调试上下文中,即使启用了调试输出,OpenGL 实现也可能不会生成消息。

    我验证了在 Windows 10 上,实际上只是通过启用调试输出和设置回调来生成一些输出,而没有激活调试上下文。

    docs.GLOpenGL Wiki 上的 glDebugMessageCallback 的详细信息以及 OpenGL Superbible 第 7 版。

    【讨论】:

    • 您的代码缺少一个关键部分:在上下文创建时实际请求“调试”上下文。此外,main 的示例令人困惑,因为它表明您可以在创建上下文之前进行 GL 调用。
    • 该代码仍然没有请求调试上下文。尽管某些驱动程序即使在正常上下文中仍会生成 一些 调试消息,但您通常会在调试上下文中收到更多消息。
    • 同意,我添加了调试上下文提示。再次感谢。
    猜你喜欢
    • 2013-10-02
    • 2017-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-06
    • 2021-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多