🐕

OpenGLのデバッグを快適にするDebug Output

2023/06/28に公開

OpenGL4.3でDebug Outputという機能が追加されました。Debug Outputを使うとバッファやテクスチャなどのオブジェクトの生成、パラメーター指定などを間違えた時にエラーメッセージを受け取る事が出来るようになります。

使い方

Debug Outputを使うのは簡単です。まずはDebug Outputの機能を有効にします。

glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);

GL_DEBUG_OUTPUT_SYNCHRONOUSも指定しておくとエラーメッセージの順番が入れ替わらくなり、デバッグが楽になります。

次にエラーメッセージを処理するコールバック関数を指定します。

// エラーメッセージを処理する
void debugMessageCallback(GLenum source, GLenum type, GLuint id,
                                       GLenum severity, GLsizei length,
                                       GLchar const *message,
                                       void const *user_param)
{
    switch (severity) {
        case GL_DEBUG_SEVERITY_HIGH:
            spdlog::critical("[gl] {}", message);
            throw std::runtime_error("critical OpenGL error");
            break;
        case GL_DEBUG_SEVERITY_MEDIUM:
            spdlog::error("[gl] {}", message);
            break;
        case GL_DEBUG_SEVERITY_LOW:
            spdlog::warn("[gl] {}", message);
            break;
        case GL_DEBUG_SEVERITY_NOTIFICATION:
            spdlog::info("[gl] {}", message);
            break;
    }
}

// ...

// エラーメッセージを処理するコールバック関数の指定
glDebugMessageCallback(debugMessageCallback, nullptr);

ここではspdlogを使ってエラーメッセージの重要度(severity)に応じてメッセージ表示の内容を変えています。また、クリティカルエラーの時は実行時エラーを吐いてアプリが強制終了するようにしています。

エラー例

テクスチャの生成方法をわざと間違えてエラーを出させてみます。

GLuint texture;
glCreateTextures(GL_TEXTURE_2D, 1, &texture);

glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_LINEAR); // 間違えてGL_LINEARが指定されている
glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextureParameteri(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

これを実行すると次のようなエラーが出ます。

[2023-06-28 08:38:33.771] [critical] [gl] GL_INVALID_ENUM error generated. Invalid wrap mode.
terminate called after throwing an instance of 'std::runtime_error'
  what():  critical OpenGL error

エラーメッセージを見るとちゃんとwrap modeの指定が間違っている事を教えてくれています。従来はこのような間違えをしても具体的に何が悪かったのかまでは教えてくれず、デバッグが大変でした。Debug Outputを使うことでこのようなエラーのデバッグが簡単になります。

Discussion