首页 文章

glBufferStorage和glBufferData有什么区别?

提问于
浏览
12

glBufferStorage为当前绑定到目标的缓冲区对象创建新的不可变数据存储 . 数据存储的大小由大小指定 . 如果初始数据可用,则其地址可以以数据形式提供 . 否则,要创建未初始化的数据存储,数据应为NULL .

不可改变意味着我不能改变它吗?但随后“未初始化的数据”将毫无意义 .

但它并非真正不可变,因为我们可以指定 GL_DYNAMIC_STORAGE_BIT

那么glBufferStorage和glBufferData有什么区别?

2 回答

  • 15

    你知道,这是 glTexStorage* (...) 背后的原理 . 实际上,您与API签订 Contract ,该 Contract 规定您永远不会被允许更改对象的某些属性,并且作为交换,这将赋予对象不可变状态,并允许您执行通常无法使用它的操作 .

    纹理视图是一个有趣的例子,其中不可变纹理的内部图像数据可以在多个纹理对象之间共享,甚至可以重新解释其格式/维度(例如,可以共享和使用1个2D数组纹理切片,就好像它是普通的2D纹理) .

    对于顶点缓冲区,不可变存储会打开一类性能优化(例如,持久映射内存),如果您可以随时更改缓冲区的大小,则无法实现 . 您创建一个永远不会更改其大小的缓冲区,但您仍然可以使用 glBufferSubData* (...) 命令随时向其发送新数据,或者在内存映射时写入缓冲区 .

    使用 glBufferData (...) ,您可以在同一对象上多次调用该命令,它将孤立旧内存并分配新存储 . 使用 glBufferStorage (...) 时,缓冲区的大小设置为对象的生命周期(不可变),并且一旦分配不可变,再次调用 glBufferStorage (...) 是错误( GL_INVALID_OPERATION ) .

    简而言之,数据存储(存储特性)是不可变的,而不是实际的数据 .

  • 8

    我相信这句话来自[https://www.opengl.org/registry/specs/ARB/buffer_storage.txt]显示关键:

    OpenGL长期以来一直支持缓冲区对象,作为存储数据的方法,可用于获取顶点属性,纹理的像素数据,制服和其他元素 . 在未扩展的GL中,缓冲区数据存储是可变的 - 也就是说,它们在使用时可能会被解除分配或调整大小 . GL_ARB_texture_storage扩展为纹理对象添加了不可变存储(随后被合并到OpenGL 4.2中) . 此扩展进一步将不可变存储的概念应用于缓冲对象 . 如果实现意识到缓冲区的不变性,则可能会做出某些假设或应用特定的优化以提高性能或可靠性 .

    这些提到可变缓冲区可能被解除分配或调整大小,并且来自 glBufferData ,它带来了可变缓冲区 . 但 glBufferStorage 将向您展示创建不可变缓冲区的能力 .

    这里的关键是“不可变”意味着您将来无法调整大小或取消分配它,但并不意味着您无法在其中写入/读取数据 .

    [编辑]我认为附加一些样本也很好,这可以使规范中的单词更容易理解,:)

    • glBufferData 有时你可能会遇到单词'buffer orphan',通常你会看到类似的调用(还有其他一些方法可以像_1658013那样做缓冲孤儿等):
      glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, size, 0, GL_STREAM_DRAW); GLubyte* ptr = glMapBufferRange(GL_ARRAY_BUFFER, 0, size, GL_MAP_WRITE_BIT); Foo(ptr, size); glUnmapBuffer(GL_ARRAY_BUFFER);

    • glBufferStorage 不允许你取消分配它[注意 glBufferData 中的 0 参数,但它保留了 Persistent-mapped Buffer 的内存,通常你会看到用法如下所示:
      glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferStorage(GL_ARRAY_BUFFER, size, data, GL_MAP_PRESISTENT_BIT|GL_MAP_COHERENT_BIT); GLubyte* ptr = glMapBufferRange(GL_ARRAY_BUFFER, 0, size, GL_MAP_PRESISTENT_BIT|GL_MAP_COHERENT_BIT); Foo(ptr, size);
      注意,ptr只是保持在同一缓冲区's address, that means the buffer is persistented in the memory, and you don't需要取消映射,直到你真的不需要它为止

    谢谢

相关问题