glBufferStorage
Allocates immutable storage for the bound buffer: fixed size, with flags that say exactly how the CPU will use it.
Signature
void glBufferStorage(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
How it works
glBufferData can be called again at any time to resize, so the driver must always be ready to move the buffer. glBufferStorage gives that up: the size is final. In exchange you get the strongest feature of modern buffers, persistent mapping. Map the buffer once with GL_MAP_PERSISTENT_BIT and keep the pointer for the life of the program, writing each frame into a region the GPU is not reading (fences tell you which).
With flags = 0 the CPU can never touch the buffer again: the driver can put it in the fastest GPU memory. That suits static meshes.
Parameters
Where the buffer is bound: GL_ARRAY_BUFFER, GL_UNIFORM_BUFFER…
Size in bytes, fixed forever.
Initial contents, or nullptr.
What the CPU may do, combined with |. 0 = nothing.
Common values
- GL_DYNAMIC_STORAGE_BIT
- glBufferSubData is allowed.
- GL_MAP_READ_BIT / GL_MAP_WRITE_BIT
- The buffer may be mapped for reading / writing.
- GL_MAP_PERSISTENT_BIT
- It may stay mapped while the GPU uses it.
- GL_MAP_COHERENT_BIT
- CPU writes become visible to the GPU without a flush.
Tips & pitfalls
Calling
glBufferDataorglBufferStorageagain on the same buffer is an error; delete it and create a new one to resize.Mapping later must ask only for flags given here.
Errors
When the call is invalid it does nothing and sets an error, which glGetError returns:
- GL_INVALID_OPERATION
- No buffer is bound to target, or its storage is already immutable.
- GL_INVALID_VALUE
- size is 0 or negative, or flags combine bits wrongly (COHERENT without PERSISTENT).
Example
1GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
2glBindBuffer(GL_ARRAY_BUFFER, vbo);
3glBufferStorage(GL_ARRAY_BUFFER, 3 * regionSize, nullptr, flags);
4void *ptr = glMapBufferRange(GL_ARRAY_BUFFER, 0, 3 * regionSize, flags); // keep forever