6. Vertex Buffers

Vertex buffers store vertex coordinates, colors, and indices, in addition to texture coordinates and other information. Use vertex buffers to process certain kinds of models, such as those with a large number of vertices, in the vertex shader. If you do not use vertex buffers, heavy CPU processing (such as vertex array sorting) could cause a considerable drop in performance.

6.1. Creating Objects

Use the glGenBuffers() function to create the buffer objects.

Code 6-1. Definition of the glGenBuffers Function
void glGenBuffers(GLsizei n, GLuint* buffers);

This code creates n buffer objects and stores their object names in buffers.

6.2. Specifying Objects

Specify buffer objects to bind as vertex buffers with the glBindBuffer() function. After this function is called, processing for each type of vertex buffer is run on the specified buffer objects.

Code 6-2. Definition of the glBindBuffer Function
void glBindBuffer(GLenum target, GLuint buffer);

Set target to the vertex buffer type. buffer specifies the buffer object created by the glGenBuffers() function. A buffer object is created for an object name as long as that uncreated object name is specified for buffer.

Table 6-1. Vertex Buffer Types

target Value

Vertex Buffer Types

GL_ARRAY_BUFFER

Buffer for vertex coordinates, vertex colors, normals, and so on.

GL_ELEMENT_ARRAY_BUFFER

Index buffer used by the glDrawElements() function.

GL_VERTEX_STATE_COLLECTION_DMP

Vertex state collection (see 6.6. Vertex State Collections).

6.3. Allocating Buffers

Use the glBufferData() function to allocate a buffer region, and then load vertex data.

Code 6-3. Definition of the glBufferData Function
void glBufferData(GLenum target, GLsizeiptr size, const void* data, 
                  GLenum usage); 

For target specify the same value specified in the glBindBuffer() function (Table 6-1).

For data and size, specify the vertex data to store and its size, respectively. When data is 0 (NULL) the region is simply allocated and no data is stored.

The value of usage must be GL_STATIC_DRAW.

Note:

To configure the GPU access targets and processing to use when allocating the buffer region, pass a bitwise OR of some specific flag values for target for the glBufferData() function. For more information, see 3. Using Data Located in Main Memory in 3DS Programming Manual: Advanced Graphics.

6.4. Rewriting Buffers

Use the glBufferSubData() function to rewrite part of the buffer that was allocated by glBufferData.

Code 6-4. Definition of the glBufferSubData Function
void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, 
                     const void* data); 

For target specify the same value specified in the glBindBuffer() function (Table 6-1).

For offset, specify the offset to the section to rewrite.

For data and size, specify the data to write and its size, respectively.

6.5. Freeing Buffers

Use the glDeleteBuffers() function to destroy buffer objects that are no longer necessary.

Code 6-5. Definition of the glDeleteBuffers Function
void glDeleteBuffers(GLsizei n, const GLuint* buffers); 

This destroys the buffer objects specified by the n object names in buffers.

6.6. Vertex State Collections

Vertex state collections are new to the Nintendo 3DS. You can bind buffer objects to vertex buffers and record them. By using vertex state collections, you can bind buffer objects to vertex buffers and set vertex attributes for a group of vertices.

Vertex state collections share a namespace with buffer objects and can be created, specified, and destroyed using glGenBuffers, glBindBuffer, and glDeleteBuffers, respectively.

6.6.1. Creating Vertex State Collections

A vertex state collection operates as a special buffer object. Use the glGenBuffers() function to generate objects that can be used as vertex state collections, just as you would for buffer objects.

6.6.2. Specifying Vertex State Collections

Use the glBindBuffer() function to specify a buffer object to use as a vertex state collection. For target, specify GL_VERTEX_STATE_COLLECTION_DMP. By default, the object with a name of 0 (with a value of 0 passed into buffer) is a vertex state collection.

After this function is called, the vertex state collection records which buffer objects are bound by glBindBuffer as vertex buffers (using GL_ARRAY_BUFFER or GL_ELEMENT_ARRAY_BUFFER), and also records which vertex attribute values are set by glEnableVertexAttribArray, glDisableVertexAttribArray, glVertexAttrib{1234}{fv}, or glVertexAttribPointer. When a buffer object is bound as a vertex buffer, it overwrites any other existing bindings to the same vertex buffer target. Settings continue to be recorded in a vertex state collection until it is switched.

When the vertex state collection is switched, all buffer objects recorded in the new vertex state collection are bound as the new vertex buffers.

6.6.3. Destroying Vertex State Collections

As with a buffer object, you can use the glDeleteBuffers() function to destroy vertex state collections. Even if a vertex state collection is destroyed, it does not affect the binding between the vertex buffer target and the buffer objects recorded in that vertex state collection.

The glDeleteBuffers() function does not immediately destroy a vertex state collection that is in use. A vertex state collection remains in use until it is switched with another one. You cannot destroy the default vertex state collection. Calls to glDeleteBuffers on the default vertex state collection are ignored.

6.7. Sample Vertex Buffer Usage

The following code samples show how to render a single triangle using a vertex buffer and the glDrawElements() function. There are three steps: defining the arrays, allocating the buffers, and rendering the triangle.

Code 6-6. Defining the Arrays
GLuint triIndexID, triArrayID;
GLushort triIndex[1 * 3] = { 0, 1, 2 };
GLfloat triVertex[3 * 4] =
{
     0.5f,  0.0f, 0.0f, 1.0f,
    -0.5f,  0.5f, 0.0f, 1.0f,
    -0.5f, -0.5f, 0.0f, 1.0f
};
GLfloat triVertexColor[3 * 3] =
{
    1.0f, 0.0f, 0.0f,
    0.0f, 1.0f, 0.0f,
    0.0f, 0.0f, 1.0f
};  
Code 6-7. Allocating the Buffers
glGenBuffers(1, &triArrayID);
glBindBuffer(GL_ARRAY_BUFFER, triArrayID);
glBufferData(GL_ARRAY_BUFFER, sizeof(triVertex) + sizeof(triVertexColor), 0, 
        GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(triVertex), triVertex);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(triVertex), sizeof(triVertexColor), 
        triVertexColor);
glGenBuffers(1, &triIndexID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triIndexID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * sizeof(GLushort), triIndex, 
GL_STATIC_DRAW); 
Code 6-8. Rendering With glDrawElements
glBindBuffer(GL_ARRAY_BUFFER, triArrayID);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)sizeof(triVertex));

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triIndexID);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0); 

6.8. Restrictions on Vertex Data Placement

The following hardware restrictions apply to the vertex data placement configured by the glVertexAttribPointer() function when rendering using vertex data stored in a vertex buffer. A GL_INVALID_OPERATION error is generated when the glDrawArrays() or glDrawElements() function is called in violation of these restrictions.

  • All vertex data must be aligned to its own data type's size.
  • The stride for all vertex data in a single structure must be a multiple of the size of that structure's largest vertex data type.
  • If any padding (beyond the minimum amount required to meet the two aforementioned restrictions) is inserted after the vertex data, it must start at the end of the vertex data and continue until the second-closest 4-byte boundary.

The compiler automatically inserts padding, so there will be no conflicts with the first two restrictions even if you do not pay attention to them when coding.

The following sample code would conflict with the last restriction, if it did not insert extraPadding2.

Code 6-9. Sample Code for Working Around Restrictions on Vertex Data Placement
struct tagVertex
{
    GLshort position[3];
    GLshort extraPadding1;
    GLshort extraPadding2[2];
    GLshort color[4];
}; 

You cannot mix vertex attributes and indices that use vertex buffers with attributes and indices that do not use them in a single call to the glDrawArrays or glDrawElements() function. A GL_INVALID_OPERATION error is generated if they are mixed together.

6.8.1. Restrictions Affecting Only glDrawElements

A GL_INVALID_OPERATION error is generated when all of the following conditions are met, due to restrictions associated with the method of vertex array storage.

  • The vertex buffer is being used.
  • There are 12 vertex attributes being used.
  • All vertex attributes are being used as vertex arrays.
    (qlEnableVertexAttribArray has been called for all vertex attributes.)
  • Rendering is performed using qlDrawElements.

When all these conditions are present, at least two vertex attributes must be placed as interleaved arrays. In other words, 12 independent arrays cannot be simultaneously used as vertex attributes.

Note:

An interleaved array is a group made up of multiple vertex attributes defined as a structure. An individual array made up of one vertex attribute is called an independent array.


CONFIDENTIAL