【问题标题】:glDebugMessageCallback doesn't get called despite of error尽管出现错误,glDebugMessageCallback 不会被调用
【发布时间】:2020-06-14 14:21:01
【问题描述】:

我在 C++ 程序中使用 GLFW 和 GLEW 来处理 OpenGL。我希望能够将 OpenGL 错误输出到控制台。为了测试这一点,我做了一个小程序:

#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>

// Test error function
void GLAPIENTRY MessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) {
    std::cout << "ERROR";
}

// Main function
int main(void)
{
    // Just some initialization
    GLFWwindow* window;

    if (!glfwInit()) {
        return -1;
    }

    window = glfwCreateWindow(640, 480, "Debugtest", NULL, NULL);
    if (!window) {
        glfwTerminate();
        return -1;
    }

    glfwMakeContextCurrent(window);
    glewInit();

    // Output the opengl version
    std::cout << glGetString(GL_VERSION) << std::endl;

    // Enable debug output
    glEnable(GL_DEBUG_OUTPUT);
    glDebugMessageCallback(MessageCallback, 0);

    unsigned int buffer;
    glGenBuffers(-1, &buffer); // -1 throws an error according to http://docs.gl/gl4/glGenBuffers

    // Loop until the user closes the window
    while (!glfwWindowShouldClose(window)) {
        glfwPollEvents();
    };

    glfwTerminate();
    return 0;
}

回调代码来自the khronos documentationglGenBuffers 应该根据the docs 抛出错误。但是,OpenGL 窗口保持白色,终端只显示 OpenGL 版本(4.5.13474 Copatibility Profile Context 22.19.162.4)。

处理错误的最佳方法是什么?如何修复我的代码?

【问题讨论】:

  • 您是否请求 OpenGL 调试上下文?否则永远不会调用错误回调。
  • 在调用glCreateWindow()之前,您是否使用glfwWindowHint (GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);进行验证

标签: c++ debugging opengl error-handling


【解决方案1】:

感谢@OutOfBound 我找到了答案。在glfwCreateWindow 之前,您需要调用glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE)

与他的回答类似,您可以在发生错误时执行以下操作来中断(至少使用 MSVC 编译器):

#define call(x) x;\
    if (error) __debugbreak();

bool error = false;

void GLAPIENTRY MessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) {
    error = true;
    std::cout << "[OpenGL Error](" << type << ") " << message << std::endl;
}

【讨论】:

    【解决方案2】:

    在我的 OpenGL 项目中,我通过错误检查将每个调用包装到 OpenGL API 中。我的方法是这样的:

    std::string error_description(GLenum err) {
        switch(err) {
            case GL_NO_ERROR:
                return "GL_NO_ERROR: No error has been recorded. The value of this symbolic constant is guaranteed to be 0. ";
            case GL_INVALID_ENUM:
                return "GL_INVALID_ENUM: An unacceptable value is specified for an enumerated argument. The offending command is ignored and has no other side effect than to set the error flag.  ";
            case GL_INVALID_VALUE:
                return "GL_INVALID_VALUE: A numeric argument is out of range. The offending command is ignored and has no other side effect than to set the error flag.  ";
            case GL_INVALID_OPERATION:
                return "GL_INVALID_OPERATION: The specified operation is not allowed in the current state. The offending command is ignored and has no other side effect than to set the error flag.  ";
            case GL_INVALID_FRAMEBUFFER_OPERATION:
                return
                "GL_INVALID_FRAMEBUFFER_OPERATION: The framebuffer object is not complete."
                "The offending command is ignored and has no other side effect than to set the error flag.";
            case GL_OUT_OF_MEMORY:
                return "GL_OUT_OF_MEMORY: There is not enough memory left to execute the command. The state of the GL is undefined, except for the state of the error flags, after this error is recorded. . ";
            case GL_STACK_UNDERFLOW:
                return "GL_STACK_UNDERFLOW: An attempt has been made to perform an operation that would cause an internal stack to underflow. ";
            case GL_STACK_OVERFLOW:
                return "GL_STACK_OVERFLOW: An attempt has been made to perform an operation that would cause an internal stack to overflow. ";
            default:
                return "No Description";
        }
    }
    
    namespace detail {
        void check() {
            const auto err = glGetError();
            if(err != GL_NO_ERROR) {
                throw std::runtime_error(error_description(err));
            }
        }
    
    }
    
    
    template <class result_t, class... gl_args_t, class... args_t>
    result_t call(result_t (*fun)(gl_args_t...), args_t... args) {
        if constexpr(!std::is_same_v<result_t, void>) {
            auto result = fun(std::forward<args_t>(args)...);
            #ifndef NDEBUG
                detail::check();
            #endif
            return result;
        } else {
            fun(std::forward<args_t>(args)...);
            #ifndef NDEBUG
                detail::check();
            #endif
        }
    }
    

    在应用程序中,我这样调用 API:

    call(<api_call>, <arguments...>>);
    call(glGenBuffers, 1, &buffer);
    

    原因,为什么我更喜欢错误检查而不是错误回调:

    • 未处理的异常将终止您的程序,并且可以轻松识别出损坏的代码行
    • 如果您随后将所有对 OpenGL 的调用封装起来,那么您就知道您的状态机始终处于已定义的状态

    【讨论】:

    • 这如何回答这个问题? Op 已经有一个调试回调,它与您的代码基本相同。
    • 谢谢,我现在正在尝试类似的方法,但回调对我来说似乎更优雅。
    猜你喜欢
    • 2015-02-18
    • 2012-09-14
    • 2014-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-23
    相关资源
    最近更新 更多