glBufferStorage creates a new immutable data store for the buffer object currently bound to target. The size of the data store is specified by size. If an initial data is available, its address may be supplied in data. Otherwise, to create an uninitialized data store, data should be NULL.
Immutable means that I can't mutate it right? But then "uninitialized data" would be pointless.
But it is not really immutable because we can specify GL_DYNAMIC_STORAGE_BIT
So what is the difference between glBufferStorage and glBufferData?
A Vertex Array Object (VAO) is an object which contains one or more Vertex Buffer Objects and is designed to store the information for a complete rendered object.
There are two ways to allocate storage for buffer objects: mutable or immutable.
glDeleteBuffers deletes n buffer objects named by the elements of the array buffers . After a buffer object is deleted, it has no contents, and its name is free for reuse (for example by glGenBuffers). If a buffer object that is currently bound is deleted, the binding reverts to 0 (the absence of any buffer object).
One of the advantages of using OpenGL® buffers is that they are able to be located in memory that is accessed very quickly. Important types of buffers, such as framebuffers, can actually be placed directly into the memory of the graphics card being used.
Just so you know, this is the same principle behind glTexStorage* (...)
. Effectively, you sign a contract with the API that says you will never be allowed to change certain properties of your object and in exchange this gives the object immutable status and allows you to do things you normally could not with it.
Texture Views are an interesting example, where the internal image data of an immutable texture can be shared between multiple texture objects and even have its format/dimensions reinterpreted (e.g. 1 slice of a 2D array texture can be shared and used as if it were an ordinary 2D texture).
For vertex buffers, immutable storage opens a class of performance optimizations (e.g. persistent mapped memory) that would not be possible if you could change the size of the buffer at any time. You create a buffer whose size can never be changed, but you are still free to send it new data at any time using glBufferSubData* (...)
commands or by writing to the buffer while it is memory mapped.
With glBufferData (...)
, you can call that command multiple times on the same object and it will orphan the old memory and allocate new storage. With glBufferStorage (...)
, the buffer's size is set for the lifetime of the object (immutable) and it is an error (GL_INVALID_OPERATION
) to call glBufferStorage (...)
again once it has been allocated immutably.
In short, it is the data store (storage characteristics) that is immutable, not the actual data.
I believe this words from [https://www.opengl.org/registry/specs/ARB/buffer_storage.txt] show the key:
OpenGL has long supported buffer objects as a means of storing data that may be used to source vertex attributes, pixel data for textures, uniforms and other elements. In un-extended GL, buffer data stores are mutable - that is, they may be de-allocated or resized while they are in use. The GL_ARB_texture_storage extension added immutable storage for texture object (and was subsequently incorporated into OpenGL 4.2). This extension further applies the concept of immutable storage to buffer objects. If an implementation is aware of a buffer's immutability, it may be able to make certain assumptions or apply particular optimizations in order to increase performance or reliability.
These mentioned the mutable buffer maybe de-allocated or resized, and that comes from glBufferData
which bring mutable buffer. But glBufferStorage
will show you the ability to create immutable buffer.
The key here is 'immutable' means you can't resize or de-allocate it in the future, but not means you can't write/read data in it.
[Edit] I think it's also good to append some sample, that can make the words from spec much more easy to understand, :)
glBufferData
sometime you may meet the words 'buffer orphan', normally you will see the similar calls like (there still some other way to do buffer orphan like GL_MAP_INVALIDATE_BUFFER_BIT
, etc.):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
don't allow you to de-allocate it [note the 0
parameter in glBufferData
, but it keep the memory for the Persistent-mapped Buffer
, normally you will see the usage looks like this: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);
Thanks
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With