BuffersGL 4.4

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

targetGLenum

Where the buffer is bound: GL_ARRAY_BUFFER, GL_UNIFORM_BUFFER…

sizeGLsizeiptr

Size in bytes, fixed forever.

dataconst void *

Initial contents, or nullptr.

flagsGLbitfield

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 glBufferData or glBufferStorage again 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

example.cpp
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
Official Khronos documentation