6

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).

Community
  • 1
  • 1
Robinson
  • 8,836
  • 13
  • 64
  • 108

1 Answers1

13

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.

BDL
  • 18,169
  • 14
  • 45
  • 47
  • It's all extremely confusing. glVertexArrayAttribFormat has a *normalized* boolean parameter. And I'm seeing this described as a stride (eg here: https://www.opengl.org/sdk/docs/man/html/glVertexAttribFormat.xhtml). But if it isn't the stride then where do I put the stride? – Robinson Sep 23 '15 at 13:16
  • Even worse I see that glVertexArrayVertexBuffer has a stride and an offset value. But glVertexArrayAttribFormat has an offset. And there's a binding point value too. Just ... what? This is all extremely obtuse. – Robinson Sep 23 '15 at 13:23
  • Have you checked the thread I linked? There is a simple example given in post #7 – BDL Sep 23 '15 at 13:48
  • I have and it makes no sense to me. Fantastic comment, "// Note the 2nd argument here is a 'binding index', not the attribute index" - so? What is a "binding index"? I have no idea. How do I combine an index buffer with this? The whole interface is absolutely terrible. – Robinson Sep 23 '15 at 14:01
  • 1
    @Robinson Your confusion seems to be more with the concept of binding points than the DSA aspect. Here are a couple of older questions related to binding points, where I tried to explain how they work in my answers: http://stackoverflow.com/questions/26767939/do-opengl-vertex-array-objects-store-vertex-buffer-names-and-indices-or-only-in, http://stackoverflow.com/questions/29220416/can-opengl-vertex-buffer-binding-points-be-reused-across-different-vaos. – Reto Koradi Sep 23 '15 at 14:13
  • For index buffers, there is [VertexArrayElementBuffer](https://www.opengl.org/sdk/docs/man/html/glVertexArrayElementBuffer.xhtml). Maybe you should also read the [extension specification](https://www.opengl.org/registry/specs/ARB/direct_state_access.txt) – BDL Sep 23 '15 at 14:14
  • 3
    Why do people always say to read the specification? The specification is *terrible*. Of course I know what a *binding point* is. How these "binding points" correspond to data coming into my shader is left as an exercise for the reader, presumably. – Robinson Sep 23 '15 at 14:17
  • I extended the answer with a step-by-step example, hopefully this makes things more clear. – BDL Sep 23 '15 at 15:08
  • 1
    Thank you, thank you, thank you. It's a lot clearer, but it doesn't work. I'm getting a blank screen. I've updated the question to show what I've done. – Robinson Sep 23 '15 at 20:18
  • 1
    stride and offset are in the wrong order in `glVertexArrayVertexBuffer` (first offset, then stride is correct). – BDL Sep 23 '15 at 20:40
  • 1
    Hell yes they are. It works now. How can I thank you? :p. – Robinson Sep 23 '15 at 20:42
  • 3
    @Robinson Binding points were introduced in OpenGL 4.3, and I would consider them a fairly advanced concept. I certainly have never used them myself, and only know how they work based on reading the spec while answering the questions I linked. So I don't think we could automatically assume that you understood them already. Particularly after you said in previous concepts that you were confused by the calls that use binding points. – Reto Koradi Sep 24 '15 at 04:34
  • 1
    Can it be that specifying `0` as the stride in `glVertexArrayVertexBuffer` does not work at all? I remember that the specs somewhere said it cannot be automatically detected when using binding indices. And I just had to fix my code by specifying the stride manually - then a simple triangle appeared. With 0 it didn't. – Ray Dec 06 '16 at 22:34