OpenGL程序调试输出

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zjz520yy/article/details/83047042

前言:调试输出是OpenGL4.3版本中增加的一种用于调试的扩展工具。它不仅比glGetError接口提供更多的错误信息,而且还允许通过debugger去定位错误源。

创建调试环境:环境的创建是与平台相关的任务,一般由各种封装库提供接口进行创建。常见的创建方式如下:
1.GLFW创建方式:需要在创建OpenGL环境之前进行调试环境的创建。创建代码如下所示:

glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);

2.WGL创建方式:需要在创建OpenGL环境之后进行调试环境的创建。创建代码如下:

HGLRC CreateDebugContext(HDC hDC, HGLRC hShareContext, int major, int minor)
{
	const int attriblist[] = 
	{
		// 环境的主版本
		WGL_CONTEXT_MAJOR_VERSION_ARB, major,
		// 环境的次版本
		WGL_CONTEXT_MINOR_VERSION_ARB, mior,
		// 总是选择核心优化
		WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
		// 打开调试环境
		WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
		0
	};
	
	return wglCreateContextAttribsARB(hDC, hShareContext, attriblist);
}

3.GLX创建方式:无需先创建OpenGL环境就可以进行调试环境创建。创建代码如下:

GLXContext CreateDebugContext(Display* dpy, GLXFBConfig* config, GLXContext shareContext, int major, int minor)
{
	const int attriblist[] = 
	{
		// 环境的主版本
		GLX_CONTEXT_MAJOR_VERSION_ARB, major,
		// 环境的次版本
		GLX_CONTEXT_MINOR_VERSION_ARB, mior,
		// 总是选择核心优化
		GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
		// 打开调试环境
		GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB,
		0
	};
	
	return glXCreateContextAttribsARB(dpy, config, shareContext, attriblist);
}

检查调试环境:要检查是否成功地初始化了调试环境,我们可以对OpenGL进行查询。检查代码如下所示:

GLint flags; 
glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
{
    // TODO 初始化调试输出成功
}

开关调试消息:传递调试消息默认是启动的,当然我们也可以禁止。通常使用GL_DEBUG_OUTPUT或者GL_DEBUG_OUTPUT_SYNCHRONOUS来调用glEnable接口进行启用,或者调用glDisable接口来进行禁用。

传递调试消息:调试环境存在两种方式将获取的调试消息传递给开发者。第一种方式就是设置回调函数。第二种方式就是通过远程渲染方式利用调试环境获取调试消息日志。
常用接口如下:
1.void glDebugMessageCallback(DEBUGPROC callback, void* userParam):设置一个新的调试消息回调函数callback给调试环境。当调试消息生成的时候就会触发这个回调函数,并将调试消息以及用户自定义参数userParam传递给回调函数callback。
其中DEBUGPROC声明如下所示:
void APIENTRY DEBUGPROC(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, void *userParam)
.source表示消息来源。通常是GL_DEBUG_SOURCE_API(OpenGL API),GL_DEBUG_SOURCE_WINDOW_SYSTEM(窗口系统),GL_DEBUG_SOURCE_SHADER_COMPILER(着色器编译器),GL_DEBUG_SOURCE_THIRD_PARTY(第三方库),GL_DEBUG_SOURCE_APPLICATION(应用程序),GL_DEBUG_SOURCE_OTHER(其他)当中的一种。
.type表示消息类型。通常是GL_DEBUG_TYPE_ERROR(错误生成),GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR(过时功能),GL_DEBUG_TYPE_UNSINGNED_BEHAVIOR(未定义功能),GL_DEBUG_TYPE_PERFORMANCE(性能不优),GL_DEBUG_TYPE_PORTABILITY(不能移植),GL_DEBUG_TYPE_MARKER(注解),GL_DEBUG_TYPE_PUSH_GROUP(调用glPushDebugGroup),GL_DEBUG_TYPE_POP_GROUP(调用glPopDebugGroup),GL_DEBUG_TYPE_OTHER(其他)当中的一种。
.id表示消息标志。
.severity表示消息等级。通常是GL_DEBUG_SEVERITY_HIGH(致命消息。如:OpneGL错误,着色器编译失败等),GL_DEBUG_SEVERITY_MEDIUM(不致命消息。如:移植性能警告),GL_DEBUG_SEVERITY_LOW(没危害消息。如:冗余的状态切换),GL_DEBUG_SEVERITY_NOTIFICATION(普通通知消息)当中的一种。
.message表示调试消息。
.userParam表示用户自定义参数。与设置回调时传入的自定义参数相关联。

有了这一大堆的数据,我们可以创建一个非常有用的错误打印工具。代码如下所示:

void APIENTRY glDebugOutput(GLenum source, 
                            GLenum type, 
                            GLuint id, 
                            GLenum severity, 
                            GLsizei length, 
                            const GLchar *message, 
                            void *userParam)
{
    // 忽略一些不重要的错误/警告代码
    if(id == 131169 || id == 131185 || id == 131218 || id == 131204) return; 

    std::cout << "---------------" << std::endl;
    std::cout << "Debug message (" << id << "): " <<  message << std::endl;

    switch (source)
    {
        case GL_DEBUG_SOURCE_API:             std::cout << "Source: API"; break;
        case GL_DEBUG_SOURCE_WINDOW_SYSTEM:   std::cout << "Source: Window System"; break;
        case GL_DEBUG_SOURCE_SHADER_COMPILER: std::cout << "Source: Shader Compiler"; break;
        case GL_DEBUG_SOURCE_THIRD_PARTY:     std::cout << "Source: Third Party"; break;
        case GL_DEBUG_SOURCE_APPLICATION:     std::cout << "Source: Application"; break;
        case GL_DEBUG_SOURCE_OTHER:           std::cout << "Source: Other"; break;
    } std::cout << std::endl;

    switch (type)
    {
        case GL_DEBUG_TYPE_ERROR:               std::cout << "Type: Error"; break;
        case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: std::cout << "Type: Deprecated Behaviour"; break;
        case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:  std::cout << "Type: Undefined Behaviour"; break; 
        case GL_DEBUG_TYPE_PORTABILITY:         std::cout << "Type: Portability"; break;
        case GL_DEBUG_TYPE_PERFORMANCE:         std::cout << "Type: Performance"; break;
        case GL_DEBUG_TYPE_MARKER:              std::cout << "Type: Marker"; break;
        case GL_DEBUG_TYPE_PUSH_GROUP:          std::cout << "Type: Push Group"; break;
        case GL_DEBUG_TYPE_POP_GROUP:           std::cout << "Type: Pop Group"; break;
        case GL_DEBUG_TYPE_OTHER:               std::cout << "Type: Other"; break;
    } std::cout << std::endl;

    switch (severity)
    {
        case GL_DEBUG_SEVERITY_HIGH:         std::cout << "Severity: high"; break;
        case GL_DEBUG_SEVERITY_MEDIUM:       std::cout << "Severity: medium"; break;
        case GL_DEBUG_SEVERITY_LOW:          std::cout << "Severity: low"; break;
        case GL_DEBUG_SEVERITY_NOTIFICATION: std::cout << "Severity: notification"; break;
    } std::cout << std::endl;
    std::cout << std::endl;
}

过滤调试消息:可以潜在地过滤出需要的输出消息。使用接口如下所示:
void APIENTRY glDebugMessageControl(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint * ids, GLboolean enabled)
.source表示消息来源。
.type表示消息类型。
.severity表示消息等级。

猜你喜欢

转载自blog.csdn.net/zjz520yy/article/details/83047042