glBufferStorage为缓冲区创建一个新的不可变数据存储 当前绑定到目标的对象。数据存储的大小是 由大小指定。如果初始数据可用,则其地址可以 提供数据。否则,创建未初始化的数据 存储,数据应为NULL。
不可变意味着我不能改变它吗?但是,“未初始化的数据”将毫无意义。
但它并非真正不可变,因为我们可以指定GL_DYNAMIC_STORAGE_BIT
那么glBufferStorage和glBufferData有什么区别?
答案 0 :(得分:17)
您知道,这与glTexStorage* (...)
背后的原理相同。实际上,您与API签订了一份合同,该合同规定您永远不会被允许更改对象的某些属性,作为交换,这将赋予对象不可变状态,并允许您执行通常无法使用它的操作。
纹理视图是一个有趣的例子,其中不可变纹理的内部图像数据可以在多个纹理对象之间共享,甚至可以重新解释其格式/维度(例如 1个2D数组纹理切片可以像普通的2D纹理一样共享和使用。)
对于顶点缓冲区,不可变存储会打开一类性能优化(例如持久映射内存),如果您可以随时更改缓冲区的大小,则无法实现。您创建一个永远不会更改其大小的缓冲区,但您仍然可以使用glBufferSubData* (...)
命令随时向其发送新数据,或者在内存映射时写入缓冲区。
使用glBufferData (...)
,您可以在同一个对象上多次调用该命令,它将孤立旧内存并分配新存储。使用glBufferStorage (...)
,缓冲区的大小设置为对象的生命周期(不可变),并且一旦分配不可变,再次调用GL_INVALID_OPERATION
是错误的(glBufferStorage (...)
)。
简而言之,数据存储(存储特性)是不可变的,而不是实际的数据。
答案 1 :(得分:8)
我相信[https://www.opengl.org/registry/specs/ARB/buffer_storage.txt]中的这句话显示了关键:
OpenGL长期以来一直支持缓冲区对象作为存储数据的方法 可用于获取顶点属性,纹理的像素数据, 制服和其他元素。在未扩展的GL中,缓冲区数据存储 是可变的 - 也就是说,它们可能会被取消分配或调整大小 正在使用中。 GL_ARB_texture_storage扩展添加了不可变存储 用于纹理对象(随后并入OpenGL 4.2)。 此扩展进一步将不可变存储的概念应用于 缓冲对象。如果实现意识到缓冲区的不变性, 它可以做出某些假设或特别适用 优化以提高性能或可靠性。
这些提到可变缓冲区可能已经解除分配或调整大小,并且来自glBufferData
,它带来了可变缓冲区。但是glBufferStorage
将向您展示创建不可变缓冲区的能力。
这里的关键是“不可变”'意味着您将来无法调整大小或取消分配,但这并不意味着您无法在其中写入/读取数据。
[编辑] 我认为附加一些样本也很好,这可以使规范中的单词更容易理解,:))
glBufferData
有时您可能会遇到“缓冲孤儿”字样,通常您会看到类似的调用(还有一些其他方法可以像GL_MAP_INVALIDATE_BUFFER_BIT
这样做缓冲孤儿等等。):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
不允许您取消分配[请注意0
中的glBufferData
参数,但它会保留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);
由于