Buffer Objects (BO)

Buffer Objects (BO)

Most of of OpenGL's data are stored inside of a Buffer Object (BO) . For example 3D Model data (Vertex data) are stored inside a Vertex Buffer Object (VBO). Or data that is indexing vertices called Index Buffer Object (IBO). Data that is exchanged between client and shader can use Uniform Buffer Objects (UBO) etc. Those BO are created, initialized and updated by the same functions we will discuss now.

Create identifier

To identify an BO we need an empty name (which is an identificier of that object). We get one using the glCreateBuffers function:

GLuint vbo {};
glCreateBuffers(1, &vbo);

glCreateBuffers

Parameter

Type

Description

1

GLsizei n

Number of buffer objects to create.

2

GLuint *buffers

An array in which names of the new buffer objects are stored.

Until here we didn't allocate memory for the BO. We only got an valid name wich we will use to identify our BO. In the next section we will really allocate memory and initialize the BO with data.

Initialize and allocate memory

We want to use our first BO as a VBO. Look at the following code snippet:

struct vertex {
    float x, y, z;
    float r, g, b;
};

const std::vector<vertex> vertices {
    {-1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f }, // Vertex 1
    { 0.0f,  1.0f, 1.0f, 0.0f, 1.0f, 0.0f }, // Vertex 2
    { 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f }  // Vertex 3
};
glNamedBufferStorage(vbo, vertices.size() * sizeof(vertex), vertices.data(), 0);

The first thing we did is to define a structure for our vertex. The structure will hold 3 position and 3 color data. Then we created 3 vertices and put it into an array called: vertices. Now we want to tell OpenGL that we like to upload the vertices and how we like to use the this BO later. To allocate memory and set the properties of the BO we use the function glNamedBufferStorage.

glNamedBufferStorage

Parameter

Type

Description

1

GLuint buffer

Name of the buffer object.

2

GLsizei size

The size of the buffer in bytes.

3

const void *data

Data to upload into the buffer storage.

4

GLbitfield flags

Intented usage bits.

The 1. parameter should be a valid BO name. We got one when we used glCreateBuffers. See above. The 2. parameter as it says it the size of the buffer in bytes. The 3. parameter points to a buffer where the data to upload is hold. If we specify a nullptr nothing will be uploaded but memory allocated of the size we specified in the 2. parameter. The 4. parameter is the important one. It tells OpenGL how to deal with the buffer later when it is used with other OpenGL functions. The following bits can be combined with the OR operator.

Bit

Description

GL_DYNAMIC_STORAGE_BIT

If this is set, we tell OpenGL that we will change the content of the buffer using glBufferSubData. If we don't specify this bit the client (our program) will not be able to change the data of this buffer directly.

GL_MAP_READ_BIT

If we want to map the address of the memory into the client space to read from it, we need to set this flag. If not set we can't use glMapNamedBuffer to read from it.

GL_MAP_WRITE_BIT

If we want to map the address of the memory into the client space to write to it, we need to set this flag. If not set we can't use glMapNamedBuffer to write to it.

GL_MAP_PERSISTENT_BIT

GL_MAP_COHERENT_BIT

GL_CLIENT_STORAGE_BIT

If this bit is set we tell OpenGL that we like the buffer to be managed inside the client memory.

If you look at our example above you will notice that we didn't set any flags for the usage. We use = 0. This means we don't want any of those features for this buffer. We just simply use it to draw and never touch it again. Later we will see how to use those flags in different scenarios. For now its sufficient.

Copy data between BO

There will be a time when you want to copy data from one VBO to another. This is done with glCopyNamedBufferSubData.

glCopyNamedBuferSubData

Parameters

Type

Description

1

GLuint readBuffer

The buffer name from where we like to copy from.

2

GLuint writeBuffer

The buffer name where we like to copy to.

3

GLintptr readOffset

Offset we like to use from the buffer we like to read from.

4

GLintptr writeOffset

Offset we like to use inside the buffer we like to write to.

5

GLsizei size

Number of bytes to copy.

Mapping BOs address into client memory space

If we want to modify the values of the BO manually we can map the BO's memory into the clients memory space. We use for that glMapNamedBuffer. I hope you didn't forget that we can use this function only if the correct bits where set when we initialized the BO.

glMapNamedBuffer

Parameters

Type

Description

GL_bool

1

GLuint buffer

The VBO name.

2

GLenum access

Specifies the access policy.

The 1. parameter is the name of the BO we have to specify. The 2. parameter is how we like to access the values of the BO. There are the following options:

Enum

Description

GL_READ_ONLY

We will only read from the buffer.

GL_WRITE_ONLY

We will only write into the buffer.

GL_READ_WRITE

We will read and write from and into the buffer.

If everything (mapping) was successful the function will return a valid pointer to the memory.

When we are finished with reading/writing to/from the BO we have to unmap it. This is done by the function glUnmapNamedBuffer.

Last updated

Was this helpful?