Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Direct State access with vertex buffers

Looking at this question from 2010, concerning vertex buffers in modern OpenGL, is it still the case that Direct State Access is unavailable with them? I've modified most of my graphics library to use DSA with framebuffer, texture and so on but I still need to "bind" to set my vertex array state (bind array, bind index buffer, bind vertex buffer, unbind array, etc.).

Update 1: I had trouble understanding what the parameters do from BDL's answer. My unit test for a very simple vertex buffer (one attribute, a position) gives me a blank screen (it worked fine with the old method of describing vertex streams). It's supposed to just draw a single triangle, no index buffers required.

Here's what I'm doing, the comments are my understanding:

        ::glEnableVertexArrayAttrib(vao,        // VAO name.
                                    0);         // Attribute index (layout in shader).
        ::glVertexArrayVertexBuffer(vao,        // VAO name.
                                    0,          // Binding point.
                                    vbo,        // VBO name.
                                    12,         // Stride (bytes).
                                    0);         // Offset (bytes).
        ::glVertexArrayAttribFormat(vao,        // VAO name.
                                    0,          // Attribute index (layout in shader).
                                    3,          // Component count (x,y,z).
                                    GL_FLOAT,   // Type.
                                    GL_FALSE,   // Normalised.
                                    0);         // Offset (bytes).
        ::glVertexArrayAttribBinding(vao,       // VAO name.
                                     0,         // Attribute index (layout in shader).
                                     0);        // Binding point.

Now, I think I "get it" about binding points. They're an arbitrary number I can assign such that it's quick and easy for me to swap in a different set of attributes. So just using 0 here for this simple test should suffice.

I'm using glCreateBuffers to create the vbo and glCreateVertexArrays to create the vao (changed from the previous bindable style). There's no debug output (debug context is on) and every call is checked with glGetError and there are no errors reported.

Update 2: the glVertexArrayVertexBuffer stride and offset were in the wrong order. It now works.

Update 3: glVertexArrayVertexBuffer is called once, not once for each attribute in the VBO (if you have interleaved position, texture and so on).

like image 290
Robinson Avatar asked Sep 23 '15 12:09

Robinson


1 Answers

Since OpenGL 4.3 most of the VAO states can be set using direct state access. Have a look at the following functions:

void glVertexArrayAttribBinding  (GLuint vaobj, GLuint attribindex, GLuint bindingindex);

void glVertexArrayVertexBuffer   (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
void glVertexArrayBindingDivisor (GLuint vaobj, GLuint bindingindex, GLuint divisor);

void glEnableVertexArrayAttrib   (GLuint vaobj, GLuint attribindex);
void glDisableVertexArrayAttrib  (GLuint vaobj, GLuint attribindex);
void glVertexArrayAttribFormat   (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
void glVertexArrayAttribIFormat  (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
void glVertexArrayAttribLFormat  (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);

You can find some examples on how to use them in this thread.

In principle "old" VAO code can be translated 1-1 to DSA code. Assume we have an example like this

glBindVertexArray(vao);
glEnableVertexAttribArray(att_idx); //att_idx comes from shader
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(att_idx, 4, GL_FLOAT, GL_FALSE, sizeof(vec4), 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);

then this could look in DSA code as follows

//glBindVertexArray(vao);
//No translation needed, since we don't want to bind :)

//glEnableVertexAttribArray(att_idx);
glEnableVertexArrayAttrib(vao, att_idx);

That was the easy part.

//glBindBuffer(GL_ARRAY_BUFFER, vbo);
//glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glVertexArrayVertexBuffer(vao, 0, vbo, 0, sizeof(vec4));

Specifies the binding-point <-> buffer correspondance. Here the second parameter is a binding point. You can choose here basically what you want as long as it is < GL_MAX_VERTEX_ATTRIB_BINDINGS. But I normally recommend to use the same index that the attribute has. Parameter 3 and 4 (Stride, Offset) are the same values as in glVertexAttribPointer. Note, that glVertexArrayVertexBuffer does, in contrast to glVertexAttribPointer, not allow a stride of 0 to indicate tightly packed data. Even when the data is tightly packed, the stride has to be specified in bytes.

glVertexArrayAttribFormat(vao, att_idx, 4, GL_FLOAT, GL_FALSE, 0);

This defines the format of an attribute. Values 3-5 are similar to their correspondances in glVertexAttribPointer. The last parameter is the relativeoffset between elements in the buffer.

glVertexArrayAttribBinding(vao, att_idx, 0);

This line creates a correspondence between the attribute index and the binding point used in glVertexArrayVertexBuffer.

The last thing missing is the index buffer:

//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glVertexArrayElementBuffer(vao, ibo);

Now the vao should be in the same state as it was with the old code.

like image 188
BDL Avatar answered Oct 20 '22 09:10

BDL