多くの場合、OpenGLは何も描画しないことで失敗したことを示します。変換マトリックススタックなどを調べることで、OpenGLプログラムをデバッグする方法を見つけようとしています。 OpenGLをデバッグする最良の方法は何ですか?コードが頂点が適切な場所にあるように見える場合、どのようにしてそれらを確認できますか?
直接的な答えはありません。それはすべてあなたが理解しようとしているものに依存します。 OpenGLは状態マシンであるため、必要な状態が設定されていないなどの理由で、期待どおりに動作しない場合があります。
一般に、glTrace/glIntercept(OpenGL呼び出しトレースを見る)、gDebugger(テクスチャ、シェーダー、OGL状態などを視覚化する)、および紙/鉛筆:)のようなツールを使用します。カメラをどのように設定し、どこで見ているか、何がクリップされているかなどを理解するのに役立つ場合があります。しかし、深さが間違っていると主張できる場合は、トレースを見ると役立ちます。 gDebuggerは、OpenGLアプリのプロファイリングと最適化に効果的に使用できるtheのみのツールでもあります。
このツールとは別に、ほとんどの場合、人が間違っているのは数学であり、ツールを使用して理解することはできません。 OpenGL.orgニュースグループにコード固有のコメントを投稿すると、失望することはありません。
GLIntercept が最善の策です。彼らのウェブページから:
Apitraceは、Valveの一部の人々からの比較的新しいツールですが、すばらしい機能です!試してみてください: https://github.com/apitrace/apitrace
OpenGLをデバッグする最良の方法は何ですか?
追加および外部ツールを考慮することなく(他の回答はすでに行っています)。
それから一般的な方法は glGetError()
を広範囲に呼び出すことです。ただし、より良い代替手段は デバッグ出力 ( KHR_debug 、 ARB_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()
を呼び出すことができます。エラーが発生した場合は、検出された正確なファイルと行を通知します。
疑わしいコードの各行の後にglGetError
を使用してチェックできることがわかりましたが、それを実行すると、コードはあまりきれいに見えませんが、動作します。
GDebuggerは優れた無料のツールですが、サポートされなくなりました。ただし、AMDは開発を開始し、このデバッガーは現在、 CodeXL として知られています。 NVidiaとAMD GPUの両方で、スタンドアロンアプリケーションまたはVisual Studioプラグインの両方として利用できます。ネイティブC++アプリケーション、またはOpenGLバインディングを使用するJava/Pythonアプリケーションの両方で動作します。それはツールの地獄です。
Macを使用している場合は、組み込みのOpenGLデバッガーも優れています。バッファ、状態を検査し、パフォーマンスの問題を見つけるのに役立ちます。
無料のglslDevilもあります。 http://www.vis.uni-stuttgart.de/glsldevil/
Glslシェーダーを広範囲にデバッグできます。また、失敗したOpenGL呼び出しも示します。
ただし、テクスチャとオフスクリーンバッファを検査する機能がありません。
ウィンドウタイトルの更新動的に便利です。
例(GLFW、C++ 11を使用):
glfwSetWindowTitle(window, ("Now Time is " + to_string(glfwGetTime())).c_str());
Nsight は、NVidiaカードをお持ちの場合に適したデバッグツールです。