OpenGL笔记<5> shader 调试信息获取 Debug
我们今天来讲调试信息,这个东西讲起来会比较无聊,因为都是一些函数调用,没啥可讲的,函数就是那样用的,不过其效果挺好玩的,同时在程序设计中也是很必要的,所以还是来写一下,不过,就是因为知识比较固定且简单,所以我们 一篇就覆盖三节的内容吧:
1. 获取当前活动的顶点属性和对应索引
2.获取当前活动的uniform量和对应索引
2.Debug
Getting Ready
我们以上一节的旋转三角形的例子来讲这一篇。
当我们的shader program编译连接完成之后,所有的量都已经分配了自己的索引,这时候我们可以查看其信息。
我们默认连接好的shader program的句柄为programHandle
Getting a list of active vertex input attributes and locations
我们需要获取所有顶点属性信息,首先要知道有多少个顶点属性
glGetProgramInterfaceiv用来获取program中的一些状态信息。
它有四个参数:
第一个参数为:program 句柄,确定是哪一个程序中的状态信息
第二个参数为:我们要查询的是程序的哪一类数据资源
第三个参数为:我们要查询的量
第四个参数为:存储获取的信息
glGetProgramInterfaceiv(programHandle, GL_PROGRAM_INPUT, GL_ACTIVE_RESOURCES, &numAttribs);
即为,我们要获取programHandle这个着色器程序中有关程序输入(即为顶点属性)的数据信息,将当前处于活动状态的上述资源的数量( GL_ACTIVE_RESOURCES)存储到numAttribs中
接下来,我们需要循环获取顶点属性(数据资源,resource)信息
假如我们的numAttribs的值为6,我们对于每一都如此做:
glGetProgramResourceiv获取单个数据资源的状态信息
它一共有8个参数:
para1:shader program 句柄用于指定处理的是哪一个程序
para2:同上面那个函数的第二个参数,数据资源的类型
para3:查询的是第几个数据资源(0 ~ numAttribs-1)
para5:要查询数据资源的哪些信息,参数类型为枚举数组地址,用于记录要查询的所有查询信息
para4:para5中所传入的数组的size
para6:para8的数组中一个数据资源包含多少个信息元素
para7:第七个参数是一个指向整数的指针,该整数将接收被写入的数据组有多少组,如果para8为二维信息,即有很多组,每组数据为一维,那么需要该参数返回para8中有多少组,以便解析para8中的数据,而我们 这里的para8指定接收资源数据的一组信息,所以,此参数无效,我们可用nullptr来跳过该参数。
para8:用于接收系统返回的数据信息
glGetProgramResourceiv(programHandle, GL_PROGRAM_INPUT, i, 3, properties, 3, nullptr, results);
前两个就不用说了,我们要获取第 i 个数据资源(顶点属性量)的信息,其中一组信息有三种,它们存储在properties数组中:
GLenum properties[]{ GL_NAME_LENGTH, GL_TYPE, GL_LOCATION }; //数据资源的名字的长度,数据资源的数据类型,数据资源的索引值
我们需要将系统传出的数据每3个一组存入results中,返回。由于我们的results只记录一组返回信息,所以数据无需解析分组,所以para7为nullptr,如果为多组的二维信息,我们需要指定一个整型来接受返回数据。
如:glGetProgramResourceiv(programHandle, GL_PROGRAM_INPUT, i, 3, properties, 3, num, results);
num是一个GLint,那么意思是,results中存储着num组数据,每组数据有3个,如同二维数组传递参数一样,低维度的参数必须给定,也就是num前面的3,对吧~
最后,我们通过glGetProgramResourceiv获取数据资源的名字。
我们已经通过上面那个函数获取到了名字的长度,所以,我们创建一个缓冲区来接受字符串。
GLint nameBufSize = results[] + ;
GLchar* name = new char[nameBufSize];
glGetProgramResourceName(programHandle, GL_PROGRAM_INPUT, i, nameBufSize, nullptr, name);
至此,我们获取到了顶点属性量的名字
我们的名字以及索引都得到了,还需要将GL_TYPE获取到的类型枚举值换成字符串
const GLchar* getTypeString(GLenum type)
{
// There are many more types than are covered here, but
// these are the most common in these examples.
switch (type) {
case GL_FLOAT:
return "float";
case GL_FLOAT_VEC2:
return "vec2";
case GL_FLOAT_VEC3:
return "vec3";
case GL_FLOAT_VEC4:
return "vec4";
case GL_DOUBLE:
return "double";
case GL_INT:
return "int";
case GL_UNSIGNED_INT:
return "unsigned int";
case GL_BOOL:
return "bool";
case GL_FLOAT_MAT2:
return "mat2";
case GL_FLOAT_MAT3:
return "mat3";
case GL_FLOAT_MAT4:
return "mat4";
default:
return "?";
}
}
代码如下:
void getVertexAttribList(GLint programHandle)
{
GLint numAttribs;
glGetProgramInterfaceiv(programHandle, GL_PROGRAM_INPUT, GL_ACTIVE_RESOURCES, &numAttribs); GLenum properties[]{ GL_NAME_LENGTH,GL_TYPE,GL_LOCATION };
cout << "Active attributes:" << endl;
for (int i = ; i < numAttribs; ++i)
{
GLint results[];
glGetProgramResourceiv(programHandle, GL_PROGRAM_INPUT, i, , properties, , nullptr, results); GLint nameBufSize = results[] + ;
GLchar* name = new char[nameBufSize];
glGetProgramResourceName(programHandle, GL_PROGRAM_INPUT, i, nameBufSize, nullptr, name);
cout << "location:" << results[] << " " << name << "(" << getTypeString(results[]) << ")" << endl;
delete[] name;
}
}
在main主程序中的着色器程序连接完成之后调用此函数即可得到如下测试结果:
没问题,嘻嘻
Getting a list of active uniform variables
void getUniformList(GLint programHandle)
{
GLint numUniforms = ;
glGetProgramInterfaceiv(programHandle, GL_UNIFORM, GL_ACTIVE_RESOURCES, &numUniforms); GLenum properties[] = { GL_NAME_LENGTH, GL_TYPE, GL_LOCATION, GL_BLOCK_INDEX }; printf("Active uniforms:\n");
for (int i = ; i < numUniforms; ++i) {
GLint results[];
glGetProgramResourceiv(programHandle, GL_UNIFORM, i, , properties, , NULL, results); if (results[] != -) continue; // Skip uniforms in blocks
GLint nameBufSize = results[] + ;
char * name = new char[nameBufSize];
glGetProgramResourceName(programHandle, GL_UNIFORM, i, nameBufSize, NULL, name);
cout << "location:" << results[] << " " << name << "(" << getTypeString(results[]) << ")" << endl;
delete[] name;
}
}
唯一不同的一点是properties的第四个枚举量
它记录了当前查询的uniform量所在的uniform block,如果该uniform量不属于任何block,那么该元素对应的值为-1
这里,我们只查询单独的uniform量,所以当其GL_BLOCK_INDEX对应的返回值为-1的时候是我们所要的,反之,我们跳过。
Debug
在之前,我们获取调试信息的传统方法是调用glGetError。但是这是一种非常繁琐的方法,其繁琐程度就不再赘述了。
从OpenGL 4.3开始,我们现在支持更现代的调试方法。我们可以整一个调试回调函数,该函数将在发生错误或者生成其他警告提示性消息时执行。
不仅如此,我们还可以发送自己的自定义消息,由同一个回调处理,我们可以使用各种条件过滤消息。
注:context有翻译为上下文,有翻译为环境,个人比较倾向于环境一说,下文不做翻译
使用debug context 创建OpenGL程序。 虽然获取debug context 并非绝对必要,但我们可能无法获得与使用debug context 时相同的消息。
要在启用调试的情况下使用GLFW创建OpenGL context,在创建窗口之前要使用以下函数调用。
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
默认情况下,OpenGL debug context 将启用调试消息。但是,如果需要显式启用调试消息,请使用以下调用。
glEnable(GL_DEBUG_OUTPUT);
我们采用如下步骤进行:
1.创建回调函数以接收调试消息。
该函数必须符合OpenGL文档中描述的特定原型。 我们采用如下方式:
void debugCallback(GLenum source, GLenum type, GLuint id,
GLenum severity, GLsizei length,
const GLchar * message, void * param) {
// Convert GLenum parameters to strings
printf("%s:%s[%s](%d): %s\n", sourceStr, typeStr,
severityStr, id, message);
}
2.使用glDebugMessageCallback向OpenGL注册我们的回调:
glDebugMessageCallback(debugCallback,NULL);
3.启用所有消息,所有来源,所有级别和所有ID:
glDebugMessageControl(GL_DONT_CARE,GL_DONT_CARE,
GL_DONT_CARE,0,NULL,GL_TRUE);
我们来解释一下上述的一些内容:
回调函数debugCallback有几个参数,其中最重要的是调试消息本身(第六个参数,message)。
对于此示例,我们只是将消息打印到标准输出,但我们可以将其发送到日志文件或其他目的地.
debugCallback的前四个参数描述消息的来源,类型,ID号和严重性。
id号是特定于消息的无符号整数。 下表中描述了source,type和Severity参数的可能值。
Source |
Generated By |
GL_DEBUG_SOURCE_API |
Calls to the OpenGL API |
GL_DEBUG_SOURCE_WINDOW_SYSTEM |
Calls to a window system API |
GL_DEBUG_SOURCE_THIRD_PARTY |
An application associated with OpenGL |
GL_DEBUG_SOURCE_APPLICATION |
This application itself. |
GL_DEBUG_SOURCE_OTHER |
Some other source |
Type |
Description |
GL_DEBUG_TYPE_ERROR |
An error from the OpenGL API. |
GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR |
Behavior that has been deprecated |
GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR |
Undefined behaviour |
GL_DEBUG_TYPE_PORTABILITIY |
Some functionality is not portable. |
GL_DEBUG_TYPE_PERFORMANCE |
Possible performance issues |
GL_DEBUG_TYPE_MARKER |
An annotation |
GL_DEBUG_TYPE_PUSH_GROUP |
Messages related to debug group push. |
GL_DEBUG_TYPE_POP_GROUP |
Messages related to debug group pop. |
GL_DEBUG_TYPE_OTHER |
Other messages |
Severity | Meaning |
GL_DEBUG_SEVERITY_HIGH |
Errors or dangerous behaviour |
GL_DEBUG_SEVERITY_MEDIUM |
Major performance warnings, other warnings or use of deprecated functionality. |
GL_DEBUG_SEVERITY_LOW |
Redundant state changes, unimportant undefined behaviour. |
GL_DEBUG_SEVERITY_NOTIFICATION |
A notification, not an error or performance issue. |
length参数是消息字符串的长度,不包括空终止符。 最后一个参数param是用户定义的指针。 我们可以使用它指向一些可能对回调函数有帮助的自定义对象。 例如,如果我们将消息记录到文件中,则可能指向包含文件I / O功能的对象。可以使用glDebugMessageCallback的第二个参数设置此参数。
在debugCallback中,我们将每个GLenum参数转换为字符串,此篇第一节中,我们写过getTypeString这个函数。
然后,我们将所有信息打印到标准输出。
对glDebugMessageCallback的调用使用OpenGL调试系统注册我们的回调函数。
第一个参数是指向我们的回调函数的指针,第二个参数(本例中为NULL)可以是指向我们想要传递给回调的任何对象的指针。
每次调用debugCallback时,此指针都作为最后一个参数传递。
最后,对glDebugMessageControl的调用确定了我们的消息过滤器。
此功能可用于有选择地打开或关闭消息源,类型,ID或严重性的任何组合。 在这个例子中,我们打开了一切。
一些扩展内容,可能不会用到,可跳过
OpenGL还为命名调试组的堆栈提供支持。 基本上这意味着我们可以记住堆栈上的所有调试消息过滤器设置,并在稍后进行一些更改后返回它们。 这可能很有用,例如,如果有一些代码段我们需要过滤某些类型的消息,而其他段我们需要一组不同的消息。涉及的函数是glPushDebugGroup和glPopDebugGroup。 对glPushDebugGroup的调用会生成类型为GL_DEBUG_TYPE_PUSH_GROUP的调试消息,并在堆栈上保留调试过滤器的当前状态。 然后我们可以使用glDebugMessageControl更改我们的过滤器,然后使用glPopDebugGroup返回到原始状态。 类似地,函数glPopDebugGroup生成类型为GL_DEBUG_TYPE_POP_GROUP的调试消息。
第三部分主要是用于我们下一篇的类所用的,暂时没有相关的测试
感觉像是在写说明书,没有办法,这种章节的特点就是这样,但又比较重要~
感谢您的阅读,生活愉快~
OpenGL笔记<5> shader 调试信息获取 Debug的更多相关文章
- Keil ARM-CM3 printf输出调试信息到Debug (printf) Viewer
参考资料:http://www.keil.com/support/man/docs/jlink/jlink_trace_itm_viewer.htm 1.Target Options -> De ...
- OpenGL ES 2.0 Shader 调试新思路(一): 改变提问方式
OpenGL ES 2.0 Shader 调试新思路(一): 改变提问方式 --是什么(答案是具体值) VS 是不是(答案是布尔值) 目录 背景介绍 问题描述 Codea 是 iPad 上的一款很方便 ...
- OpenGL ES 2.0 Shader 调试新思路(二): 做一个可用的原型
OpenGL ES 2.0 Shader 调试新思路(二): 做一个可用的原型 目录 背景介绍 请参考前文OpenGL ES 2.0 Shader 调试新思路(一): 改变提问方式 优化 ledCha ...
- C# Debug和Trace:输出调试信息
在 C# 语言中允许在程序运行时输出程序的调试信息,类似于使用 Console.WriteLine 的方式向控制台输出信息.所谓调试信息是程序员在程序运行时需要获取的程序运行的过程,以便程序员更好地解 ...
- C#报错:创建调试信息文件 ……obj\Debug\model.pdb: 拒绝访问
错误:创建调试信息文件“.......\obj\Debug\model.pdb”时发生错误 --“......\obj\Debug\model.pdb: 拒绝访问. 解决办法如下: 删除该项目下的 b ...
- C# trace debug TraceListener调试信息详解
在C#编程中,可能要碰到把调试信息输出的问题,我们可以自己把信息显示在某个控件上,但是MS自己提供了一套机制帮助我们输出一些调试信息,这些信息有助于我们判断程序的走向,不用自己再去额外写调试代码了. ...
- INV 调试: 如何获取库存物料事务处理调试信息
1. 按如下方式设置系统配置文件值: 系统配置文件值 地点/用户/应用/职责层配置文件值 --汇总 FND: 启用调试日志 是 FND:调试日志层级 陈述 INV: 调试跟踪: 是 IN ...
- [QT_QML]qml假如调试信息 qDebug console.debug
WinSys: win7 Qt Version: 5.8.0 使用Console调试 console.log 打印日志信息console.debug 打印调试信息console.info 打印普通信息 ...
- 【转】 C# DEBUG 调试信息打印及输出详解
[转] C# DEBUG 调试信息打印及输出详解 1.debug只在[debug模式下才执行](运行按钮后面的下拉框可选) 2.debug提供了许多调试指令,如断言 System.D ...
随机推荐
- springboot中使用Scheduled定时任务
一:在程序入口类中添加注解@EnableScheduling @SpringBootApplication @EnableScheduling public class DemoApplication ...
- 20155330 2016-2017-2 《Java程序设计》第七周学习总结
20155330 2016-2017-2 <Java程序设计>第七周学习总结 教材学习内容总结 学习目标 了解Lambda语法 了解方法引用 了解Fucntional与Stream API ...
- Hadoop2.6.0在CentOS 7中的集群搭建
我这边给出我的集群环境是由一台主节点master和三台从节点slave组成: master 192.168.1.2 slave1 192.168.1.3 slave2 ...
- 未来人类T5 安装win10,ubuntu双系统
1.首先确保win10已经安装,u盘中已刻录好系统,下载好英伟达最新驱动保存在u盘中,压缩100g的磁盘空间给ubuntu. 2.设置双显卡模式,重启时按F7选择进入u盘启动. 3.进入安装界面,选择 ...
- Hibernate5笔记9--Hibernate注解式开发
Hibernate注解式开发: (1)注解式开发的注意点: Hibernate中使用注解,主要是为了替代映射文件,完成“类到表,属性到字段”的映射. JPA提供了一套功能强大的注解.Hibernat ...
- 关于new Handler()与new Handler(Looper.getMainLooper())区别
如果你不带参数的实例化:Handler handler=new Handler();那么这个会默认用当前线程的Looper对象. 一般而言,如果你的Handler是要用来刷新UI的,那么就需要在主线程 ...
- 推荐一本springBoot学习书籍---深入浅出springBoot2.x
花了几周时间读完了这本书,确实是一本特别详细全面的书,而且不单单只是springBoot, 书中还介绍了许多工作中常用的技术与springBoot的整合使用,当然,也有一些小bug, 因为在代码实践过 ...
- XSS练习小游戏和答案参考
源码:https://files.cnblogs.com/files/Eleven-Liu/xss%E7%BB%83%E4%B9%A0%E5%B0%8F%E6%B8%B8%E6%88%8F.zip 感 ...
- CentOS_5.5_安装GCC编译LiME
1 概述 近期遇到个使用CentOS 5.5的系统,生产环境没有GCC.GDB.要对这台机器抓取关键内存回去用volatility分析. 思路1:使用工具Dump某个进程的内存.使用cat /proc ...
- JSP中page,request,session,application四个域对象区别
page page指当前页面.只在一个jsp页面里有效 . page里的变量没法从index.jsp传递到test.jsp,只要页面跳转了,它们就不见了. pageContext 如果把变量放到pag ...