Chapter 5. Data (Chapter V data)

Monday to Friday, a day, 7 am Beijing time on time updates -

What You'll Learn in This Chapter (what you'll learn in this chapter)

To the Create buffers and Textures How you CAN use that to the Data Store that your CAN Access Program
How to GET OpenGL to Supply's at The values of the Attributes your Vertex Automatically
How to Access Textures and buffers from your shaders
how to create a buffer and texture maps
how to get OpenGL automatically set your vertex data of
how to access the buffer from the shader and texture
In the examples you’ve seen so far, either we have used hard-coded data directly in our shaders, or we have passed values to shaders one at a time. While sufficient to demonstrate the configuration of the OpenGL pipeline, this is hardly representative of modern graphics programming. Recent graphics processors are designed as streaming processors that consume and produce huge amounts of data. Passing a few values to OpenGL at a time is extremely inefficient. To allow data to be stored and accessed by OpenGL, we include two main forms of data storage—buffers and textures. In this chapter, we first introduce buffers, which are linear blocks of untyped data and can be seen as generic memory allocations. Next, we introduce textures, which are normally used to store multidimensional data, such as images or other data types

Until now, show us those hard-coded data Ye Hao, Ye Hao to the shader pass data from the C language, while indicating OpenGL games are played, but it is actually just teaching. It is the efficient use of OpenGL way we are going to learn. There are two main forms of data in OpenGL: texture storage buffer and used for general data buffer. In this section, we first look at the buffer store general data, which is non-linear types of data blocks. Then we introduce the texture, you can store inside the multi-dimensional data such as pictures or something.

Buffers (buffer)

In OpenGL, buffers are linear allocations of memory that can be used for a number of purposes. They are represented by names, which are essentially opaque handles that OpenGL uses to identify them. Before you can start using buffers, you have to ask OpenGL to reserve some names for you and then use them to allocate memory and put data into that memory. The memory allocated for a buffer object is called its data store. The data store of the buffer is where OpenGL stores its data. You can put data into the buffer using OpenGL commands, or you can map the buffer object, which means that you can get a pointer that your application can use to write directly into (or read directly out of) the buffer

In OpenGL, the buffer memory is stored in a linear block, they have their own name, the name is basically a OpenGL marker used to distinguish them. Before you start using the buffer, you need to get OpenGL to assign you some names, so that you can allocate memory buffers that correspond to the names and operate them. You can plug by the OpenGL API to these buffers in the data, you can also get directly to address these buffers, and then entered, write data or read data from the inside.

Once you have the name of a buffer, you can attach it to the OpenGL context by binding it to a buffer binding point. Binding points are sometimes referred to as targets; these terms may be used interchangeably. There are a large number of buffer binding points in OpenGL and each has a different use, although the buffers you bind to them are the same. For example, you can use the contents of a buffer to automatically supply the inputs of a vertex shader, to store the values of variables that will be used by your shaders, or as a place for shaders to store the data they produce. You can even use the same buffer for multiple purposes at the same time

When you have a buffer object, you can bind it to the current OpenGL context. These bindings node sometimes we call it objective. OpenGL bindings there are many nodes, even though you bind up the buffers are the same, but each node has a different use. For example, you can use a buffer to provide a vertex shader data, or use a buffer to store output data generated by the shader. You can even apply the same buffer used for multiple purposes at the same time.

Creating Buffers and Allocating Memory (create buffers and memory allocation)

Before you can ask OpenGL to allocate memory, you need to create a buffer object to represent that allocation. Like most objects in OpenGL, buffer objects are represented by a GLuint variable, which is generally called its name. One or more buffer objects can be created using the glCreateBuffers() function, whose prototype is

Before you allocate memory for the buffer objects, you need to create such a buffer. With most of the OpenGL in the objects, mark the buffer object is a GLuint type, which is its name. You can use glCreateBuffers to create a one-time or multiple buffer objects

void glCreateBuffers(GLsizei n, GLuint* buffers);
The first parameter to glCreateBuffers(), n, is the number of buffer objects to create. The second parameter, buffers, is the address of the variable or variables that will be used to store the names of the buffer objects. If you need to create only one buffer object, set n to 1 and set buffers to the address of a single GLuint variable. If you need to create more than one buffer at a time, simply set n to that number and point buffers to the beginning of an array of at least n GLuint variables. OpenGL will just trust that the array is big enough and will write that many buffer names to the pointer that you specify

The first parameter is the number of objects you need to create a buffer zone, and the second parameter is the address of the buffer for storing objects. Note that the second argument needs to have enough space to store the name of an object, such as if you want to 10 buffer object, then the second parameter points to the need to address at least you can put 10 GLuint.

Each of the names you get back from glCreateBuffers() represents a single buffer object. You can bind the buffer objects to the current OpenGL context by calling glBindBuffer(), the prototype of which is

Once you've created a buffer objects, you can use glBindBuffer to bind a buffer object to the current OpenGL context of the

void glBindBuffer(GLenum target, GLuint buffer);
Before you can actually use the buffer objects, you need to allocate their data stores, which is another term for the memory represented by the buffer object. The functions that are used to allocate memory using a buffer object are glBufferStorage() and glNamedBufferStorage(). Their prototypes are

After completing the above operation, you may obtain a memory buffer object allocation, use and glNamedBufferStorage to allocate glBufferStoerage

void glBufferStorage(GLenum target,
GLsizeiptr size,
const void data,
GLbitfield flags);
void glNamedBufferStorage(GLuint buffer,
GLsizeiptr size,
const void
data,
GLbtifield flags);
The first function affects the buffer object bound to the binding point specified by target; the second function directly affects the buffer specified by buffer. The remainder of the parameters serve the same purpose in both functions. The size parameter specifies how big the storage region is to be, in bytes. The data parameteris used to pass a pointer to any data that you want to initialize the buffer with. If this is NULL, then the storage associated with the buffer object will at first be uninitialized. The final parameter, flags, is used to tell OpenGL how you’re planning to use the buffer object.

The first function will affect the binding buffer object on the target node. The second function directly affects the buffer object buffer specified. Meaning both function parameters remaining the same. memory buffer size indicates the number of bytes of the object data represented by the data, if the data is empty, the buffer memory is only allocated, data is not written, if data has data, it will copy the data on the data go to the buffer object. The last argument is a flag that tells OpenGL, our program will later how to use this buffer object.

Once storage has been allocated for a buffer object using either glBufferStorage() or glNamedBufferStorage(), it cannot be reallocated or respecified, but is considered immutable. To be clear, the contents of the buffer object’s data store can be changed, but its size or usage flags may not. If you need to resize a buffer, you need to delete it, create a new one, and set up new storage for that

When you assign a good memory for the buffer objects, you can change the contents of the buffer object, but you can not change its size, if you have to do this, you must first delete the current buffer object, and then again create a new one.

The most interesting parameter to these two functions is the flags parameter. This should give OpenGL enough information to allocate memory suitable for your intended purpose and allow it to make an informed decision about the storage requirements of the buffer. flags is a GLbitfield type, which means that it’s a combination of one or more bits. The flags that you can set are shown in Table 5.1

The most funny is the last parameter of the parameter, the parameter tells OpenGL how you will use these buffers objects, so OpenGL can assign these to the appropriate buffer memory, the last parameter may be more flags in Table 5.1 bit bit operation is performed using a combination of

Chapter 5. Data (Chapter V data)
The flags listed in Table 5.1 may seem a little terse and probably deserve more explanation. In particular, the absence of certain flags can mean something to OpenGL, some flags may be used only in combination with others, and the specification of these flags can have an effect on what you’re allowed to do with the buffer later. We’ll provide a brief explanation of each of these flags here and then dive deeper into some of their meanings as we cover further functionality

Table 5.1 in the these flags may need more explanation for the job, in particular, certain signs of OpenGL has a special meaning, some signs can only be used in conjunction with a specific logo. Let's take some short note behind when we use those features further in-depth explanation

First, the GL_DYNAMIC_STORAGE_BIT flag is used to tell OpenGL that you mean to update the contents of the buffer directly—perhaps once for every time that you use thedata. If this flag is not set, OpenGL will assume that you’re not likely to need to change the contents of the buffer and might put the data somewhere that is less accessible. If you don’t set this bit, you won’t be able to use commands like glBufferSubData() to update the buffer content, although you will be able to write into it directly from the GPU using other OpenGL commands

First GL_DYNAMIC_STORAGE_BIT, this tag tells OpenGL, you need to frequently update the buffer object, if the flag is not set, then, OpenGL as your buffer memory objects can be allocated in the distant mountains, you might access such buffer cause endocrine disorders, and even incontinence. If you do not set this thing, you may not be able to use glBufferSubData to update the data buffer, although you can write data entered by other OpenGL instructions directly from the GPU

The mapping flags GL_MAP_READ_BIT, GL_MAP_WRITE_BIT, GL_MAP_PERSISTENT_BIT, and GL_MAP_COHERENT_BIT tell OpenGL if and how you’re planning to map the buffer’s data store. Mapping is the process of getting a pointer that you can use from your application that represents the underlying data store of the buffer. For example, you may map the buffer for read or write access only if you specify the GL_MAP_READ_BIT or GL_MAP_WRITE_BIT flags, respectively. Of course, you can specify both if you wish to map the buffer for both reading and writing. If you specify GL_MAP_PERSISTENT_BIT, then this flag tells OpenGL that you wish to map the buffer and then leave it mapped while you call other drawing comands. If you don’t set this bit, then OpenGL requires that you don’t have the buffers mapped while you’re using it from drawing commands. Supporting peristent maps might come at the expense of some performance, so it’s best not to set this bit unless you really need to. The final bit, GL_MAP_COHERENT_BIT, goes further and tells OpenGL that you want to be able to share data quite tightly with the GPU. If you don’t set this bit, you need to tell OpenGL when you’ve written data into the buffer, even if you don’t unmap it.

GL_MAP_READ_BIT, GL_MAP_WRITE_BIT, GL_MAP_PERSISTENT_BIT and GL_MAP_COHERENT_BIT tell OpenGL how you manipulate the data buffer. For example, only you set GL_MAP_READ_BIT or GL_MAP_WRITE_BIT, you can read or write data by mapping the way. You can use two signs to read and write buffer object. GL_MAP_PERSISTENT_BIT flag tells OpenGL, when you call the plotting instructions, will not cancel the mapping state, if you do not use this flag, then you're in the drawing, it is necessary to cancel the mapping state buffer object. GL_MAP_PERSISTENT_BIT This flag actually will make a big burden on the system, it is best not to use the more Ay, unless you really need. GL_MAP_COHERENT_BIT This tells OpenGL you want to be able to share data with compact GPU, if you do not set this flag, even if you do not unmap, you also need to tell OpenGL, When did you write data to the buffer.

// The type used for names in OpenGL is GLuint
GLuint buffer;
// Create a buffer
glCreateBuffers(1, &buffer);
// Specify the data store parameters for the buffer
glNamedBufferStorage(
buffer, // Name of the buffer
1024 * 1024, // 1 MiB of space
NULL, // No initial data
GL_MAP_WRITE_BIT); // Allow map for writing
// Now bind it to the context using the GL_ARRAY_BUFFER binding point
glBindBuffer(GL_ARRAY_BUFFER, buffer);
Listing 5.1: Creating and initializing a buffer

Listing 5.1: create and initialize a buffer objects

After the code in Listing 5.1 has executed, buffer contains the name of a buffer object that has been initialized to represent one megabyte of storage for whatever data we choose. Using the GL_ARRAY_BUFFER target to refer to the buffer object suggests to OpenGL that we’re planning to use this buffer to store vertex data, but we’ll still be able to take that buffer and bind it to some other target later. There are a handful of ways to get data into the buffer object. You may have noticed the NULL pointer that we pass as the third argument to glNamedBufferStorage() in Listing 5.1. Had we instead supplied a pointer to some data, that data would have been used to initialize the buffer object. Using this pointer, however, allows us to set only the initial data to be stored in the buffer.

After the implementation of the code in Listing 5.1 is completed, you will get a 1MB size of the buffer object. GL_ARRAY_BUFFER tell OpenGL, we will use this vertex buffer object storage data, but we can still put it behind for other purposes. We There are many ways to plug inside the buffer object data, noting that the list of third parameter 5.1, we give it a pass NULL, apply only to express our memory, but not pass data. Here, if the third parameter is the data, then the data will be passed up to the buffer memory of the object

Another way get data into a buffer is to give the buffer to OpenGL and tell it to copy data there. This allows you to dynamically update the content of a buffer after it has already been initialized. To do this, we call either glBufferSubData() or glNamedBufferSubData(), passing the size of the data we want to put into the buffer, the offset in the buffer where we want it to go, and a pointer to the data in memory that should be put into the buffer. glBufferSubData() and glNamedBufferSubData() are declared as follows:

Another method is to write data after creating a buffer, using glBufferSubData or glNamedBufferSubData function, the API allows you to dynamically update the contents of the buffer object. offset is the offset data writing position, size is the size of the data, data to be written is the data we

void glBufferSubData(GLenum target,
GLintptr offset,
GLsizeiptr size,
const GLvoid data);
void glNamedBufferSubData(GLuint buffer,
GLintptr offset,
GLsizeiptr size,
const void
data);
To update a buffer object using glBufferSubData(), you must have told OpenGL that you want to put data into it that way. To do this, include GL_DYNAMIC_STORAGE_BIT in the flags parameter to glBufferStorage() or glNamedBufferStorage(). Like glBufferStorage() and glNamedBufferStorage(), glBufferSubData() affects the buffer bound to the binding point specified by target, and glNamedBufferSubData() affects the buffer object specified by buffer. Listing 5.2 shows how we can put the data originally used in Listing 3.1 into a buffer object, which is the first step in automatically feeding a vertex shader with data.

In order to update the contents of the buffer objects used glBufferSubData, when you need to create it using GL_DYNAMIC_STORAGE_BIT. glBufferSubData will affect the buffer object binding node, glNamedBufferSubData will affect the data content of the buffer objects specified by the buffer. Listing 5.2 shows us how to pass data list 3.1 buffer object with the way learned today

// This is the data that we will place into the buffer object
static const float data[] =
{
0.25, -0.25, 0.5, 1.0,
-0.25, -0.25, 0.5, 1.0,
0.25, 0.25, 0.5, 1.0
};// Put the data into the buffer at offset zero
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(data), data);
Listing 5.2: Updating the content of a buffer with glBufferSubData()

Listing 5.2, using the content glBufferSubData update buffer object

Another method for getting data into a buffer object is to ask OpenGL for a pointer to the memory that the buffer object represents and then copy the data there yourself. This is known as mapping the buffer. Listing 5.3 shows how to do this using the glMapNamedBuffer() function

Another method of writing data into the buffer in the object mapping method is used, as shown below

// This is the data that we will place into the buffer object
static const float data[] =
{
0.25, -0.25, 0.5, 1.0,
-0.25, -0.25, 0.5, 1.0,
0.25, 0.25, 0.5, 1.0
};
// Get a pointer to the buffer's data store
void * ptr = glMapNamedBuffer(buffer, GL_WRITE_ONLY);
// Copy our data into it...
memcpy(ptr, data, sizeof(data));
// Tell OpenGL that we're done with the pointer
glUnmapNamedBuffer(GL_ARRAY_BUFFER);
Listing 5.3: Mapping a buffer’s data store with glMapNamedBuffer()

As with many other buffer functions in OpenGL, there are two versions—one that affects the buffer bound to one of the targets of the current context, and one that operates directly on a buffer whose name you specify. Their prototypes are

Operation with many other functions as a buffer, there are two versions Mapping method, as shown below

void glMapBuffer(GLenum target,
GLenum usage);
void
glMapNamedBuffer(GLuint buffer,
GLenum usage);
To unmap the buffer, we call either glUnmapBuffer() or glUnmapNamedBuffer(), as shown in Listing 5.3. Their prototypes are

unmapping operations using corresponding glUnmapBuffer or glUnmapNamedBuffer

void glUnmapBuffer(GLenum target);
void glUnmapNamedBuffer(GLuint buffer);
Mapping a buffer is useful if you don’t have all the data handy when you call the function. For example, you might be about to generate the data, or to read it from a file. If you wanted to use glBufferSubData() (or the initial pointer passed to glBufferData()), you’d have to generate or read the data into temporary memory and then get OpenGL to make another copy of the data into the buffer object. If you map a buffer, you can simply read the contents of the file directly into the mapped buffer. When you unmap it, if OpenGL can avoid making a copy of the data, it will. Regardless of whether we used glBufferSubData() or glMapBuffer() and an explicit copy to get data into our buffer object, it now contains a copy of data[] and we can use it as a source of data to feed our vertex shader

The benefits of mapping is that you do not have to save a copy of the data in the C language, you can go directly to the operation of the data on the GPU. For example, if you read data from a file, to update the contents of the buffer object, if glBufferSubData way, you must first file to read the contents of memory, and then use glBufferSubData update the data if you use mapping the way then you can read the data into the buffer object directly from the file.

The glMapBuffer() and glMapNamedBuffer() functions can sometimes be a little heavy handed. They map the entire buffer, and do not provide any information about the type of mapping operation to be performed besides the usage parameter. Even that serves only as a hint. A more surgical approach can be taken by calling either glMapBufferRange() or glMapNamedBufferRange(), whose prototypes are

Use glMapBuffer and glMapNamedBuffer sometimes too violent, because it is mapping the entire buffer, another more preferred way is glMapBufferRange and glMapNamedBufferRange

void glMapBufferRange(GLenum target,
GLintptr offset,
GLsizeiptr length,
GLbitfield access);
void
glMapNamedBufferRange(GLuint buffer,
GLintptr offset,
GLsizeiptr length,
GLbitfield access);
As with the glMapBuffer() and glMapNamedBuffer() functions, there are two versions of these functions—one that affects a currently bound buffer and one that affects a directly specified buffer object. These functions, rather than mapping the entire buffer object, map only a specific range of the buffer object. This range is given using the offset and length parameters. The parameter contains flags that tell OpenGL how the mapping should be performed. These flags can be a combination of any of the bits listed in Table 5.2.

GlMapBuffer and glMapNamedBuffer with the same, there are two versions - a buffer object currently bound node influence of an impact buffer object specified by the first argument. Compared to mapping the entire buffer, maybe only a mapping function part. offset from the start offset address indicate which mapping, length indicates how much data blocks to mapping. The last flag as shown in Table 5.2.

Chapter 5. Data (Chapter V data)
As with the bits that you can pass to glBufferStorage(), these bits can control some advanced functionality of OpenGL and, in some cases, their correct usage depends on other OpenGL functionality. However, these bits are not hints and OpenGL will enforce their correct usage. You should set GL_MAP_READ_BIT if you plan to read from the buffer and GL_MAP_WRITE_BIT if you plan to write to it. Reading or writing into the mapped range without setting the appropriate bits is an error. The GL_MAP_PERSISTENT_BIT and GL_MAP_COHERENT_BIT flags have similar meanings to their identically named counterparts in glBufferStorage(). All four of these bits are required to match between when you specify storage and when you request a mapping. That is, if you want to map a buffer for reading using the GL_MAP_READ_BIT flag, then you must also specify the GL_MAP_READ_BIT flag when you call glBufferStorage()

When you create a buffer with those marks are different, where the flag will be set not prompt, but forcibly set, that is, if you are mapping when the flag is set to read, then write the data entered, but later, it will An error occurred. Another point to note is that, in order to be able to read and write operations here, you need to create the buffer objects when you set the corresponding flag

We’ll dig deeper into the remaining flags when we cover synchronization primitives a little later in the book. However, because of the additional control and stronger contract provided by glMapBufferRange() and glMapNamedBufferRange(), it isgenerally preferred to call these functions rather than glMapNamedBuffer() (or glMapBuffer()). You should get into the habbit of using these functions even if you’re not using any of their more advanced features

We will talk more in-depth those other flags in the following pages. You should be more use of glMapBufferRange of API instead glMapBuffer, because then you can get more performance improvements.

Translations of this day to get here, see you tomorrow, bye ~

Get the latest plot first time, please pay attention to the Eastern Han Dynasty academy and the heart of the public graphic No.

Han College, waiting for you to play Oh

Guess you like

Origin blog.51cto.com/battlefire/2429628