Buffer Objects in OpenGL

Source: Internet
Author: User
Tags server memory

In many OpenGL operations, we send a large chunk of data to OpenGL, such as passing the vertex array data that needs to be processed. Transferring this data can be very simple, such as copying data from the system's memory to a graphics card. However, because OpenGL is designed according to the client-server model, the data must be transferred from client memory to the server at any time that OpenGL requires data. If the data is not modified, or if the client and server are on different computers (distributed rendering), the data transmission may be slow or redundant.

The OpenGL 1.5 version adds buffer objects, which allow an application to explicitly specify which data to store in the graphics server.

Many different types of buffer objects are used in the current version of OpenGL:

Starting with OpenGL 1.5, the vertex data in an array can be stored in a server-side buffer object.

In OpenGL 2.1, support is added for storing pixel data (for example, texture maps or pixel blocks) in a buffer object.

OpenGL 3.1 Adds a unified buffer object (uniform buffer objects) to store a block of uniform variable data for the shader.

Readers will also find that there are many other features in OpenGL that use the term "object", but these features do not all apply to storing block data. For example, the texture object (OpenGL 1.1 introduces) encapsulates only the various state settings associated with the texture map. Similarly, the added vertex array object in OpenGL 3.0 encapsulates the state parameters associated with using a vertex array. These types of objects allow us to modify a large number of state settings with fewer function calls. To maximize performance, you should try to use them whenever you get used to them.

Note: The name of the object refers to it by its name, which is an unsigned integer identifier. Starting with OpenGL 3.1, all names must be generated by OpenGL using one of the glgen* () functions and no longer accept user-defined names.

creating a Buffer object

Any Non-zero unsigned integer can be used as an identifier for a buffer object. You can either select a representative value or have OpenGL responsible for assigning and managing those identifiers. What is the difference between the two approaches? Letting OpenGL assign identifiers eliminates the risk of unintentionally modifying data by avoiding the reuse of buffer object identifiers that are already in use.

In order for OpenGL to allocate a buffer object identifier, you can call the Glgenbuffers () function.

void Glgenbuffers (Glsizei N, Gluint *buffers);

Returns n the currently unused name in the buffers array, representing the buffer object. The name returned in the buffers array does not need to be a contiguous integer.

The returned name is marked as used for allocation to the buffer object. However, when they are bound, they only get a legitimate state.

0 is a reserved buffer object name that is never returned as a buffer object by Glgenbuffers ().

You can also call the Glisbuffer () function to determine whether an identifier is an identifier for a buffer object that is currently being used.

Glboolean Glisbuffer (gluint buffer);

If buffer is the name of a buffer object that has already been bound and has not been deleted, this function returns GL_TRUE.

This function returns Gl_false if the buffer is 0 or if it is not the name of a buffer object.

Activate Buffer Object

To activate a buffer object, you first need to bind it. A bound buffer object represents which buffer object is affected by the selection of future operations (initialization of data or rendering with a buffer object). That is, if your application has multiple buffer objects, you need to call the Glbindbuffer () function multiple times: once to initialize the buffer object and its data, subsequent calls either select the buffer object for rendering or update the data for the buffer object.

To disable a buffer object, you can call the Glbindbuffer () function with 0 as the identifier for the buffer object. This will switch OpenGL to the default mode of not using buffer objects.

void Glbindbuffer (glenum target, gluint buffer);

The current active buffer object is specified. Target must be set to Gl_array_buffer, Gl_element_array_buffer, Gl_pixel_pack_buffer, Gl_pixel_unpack_buffer, GL_COPY_READ_ Buffer, Gl_copy_write_buffer, gl_transform_ feedback_ buffer or Gl_uniform_buffer. The buffer object that you want to bind is specified by buffer.

Glbindbuffer () completes one of 3 tasks: ① When buffer is the first time a non-0 unsigned integer is used, it creates a new buffer object and assigns buffer to the buffer object as its name. ② when bound to a previously created buffer object, the buffer object becomes the active buffer object. ③ when bound to a buffer with a value of zero, OpenGL stops using the buffer object.

allocating and initializing buffer objects with data

Once a buffer object is bound, you need to reserve the space to store the data, which is implemented by invoking the Glbufferdata () function.

void Glbufferdata (Glenum target, glsizeiptr size, const glvoid *data, Glenum usage
);

An OpenGL server memory that allocates size storage units (usually bytes) for storing vertex data or indexes. All previous data associated with the current bound object will be deleted.

Target can be gl_array_buffer (representing vertex data), Gl_element_array_buffer (representing index data), G l _ P I X E L _ U N pack_bufeer (representing pixel data passed to O P E N G) Or Gl_pixel_pack_buffer (representing pixel data obtained from OpenGL), Gl_copy_read_buffer, and Gl_copy_write_buffer (representing the copying of data between buffers), gl_texture_ Buffer (represents the texture data stored as a texture buffer), gl_transform_feedback_buffer (represents the result of executing a transform feedback shader), or Gl_uniform_buffer (representing the uniform variable value).

The size is the amount of memory needed to store the related data. This value is usually the number of data elements multiplied by their respective storage lengths. Data can be a pointer to the client's memory (for initializing a buffer object), or it can be null. If it passes a valid pointer, the storage space of the size unit is copied from the client to the server. If it passes null, the function retains the storage space of the size unit for later use, but does not initialize it.

Usage provides a hint of how the data will be read and written after it is allocated. Its valid values include Gl_stream_draw, Gl_stream_read, Gl_stream_copy, Gl_static_draw, Gl_static_read, Gl_static_copy, GL_DYNAMIC_ DRAW, Gl_dynamic_read, Gl_dynamic_copy.

If the request allocates more memory than the server can allocate, G L B u f f E r D A () will return to Gl_out_of_memory. This function returns Gl_invalid_value if usage is not one of the values that are allowed to be used. Glbufferdata () First allocates memory to the OpenGL server to store the data. If there is too much memory requested, it will set a gl_out_of_memory error. If the storage space is successfully allocated, and the value of the data parameter is not a null,size storage unit (usually a byte), it is copied from the client's memory to the buffer object. However, if you need to load the data dynamically at some point after the buffer object is created, you can set the data parameter to NULL, reserving the appropriate storage space for the datastore, but not initializing it.

The last parameter of Glbufferdata () usage is a performance tip that is provided to OpenGL. Based on the value specified by the usage parameter,
OpenGL may optimize the data to further improve performance. It can also choose to ignore this hint. In the Buffer object data
, you can do 3 types of operations:

1) Drawing: The client specifies the data for rendering.

2 reads: Reads from the OpenGL buffer (for example, frame buffers) data values, and is used in applications for a variety of computational processes that are not directly related to rendering.

3) Copy: Read the data value from the OpenGL buffer as the data for rendering.

In addition, depending on how often the data is updated, there are several different action hints that describe how often the data is read or used in rendering:

Flow mode: Data in a buffer object often needs to be updated, but less frequently used in drawings or other operations.

Static mode: The data in the buffer object is specified only 1 times, but the data is used very frequently.

Dynamic mode: Data in a buffer object not only needs to be updated, but is also very frequently used.

The values that the usage parameter may use are shown in table 2-6.

Table 2-6 The value of the usage parameter of Glbufferdata ()

(Click to view larger image)

update the data value of the buffer object

There are two ways to update data stored in a buffer object. The first method assumes that we have prepared the same type of data in one buffer of the application. Glbuffersubdata () replaces some subset of the data for the bound buffer object with the data we provide.

void Glbuffersubdata (glenum target, glintptr offset, glsizeiptr size,
const glvoid *data);

Updates the size byte data in the current bound buffer object associated with target from offset (in bytes) with data that is pointing to. Target must be Gl_array_buffer, Gl_element_ Array_buffer, Gl_pixel_unpack_buffer, Gl_pixel_pack_buffer, GL_COPY_READ_ BUFFER, G l _ C O P Y _ W R I T e _ b U F f E R, G l _ T R A N S F O R M _ f E e D B A C K _ b u f f e R or Gl_uniform_buffer 。

If size is less than 0 or size+offset is greater than the size specified when the buffer object was created, Glbuffersubdata () will produce a gl_invalid_value error.

The second approach allows us to more flexibly select the data that needs to be updated. Glmapbuffer () Returns a pointer to a buffer object that can write a new value in the buffer object (or simply read the data, depending on the memory access rights), just as the array is assigned. After you have finished updating the data for the buffer object, you can call Glunmapbuffer () to indicate that you have completed updating the data.

Glmapbuffer () provides access to the entire collection of data contained in the buffer object. This is useful if you need to modify most of the data in the buffer, but this approach is inefficient if you have a large buffer and need only to update a small subset of the values.

Glvoid *glmapbuffer (glenum target, glenum access);

Returns a pointer to the data store of the current bound buffer object associated with T a RG e T. T-a RG e T can be gl_array_buffer, Gl_element_array_buffer, Gl_pixel_pack_buffer, Gl_pixel_unpack_buffer, GL_COPY_READ_ BUFFER, Gl_copy_write_buffer, Gl_transform_feedback_buffer or Gl_uniform_buffer. A C c e s must be one of the gl_read_only, gl_write_only, or gl_read_write, indicating what the customer can do with the data.

If the buffer cannot be mapped (the OpenGL Error state is set to gl_out_of_memory) or it has previously been mapped (OpenGL Error state is set to Gl_invalid_operation), Glmapbuffer () will return NULL.

After you have completed access to the data store, you can call Glunmapbuffer () to cancel the mapping of this buffer.

Glboolean Glunmapbuffer (glenum target);

Indicates that an update to the current bound buffer object has been completed and that the buffer can be freed. T a RG e T must be gl_array_buffer, Gl_element_array_buffer, Gl_pixel_pack_buffer,gl_pixel_unpack_buffer, GL_COPY_READ_ BUFFER, Gl_copy_write_buffer, Gl_transform_feedback_buffer or Gl_uniform_buffer.

The following is a simple example of how to selectively update data elements. We'll use Glmapbuffer () to get a pointer to the data in the buffer object that contains the three-dimensional position coordinates, and then only the z coordinates are updated.

glfloat* data;  
data = (glfloat*) glmapbuffer (Gl_array_buffer, gl_read_write);
if (data!= (glfloat*) NULL) {for
(i = 0; i < 8; ++i)
data[3*i+2] *= 2.0;/* Modify Z values */
  glunmapbuffer (Gl_array_buffer);
else {/
* Handle not being able to update data */
}

Using Glmapbufferrange () is more efficient if you only need to update a relatively small number of values in the buffer (as compared to the overall amount of the value), or to update the value of a tiny contiguous range in a large buffer object. It allows you to modify only the data values in the range that you want.

Glvoid *glmapbufferrange (glenum target, glintptr offset,
glsizeiptr length, glbitfield access);

Returns a pointer to the data store of the current bound buffer object associated with T a RG e T. T-a RG e T can be gl_array_buffer, Gl_element_array_buffer, Gl_pixel_pack_buffer, Gl_pixel_unpack_buffer, GL_COPY_READ_ BUFFER, Gl_copy_write_buffer, Gl_transform_feedback_buffer or Gl_uniform_buffer. Offset and length Specify the scope of the mapping. Access is a bitmask combination of gl_map_read_bit and gl_map_write_bit that indicates what the customer can do with the data, or it can be gl_map_invalidate_range_bit, GL_MAP_ Invalidate_buffer_bit, Gl_map_flush_explicit_bit, or gl_map_unsynchronized_bit, which give hints about how OpenGL should manage data in the buffer.

If an error occurs, Glmapbufferrange () returns NULL. If offset or length is negative, or offset+length is larger than the size of the buffer, a gl_invalid_value is generated. If you cannot get enough memory to map the buffer, you will generate a G L _ o U T _ o F _ m E m o ry error. If any of the following occurs, a gl_invalid_operation is generated: the buffer is mapped; A C c e s S is not gl_map_read_bit or G L _ M a P _ W R i t e _ B i t set; a C c E S owns G L _ M A P _ R E a D _ B I T set and Gl_map_invalidate_range_bit, Gl_map_invalidate_buffer_bit or gl_map_unsynchronized Any one of the _bit is also set, and the Gl_map_write_bit and gl_map_flush_explicit_bit in Access are set.

With Glmapbufferrange (), you can specify optional hints by setting additional bits in Access. These flags describe how the OpenGL server needs to protect the data in the buffer before mapping. This hint is used to help the OpenGL implementation determine what data values need to be retained, and how long it takes to keep any internal copies of the data correct and consistent.

As shown in table 2-7, when you use Glmapbufferrange () to map a buffer, if you specify Gl_map_flush_explicit_bit in the access flag, You should indicate to OpenGL by calling Glflushmappedbufferrange () that the scope in the mapping buffer needs to be modified.

Table 2-7 Glmapbufferrange () Access parameter value

Glvoid Glflushmappedbufferrange (glenum target, glintptr offset,glsizeiptr length);

Indicates that a value in a buffer range has been modified, which may raise the cached version of the OpenGL server update buffer object. Target must be one of the following values: Gl_array_buffer, Gl_element_array_buffer, Gl_pixel_pack_buffer, Gl_pixel_unpack_buffer, GL_COPY_ Read_buffer, Gl_copy_write_buffer, Gl_transform_feedback_buffer or Gl_uniform_buffer. Offset and length specify the range of mapped buffer regions, relative to the beginning of the buffer map range.

If o f F S e t or l e n g t h is negative, or o f F S e t + L e n g t h is larger than the size of the mapped region, the Gl_invalid_value will be generated. If no buffer is bound to target (for example, in the Glbindbuffer () call, 0 is specified as a buffer to target), or if the buffer bound to target does not have a mapping, or if it is mapped but not set Gl_map_flush_ Explicit_bit, a gl_invalid_operation error will be generated.

to copy data between buffer objects

Sometimes, we may need to copy data from one buffer object to another buffer object. In the previous version of OpenGL 3.1, the process was in two steps:

1 Copy the data from the buffer object into the application's memory. You can do this by mapping the buffer and copying it into the local memory buffer, or by calling Glgetbuffersubdata () to copy the data from the server.

2 Update the data in the other buffer object by binding to the new object and then using Glbufferdata () to send the new data (or, if you just replace a subset, use Glbuffersubdata ()). You can also map the buffer, and then copy the data from a local memory buffer to the mapped buffer.

In OpenGL 3.1, the Glcopybuffersubdata () command replicates data without forcing the data to stay in the application's memory for a short pause.

void Glcopybuffersubdata (Glenum readbuffer, Glenum writebuffer,
glintptr readoffset, glintptr writeoffset,
GL Sizeiptr size);

Copies the data from the buffer object associated with the Readbuffer to the buffer object bound to WriteBuffer. Readbuffer and WriteBuffer must be one of the following values: Gl_array_buffer, Gl_copy_read_buffer, Gl_copy_write_buffer, GL_ELEMENT_ARRAY_ BUFFER, Gl_pixel_pack_buffer, Gl_pixel_unpack_buffer, Gl_texture_buffer, gl_transform_ Feedback_buffer or Gl_uniform_ BUFFER.

Readoffset and size Specify the number of data copied to the target buffer object, replacing the same size data from Writeoffset.

The following scenario causes a Gl_invalid_value error: Readoffset, Writeoffset, or size is negative; Readoffset +size exceeds the range of buffer objects bound to readbuffer; writeoffset + size exceeds the range of buffer objects bound to writebuffer; if Readbuffer and WriteBuffer are bound to the same object, And the area specified by Readoffset and size is intersected with the area determined by writeoffset and size.

If any of the bindings in Readbuffer or WriteBuffer are 0, or if any of the buffers are currently mapped, a l_invalid_operation error will occur.

Clear Buffer Object

Once you have finished manipulating the buffer object, you can free its resources and make its identifiers available to other buffer objects. To do this, you can invoke Gldeletebuffers (). All bindings for the deleted current bound buffer object are reset to zero.

void Gldeletebuffers (Glsizei n, const gluint *buffers);

Deletes the n buffer objects whose names are the elements of the buffers array. The freed buffer object can be reused (for example, by calling Glgenbuffers ()).

If a buffer object is deleted at binding time, all the bindings of this object are reset to the default buffer object, just as the Glbindbuffer () is invoked as the specified buffer object parameter with 0. If an attempt is made to delete a buffer object that does not exist or is named 0, this operation is ignored and no error is generated.

storing vertex array data using a buffer object

To store vertex array data in a buffer object, you need to add the following steps to your application:

1 generates the Buffer object identifier (this step is optional).

2) Bind a buffer object to determine whether it is used to store vertex data or indexes.

3 Request the storage space of the data and initialize the data elements (the latter step is optional).

4 Specifies a vertex array function, such as Glvertexpointer (), to initialize the offset relative to the starting position of the buffer.

5) Bind the appropriate buffer object for rendering.

6 render using the appropriate vertex array rendering function, such as gldrawarrays () or gldrawelements ().

If you want to initialize multiple buffer objects, you need to repeat step 2 for each Buffer object (~4)).

All "formats" of vertex array data apply to buffer objects. As described in section 2nd. 6.2, vertices, colors, lighting normals, or any other associated vertex data of any type can be stored in a buffer object. In addition, the mixed vertex array data described in section 2.6.6 can also be stored in a buffer object. Either way, we will create a buffer object that holds all the data used as a vertex array.

Like specifying a memory address in the client's memory (OpenGL should access the vertex array data in the client's memory), you need to specify the offset of the data in the buffer object based on the machine unit (usually the byte). To help readers understand the offset calculation, we will use the following macro to simplify the expression of the offset:

#define Buffer_offset (bytes) ((glubyte*) NULL + (bytes))

For example, if the color and position data for each vertex are floating-point types, they may be represented by the following array:

Glfloat Vertexdata[][6] = {
R0, G0, B0, X0, Y0, Z0},
{R1, G1, B1, X1, Y1, Z1},
...
{Rn, Gn, Bn, Xn, Yn, Zn}
};

This array is used to initialize the buffer object, which can be used to specify data with two separate vertex array, one for the color and the other for the vertex:

Glcolorpointer (3, Gl_float, 6*sizeof (glfloat), Buffer_offset (0));  
Glvertexpointer (3, Gl_float, 6*sizeof (glfloat), Buffer_offset (3*sizeof (
glfloat));  
glenableclientstate (Gl_color_array);
glenableclientstate (Gl_vertex_array);

Conversely, because the data in V E r T e x D a t A matches the format of a mixed vertex array, you can use Glinterleavedarrays () to specify the vertex array data:

Glinterleavedarrays (gl_c3f_v3f, 0, Buffer_offset (0));

Sample program 2-17 combines all of this to demonstrate how to use a buffer object that contains vertex data. This example creates two buffer objects, one containing the vertex data and the other containing the indexed data.

Sample program 2-17 uses vertex data in a buffer object

#define &NBSP;VERTICES&NBSP;0   #define &NBSP;INDICES&NBSP;1   #define &NBSP;NUM_BUFFERS&NBSP;2   Gluint  buffers[NUM_BUFFERS];   glfloat vertices[][3] = {  { -1.0, -1.0, -1.0 },   { 1.0, &NBSP;-1.0,&NBSP;-1.0&NBSP},   { 1.0, 1.0, -1.0 },   { -1.0, 1.0, - 1.0&NBSP},   { -1.0, -1.0, 1.0 },   { 1.0, -1.0, 1.0 },   {  1.0, 1.0, 1.0 },   { -1.0, 1.0, 1.0 }  };   glubyte indices[][4] = {  { 0, 1, 2, 3 },   { 4, &NBSP;7,&NBSP;6,&NBSP;5&NBSP},   { 0, 4, 5, 1 },   { 3, 2, 6, &NBSP;7&NBSP},   { 0, 3, 7, 4 },   { 1, 5, 6, 2 }  };   Glgenbuffers (num_buffers, buffers);   Glbindbuffer (Gl_arraY_buffer, buffers[vertices]);   Glbufferdata (gl_array_buffer, sizeof (vertices),  vertices,   Gl_static_draw);   Glvertexpointer (3, gl_float, 0, buffer_offset (0));   Glenableclientstate (Gl_vertex_array);   Glbindbuffer (gl_element_array_buffer, buffers[indices]);   Glbufferdata (gl_element_array_buffer, sizeof (indices),  indices   Gl_static_draw);   Gldrawelements (Gl_quads, 24, gl_unsigned_byte,   buffer_offset (0));

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.