如果在调用glDeleteBuffers之前在同一缓冲区对象上执行多个glBindBuffers会导致内存泄漏吗?

时间:2015-10-02 20:41:59

标签: opengl

更新我刚发现我的问题可能与If you call glBufferData after already calling it on a buffer, is there a memory leak?重复了

希望我的问题仍然对某人有用,因为我提供了代码示例,而不仅仅是提及gl函数调用,就像在Q& A中那样。

我不理解glGenBuffers / glBindBuffer / glBufferDatagldeletebuffers之间的关系。

考虑绘制一系列线条(线条)。原始序列是在一定数量的帧上绘制的,但随后新的用户输入会增加行数。

我的第一个想法是在大小改变时重用glGenBuffers指定的缓冲区对象名称。但由于缓冲区大小需要更大,我不能按原样使用现有缓冲区。

注意:此时,我宁愿不假设一些“最大大小”,分配它,然后按我当前需要的大小进行子数据调用。

考虑基于此示例的代码: When should I call glDeleteBuffers()?

如果我在绘制第一帧之前在初始化函数中完成了这些行(代码可能无法编译 - 我关注调用序列,而不是要传递的确切参数 - 我实际上是在C#下工作Xamarin使用OpenTK访问OPENGL ES 2.0,但使用opengl在C ++中查找示例更容易:

GLuint VBO;

void init(int size, float* data) {
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
}

通过以下方式(或应用程序退出时)的许多帧发布:

void destroy() {
    glDeleteBuffers(1, &VBO);
}

但是现在我想要一个“re_init”函数来分配不同的大小,我到底需要做什么?

我可以重新分配一个新的VBO缓冲区名称:

void re_init(newSize, newData) {
    destroy();
    init(newSize, newData);
}

但这看起来有点矫枉过正。我能做的最低工作是什么?这比蛮力破坏/创造一个新的一个更有效吗?

似乎我可以使用任何一组调用,但我不知道结果是否会泄漏内存。我最终需要学习如何在我所处的环境中测试内存泄漏,但是现在我想让理论正确,希望我能编写既高效又无泄漏的代码。

这会泄漏内存吗?

void re_init(newSize, newData) {
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, newSize, newData, GL_STATIC_DRAW);
}

也就是说,我没有对旧缓冲区执行glDeleteBuffers,因为这样做会释放VBO缓冲区名称,而我正试图找出如何不这样做。

一个问题是,是否有办法重新使用VBO缓冲区名称,数据大小不同?

或者我最好还是坚持每次需要更改缓冲区大小时都要释放缓冲区 及其名称 的简单模型? (这就是glDeleteBuffers似乎所做的。)

2 个答案:

答案 0 :(得分:2)

glBufferData将替换缓冲区对象的内容 - 如spec/doc所示,“在创建新存储时,任何预先存在的数据存储都将被删除” - 所以这不会泄漏记忆。

为了提高效率,需要考虑很多因素,并且没有通用指南 - 我建议您在应用程序中进行配置文件,一旦您对数据有实际用例。

答案 1 :(得分:2)

这里有3个独立的实体:

  • 缓冲区名称。由于它是一个整数值很多人喜欢称之为" id"。但是如果你阅读官方的OpenGL文档,它总是被称为" name"。
  • 缓冲区对象。这是包含状态属性的对象,如当前大小,用法标志等。
  • 缓冲区商店。这是包含实际缓冲区内容的内存。

通过这些定义,我们可以描述每个调用正在做什么:

  • glGenBuffers()创建缓冲区名称。
  • glBindBuffer()在第一次绑定给定名称时创建一个缓冲区对象,并使其成为在缓冲区上运行的其他调用的当前缓冲区。
  • glBufferData()删除当前缓冲存储区(如果已有),并创建新的缓冲区存储区。
  • glBufferSubData()修改现有数据存储中的数据。
  • glDeleteBuffers()删除缓冲区名称,以及相关的缓冲区对象和缓冲区存储(如果存在)。

这意味着多次在同一缓冲区对象上调用glBufferData()完全没问题,并且不会导致任何内存泄漏。

上面列表中的一个细微之处是glGenBuffers()不会创建缓冲区对象。这只会在第一次绑定名称时发生。这对于缓冲区对象并不重要,但了解具有相同行为的其他类型的对象(如纹理)非常重要。