openGL环境中, 应该避免过于频繁的申请和删除各种缓冲区对象

首先大致描述下我们软件目前的架构设计. 合理与否暂且不论, 毕竟都是半路接手, 重构的代价太大, 暂时只能凑合着去堆砌新功能了.

窗口中需要绘制多个物体, 但是, 会有很多事件导致物体的结构发生改变. 此时, 软件中会删除现有物体对象,并生成新的物体对象.

每个物体对象, 有属于自己的VAO, VBO和EBO等. 构造函数中使用glGenVertexArrays和glGenBuffers来申请这些opengl缓冲区对象, 删除时会在析构函数中使用glDelete...来删除这些缓冲区对象.

以上为背景. 

 

在某个新功能的开发过程中, 软件频频的发生死机.  报错的是nvoglv64.dll. 这个错误很早以前就遇到过很多次了, 知道是跟openGL和Nvidia显卡有关.

这次的死机情况伴随着两个现象:

1. 以前遇到这个错误大都是跟绘制函数有关, 且基本都是往VBO等缓冲区对象中装载的数据有问题. 但这次将所有绘制相关函数都注释掉后, 依旧没用. 接着再注释掉更多代码的时候, 终于定位在了其中一个物体对象的构造函数里.  这个物体比较特殊, 会连续申请4个vao, 28个vbo. 此时代码已经注释的差不多了, 基本只剩下构造和析构里的申请和释放的动作. 我们发现, 如果这个物体不申请那么多vbo, 比如只申请8个的话, 就不再死机. 再申请更多的话, 就会挂掉.

2. 不使用该新功能的时候, (基本)不会死机. 且系统中更新场景中物体的速度较慢. 但这个新功能其实就是在不断的高速自动更新场景中物体. 换言之, 这个新功能会伴随着这些缓冲区对象的频繁申请和删除.

 

思量一阵后, 就猜测会不会是由于openGL的这些缓冲区对象随着物体对象的不断构造和析构而不断的申请和删除, (或许是调用glDelete...时实际上并没有删除成功?), 进而导致耗光了这些缓冲区对象? 

针对这一猜测, 就简单的做了个测试, 就是把上面那个物体对象中的vao和vbo都改为全局变量, 这样就不必在删除一个物体时把这些vao和vbo也删除掉, 同样也不必在每生成一个新物体的时候都去重新申请一次. 果然, 改了之后, 不再出现死机.

 

最后, 附上最终的解决方案. 这里略略借鉴了下线程池的设计思路吧. 就是把软件中用到的所有opengl缓冲区对象"放在一个池子中"进行统一管理.  就单单以VBO为例, 其他类似. 

软件启动之初(或者在第一次有VBO需求时), 一次性申请N个VBO. 然后使用一个vector保存这些vbo, 记为缓冲(区对象)池. 再使用一个缓冲队列保存这些vbo在vector中的ID, 即索引号. 该队列的作用即保存所有处于未使用状态的VBO在缓冲池中的ID. 

当一个(新生成的)物体发出vbo申请时, 如果缓冲队列不为空, 则从缓冲队列头部弹出一个vbo对象的ID, 并将对应的vbo返回给请求者. 如果缓冲队列为空, 代表之前申请的VBO都在使用中. 则需要再申请N个VBO, 并更新缓冲池和缓冲队列. 然后弹出新申请的vbo返回给请求者. 

当一个物体被删除, 它所占用的vbo也需要被释放, 此时将他所占用的vbo的ID重新加到缓冲队列的尾部即可.

最后, 在软件退出时, 别忘了删除缓冲池中的所有缓冲区对象.

上一篇:opengl中开启深度测试后白屏的问题


下一篇:从零开始的openGL--cs游戏(9)CubeMeshComponent,一个正方形物体------------第一个页面完成