这是在 Windows 10 上使用 C++/GLEW/GLFW 和 Visual Studio 2019 的方法,只是相关部分:
/** Necessary includes */
#include <map>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
/** Debug callback prototype */
void GLAPIENTRY GLDebugMessageCallback(GLenum Source,
GLenum Type,
GLuint Id,
GLenum Severity,
GLsizei Length,
const GLchar* Message,
const void* UserParam);
/** Create the window and set the OpenGL context */
int main(void)
{
if (glfwInit() != GLFW_TRUE)
{
printf("Unable to initialize GLFW\n");
return EXIT_FAILURE;
}
/** Set the OpenGL Debug Context hint */
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
GLFWwindow* Window = glfwCreateWindow(800, 600, "OpenGL", nullptr, nullptr);
if (!Window)
{
glfwTerminate();
printf("Unable to create a GLFW window\n");
return EXIT_FAILURE;
}
glfwMakeContextCurrent(Window);
if (glewInit() != GLEW_OK)
{
printf("Unable to initialize GLEW\n");
return EXIT_FAILURE;
}
/** Check whether debug context is enabled and set the debug callback */
GLint ContextFlags;
glGetIntegerv(GL_CONTEXT_FLAGS, &ContextFlags);
if (ContextFlags & GL_CONTEXT_FLAG_DEBUG_BIT)
{
printf("OpenGL : Debug Context Is Enabled");
glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallback(GLDebugMessageCallback, 0);
}
while (!glfwWindowShouldClose(Window))
{
glfwPollEvents();
// Edit here...
glfwSwapBuffers(Window);
}
glfwDestroyWindow(Window);
glfwTerminate();
return EXIT_SUCCESS;
}
/** Debug callback definition */
void GLAPIENTRY GLDebugMessageCallback(GLenum Source,
GLenum Type,
GLuint Id,
GLenum Severity,
GLsizei Length,
const GLchar* Message,
const void* UserParam)
{
static std::map<GLenum, const GLchar*> Sources =
{
{GL_DEBUG_SOURCE_API, "API"},
{GL_DEBUG_SOURCE_WINDOW_SYSTEM, "WINDOW_SYSTEM"},
{GL_DEBUG_SOURCE_SHADER_COMPILER, "SHADER_COMPILER"},
{GL_DEBUG_SOURCE_THIRD_PARTY, "THIRD_PARTY"},
{GL_DEBUG_SOURCE_APPLICATION, "APPLICATION"},
{GL_DEBUG_SOURCE_OTHER, "OTHER"}
};
static std::map<GLenum, const GLchar*> Severities =
{
{GL_DEBUG_SEVERITY_HIGH, "HIGH"},
{GL_DEBUG_SEVERITY_MEDIUM, "MEDIUM"},
{GL_DEBUG_SEVERITY_LOW, "LOW"},
{GL_DEBUG_SEVERITY_NOTIFICATION, "NOTIFICATION"}
};
static std::map<GLenum, const GLchar*> Types =
{
{GL_DEBUG_TYPE_ERROR, "ERROR"},
{GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, "DEPRECATED_BEHAVIOR"},
{GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, "UNDEFINED_BEHAVIOR"},
{GL_DEBUG_TYPE_PORTABILITY, "PORTABILITY"},
{GL_DEBUG_TYPE_PERFORMANCE, "PERFORMANCE"},
{GL_DEBUG_TYPE_MARKER, "MARKER"},
{GL_DEBUG_TYPE_PUSH_GROUP, "PUSH_GROUP"},
{GL_DEBUG_TYPE_POP_GROUP, "POP_GROUP"},
{GL_DEBUG_TYPE_OTHER, "OTHER"}
};
printf("[OpenGL %s] - SEVERITY: %s, SOURCE: %s, ID: %d: %s\n", Types[Type], Severities[Severity], Sources[Source], Id, Message);
}
样本输出
[OpenGL ERROR] - SEVERITY: HIGH, SOURCE: API, ID: 1282: GL_INVALID_OPERATION error generated. Function glColor4fv is deprecated and not available in preview contexts.
[OpenGL ERROR] - SEVERITY: HIGH, SOURCE: API, ID: 1282: GL_INVALID_OPERATION error generated. Array object is not active.
[OpenGL OTHER] - SEVERITY: NOTIFICATION, SOURCE: API, ID: 131185: Buffer detailed info: Buffer object 1 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_DYNAMIC_DRAW) will use SYSTEM HEAP memory as the source for buffer object operations.
[OpenGL OTHER] - SEVERITY: NOTIFICATION, SOURCE: API, ID: 131185: Buffer detailed info: Buffer object 1 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_DYNAMIC_DRAW) has been mapped WRITE_ONLY in SYSTEM HEAP memory (fast).
经测试
OpenGL 4.6
GLSL 4.60 英伟达
渲染器:采用 Max-Q 设计/PCIe/SSE2 的 GeForce RTX 2070
供应商:NVIDIA Corporation
Printing to the Visual Studio Output window
#include <windows.h> // For OutputDebugStringA
将调试回调定义末尾的printf 替换为以下内容:
char ErrorString[512];
sprintf_s(ErrorString, "[OpenGL %s] - SEVERITY: %s, SOURCE: %s, ID: %d: %s\n", Types[Type], Severities[Severity], Sources[Source], Id, Message);
OutputDebugStringA(ErrorString);
关于调试上下文的通知
简而言之,当在调试上下文模式下创建 OpenGL 上下文时,会在应用程序、驱动程序和 GPU 之间的路径中激活附加层。
这些附加层执行错误检查、参数分析等,并通过调试消息回调将其作为格式正确的消息报告回来。
启用 OpenGL 调试上下文是特定于平台的,因此 GLFW 在这个意义上很有帮助,因为它提供了一种通过 glfwWindowHint 配置 OpenGL 上下文的方法,应该在创建 GLFW 窗口之前进行配置。
来自 OpenGL Wiki - Enabling Debug Output:
除非启用调试输出,否则不会生成、检索或记录任何消息。它是通过使用带有 GL_DEBUG_OUTPUT 枚举器的 glEnable 来启用的。
在调试上下文中,调试输出开始启用。在非调试上下文中,即使启用了调试输出,OpenGL 实现也可能不会生成消息。
我验证了在 Windows 10 上,实际上只是通过启用调试输出和设置回调来生成一些输出,而没有激活调试上下文。
docs.GL 和 OpenGL Wiki 上的 glDebugMessageCallback 的详细信息以及 OpenGL Superbible 第 7 版。