web-dev-qa-db-ja.com

OpenGLをデバッグする最良の方法は何ですか?

多くの場合、OpenGLは何も描画しないことで失敗したことを示します。変換マトリックススタックなどを調べることで、OpenGLプログラムをデバッグする方法を見つけようとしています。 OpenGLをデバッグする最良の方法は何ですか?コードが頂点が適切な場所にあるように見える場合、どのようにしてそれらを確認できますか?

60
dreamlax

直接的な答えはありません。それはすべてあなたが理解しようとしているものに依存します。 OpenGLは状態マシンであるため、必要な状態が設定されていないなどの理由で、期待どおりに動作しない場合があります。

一般に、glTrace/glIntercept(OpenGL呼び出しトレースを見る)、gDebugger(テクスチャ、シェーダー、OGL状態などを視覚化する)、および紙/鉛筆:)のようなツールを使用します。カメラをどのように設定し、どこで見ているか、何がクリップされているかなどを理解するのに役立つ場合があります。しかし、深さが間違っていると主張できる場合は、トレースを見ると役立ちます。 gDebuggerは、OpenGLアプリのプロファイリングと最適化に効果的に使用できるtheのみのツールでもあります。

このツールとは別に、ほとんどの場合、人が間違っているのは数学であり、ツールを使用して理解することはできません。 OpenGL.orgニュースグループにコード固有のコメントを投稿すると、失望することはありません。

29
Ketan

GLIntercept が最善の策です。彼らのウェブページから:

  • 個々のフレームを記録するオプションを使用して、テキストまたはXML形式へのすべてのOpenGL関数呼び出しを保存します。
  • 無料カメラ。グラフィックスカードに送信されたジオメトリを飛び回って、ワイヤフレーム/背面カリング/視錐台レンダリングを有効/無効にします
  • 表示リストを保存および追跡します。 OpenGLフレームバッファー(色/深さ/ステンシル)のレンダリング前およびレンダリング後の呼び出しの保存。前後の画像の「差分」を保存する機能も利用できます。
10
David Segonds

Apitraceは、Valveの一部の人々からの比較的新しいツールですが、すばらしい機能です!試してみてください: https://github.com/apitrace/apitrace

8
Foxor

OpenGLをデバッグする最良の方法は何ですか?

追加および外部ツールを考慮することなく(他の回答はすでに行っています)。

それから一般的な方法は glGetError() を広範囲に呼び出すことです。ただし、より良い代替手段は デバッグ出力KHR_debugARB_debug_output )を使用することです。これにより、さまざまな重大度レベルのメッセージにコールバックを設定する機能が提供されます。

デバッグ出力を使用するには、_WGL/GLX_DEBUG_CONTEXT_BIT_フラグを使用してコンテキストを作成する必要がありますGLFWでは、これは_GLFW_OPENGL_DEBUG_CONTEXT_ウィンドウヒントで設定できます

_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
}
_

列挙型の各可能な値 ここで見ることができます 。特に、重大度を確認することを忘れないでください。一部のメッセージは単なる通知であり、エラーではない場合があります。

これで先に進み、コールバックを登録できます。

_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_STATUS_、_GL_LINK_STATUS_、および_GL_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()によって返される文字列はnullで終了します。


また、もう少し極端に進んで、デバッグビルドでいくつかのデバッグマクロを利用することもできます。したがって、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()を呼び出すことができます。エラーが発生した場合は、検出された正確なファイルと行を通知します。

7
Vallentin

疑わしいコードの各行の後にglGetErrorを使用してチェックできることがわかりましたが、それを実行すると、コードはあまりきれいに見えませんが、動作します。

7
Frank Cheng

GDebuggerは優れた無料のツールですが、サポートされなくなりました。ただし、AMDは開発を開始し、このデバッガーは現在、 CodeXL として知られています。 NVidiaとAMD GPUの両方で、スタンドアロンアプリケーションまたはVisual Studioプラグインの両方として利用できます。ネイティブC++アプリケーション、またはOpenGLバインディングを使用するJava/Pythonアプリケーションの両方で動作します。それはツールの地獄です。

4
axel22

Macを使用している場合は、組み込みのOpenGLデバッガーも優れています。バッファ、状態を検査し、パフォーマンスの問題を見つけるのに役立ちます。

4
Sijmen Mulder

無料のglslDevilもあります。 http://www.vis.uni-stuttgart.de/glsldevil/

Glslシェーダーを広範囲にデバッグできます。また、失敗したOpenGL呼び出しも示します。

ただし、テクスチャとオフスクリーンバッファを検査する機能がありません。

3
heeen

ウィンドウタイトルの更新動的に便利です。

例(GLFW、C++ 11を使用):

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

Nsight は、NVidiaカードをお持ちの場合に適したデバッグツールです。

0
aedm