glDebugMessageCallback не вызывается несмотря на ошибку - PullRequest
1 голос
/ 02 марта 2020

Я использую GLFW и GLEW в программе на C ++ для работы с 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;
}

Код для обратного вызова взят из документации khronos . glGenBuffers должен выдать ошибку в соответствии с документами . Однако окно OpenGL остается белым, а терминал просто отображает версию OpenGL (4.5.13474 Copatibility Profile Context 22.19.162.4).

Каков наилучший способ обработки ошибок? Как мне исправить мой код?

Ответы [ 2 ]

2 голосов
/ 02 марта 2020

Благодаря @OutOfBound я нашел ответ. Прежде чем glfwCreateWindow, вам нужно позвонить glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE).

Подобно его ответу, вы можете сделать что-то подобное, чтобы прервать работу при возникновении ошибки (по крайней мере, с помощью компилятора MSV C):

#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;
}
0 голосов
/ 02 марта 2020

В моих проектах 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, то вы знаете, что ваш конечный автомат всегда находится в определенном состоянии
...