Sign in to follow this  

Handling VAOs in GL 4.5 with DSA

This topic is 1196 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

In GL_EXT_direct_state_access there was a function named glVertexArrayVertexAttribOffsetEXT. I do not see an equivalent in GL_ARB_direct_state_access. I'm trying to accomplish the following using the new core DSA functions:

GLuint vao = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[3]);
glEnableVertexArrayAttribEXT(vao, 0);
glEnableVertexArrayAttribEXT(vao, 1);
glVertexArrayVertexAttribOffsetEXT(vao, buffers[0], 0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glVertexArrayVertexAttribOffsetEXT(vao, buffers[1], 1, 2, GL_FLOAT, GL_FALSE, 0, 0);

I have tried the following, but it does work:

 

GLuint vao = 0;
glCreateVertexArrays(1, &vao);
glVertexArrayElementBuffer(vao, buffers[3]);
glEnableVertexArrayAttrib(vao, 0);
glEnableVertexArrayAttrib(vao, 1);
glVertexArrayVertexBuffer(vao, 0, buffers[0], 0, 0);
glVertexArrayVertexBuffer(vao, 1, buffers[1], 0, 0);
glVertexArrayAttribFormat(vao, 0, 3, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribFormat(vao, 1, 2, GL_FLOAT, GL_FALSE, 0);
Edited by Chris_F

Share this post


Link to post
Share on other sites

This is discussed in Issue 31 in the spec, and the recommendation is to use the GL_ARB_vertex_attrib_binding calls instead:

 

 

Do we need VertexArray*Offset? These are present in EXT_direct_state_access.

RESOLVED: No. GL 4.4 intoduced ARB_vertex_attrib_binding which allows separately changing the buffer (via BindVertexBuffer) and setting the format (via VertexAttribFormat). In this version we provide DSA routines to match these: VertexArrayVertexBuffer and VertexArrayAttribFormat.

Futhermore, no need to add VertexArrayAttribBinding, we can use VertexArrayBindingDivisor which is based on ARB_vertex_attrib_binding too.

Share this post


Link to post
Share on other sites

You are missing

glVertexArrayAttribBinding (GLuint vaobj, GLuint attribindex, GLuint bindingindex)

to bind an attribute (index) to a vertex buffer binding (index).
 
Also check all function definitions again so you don't mix them up (e.g. second parameter of glVertexArrayVertexBuffer is also the VBO binding index, not the attribute index).

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

Edit: The last sentence of Issue 31 makes no sense (also it's unresolved), how else should the attribute "know" which VBO it refers to.

Edited by Maus

Share this post


Link to post
Share on other sites

Ok, I guess I have to admit that I have never fully grasped vertex attributes in OpenGL. I pretty much knew how to get glVertexArrayVertexAttribOffsetEXT working, but I have no clue how to get these other functions to work. The AttribOffset function only has an single index parameter, and with these new functions you have both attribindex and bindingindex. I have no clue what the difference is. Also, I don't understand if the relativeoffset of glVertexArrayAttribFormat is identical to the stride of glVertexArrayVertexBuffer.

Share this post


Link to post
Share on other sites

I'm a bit rusty on the new vertex attrib binding extension (which these new vertex array DSA functions are an alternative for), but I'll give it a go.
 
In the beginning, there was nothing glVertexArribPointer would let you describe the format (type, size, etc) of a vertex attribute as well as where to source that data from, albeit this source was implicit from the currently bound vertex buffer object. Let's take your code as an example... so you have two vertex attributes:
 
Vertex attribute 0:

  • Buffer: buffers[0]
  • Index: 0
  • Num components: 3
  • Type: Float
  • Stride to next element: 12 bytes (implicit from number of components and data type)
  • Buffer offset of first element: 0 bytes

Vertex attribute 1:

  • Buffer: buffers[1]
  • Index: 1
  • Num components: 2
  • Type: Float
  • Stride to next element: 8 bytes (implicit from number of components and data type)
  • Buffer offset of first element: 0 bytes

This might make it clearer that there are two things being described for each attribute. The "layout" of the attribute, and the buffer from which to read the data.
 
The vertex attrib binding extension was Khronos' solution for separating these two descriptors. Instead of using glVertexAttribPointer, you use glVertexAttribFormat to describe the attribute format, glBindVertexBuffer to describe a buffer which can be read from and how to read from it, and glVertexAttribBinding to associate link formats with buffer sources (or their DSA counterparts).
 
Taking your code again, it would look something like this (non-DSA, because it's easier for me to write):

glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
 
With the vertex attrib binding function, we get something like this (now in DSA):
glEnableVertexAttribArray(vao, 0);
glEnableVertexAttribArray(vao, 1);
 
// Setup the formats
glVertexArrayAttribFormat(vao, 0, 3, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribFormat(vao, 1, 2, GL_FLOAT, GL_FALSE, 0);
 
// Setup the buffer sources
glVertexArrayVertexBuffer(vao, 0, buffers[0], 0, 0); // Note the 2nd argument here is a 'binding index', not the attribute index
glVertexArrayVertexBuffer(vao, 1, buffers[1], 0, 0);
 
// Link them up
glVertexArrayAttribBinding(vao, 0, 0); // Associate attrib 0 (first 0) with binding 0 (second 0).
glVertexArrayAttribBinding(vao, 1, 1);

I've not tested this, but I'm pretty sure it works :)

 

The remaining question you probably have is why do both the vertex buffer and the vertex attribute have an offset argument? Let's imagine that you store multiple models in a single vertex buffer, and not all of them have the same format. You can set up the formats ahead of time, for example:

  • Attrib 0: vec3, offset 0
  • Attrib 1: vec2, offset 16

Your buffer sources will also have its own offset, which is the base from where to start reading. So you might have a model's vertex data stored in a vertex buffer, but it's at offset 320 bytes from the start. You can set this offset on the vertex buffer and the format doesn't have to take this into account as it and the buffer source are separated! This also lets you swap buffer sources and formats a whole lot more easily, instead of having to rebind a load of buffers and respecifying the attribute types every time, as you would need to with the original glVertexAttribPointer

Share this post


Link to post
Share on other sites

Tried it and still I get nothing on screen.

 

    GLuint buffers[3] = {0};

    glCreateBuffers(3, buffers);

    glNamedBufferData(buffers[0], sizeof(position), &position, GL_STATIC_DRAW);
    glNamedBufferData(buffers[1], sizeof(texcoord), &texcoord, GL_STATIC_DRAW);
    glNamedBufferData(buffers[2], sizeof(indices), &indices, GL_STATIC_DRAW);

    /*GLuint vao = 0;
    glGenVertexArrays(1, &vao);

    glBindVertexArray(vao);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[2]);

    glEnableVertexArrayAttribEXT(vao, 0);
    glEnableVertexArrayAttribEXT(vao, 1);

    glVertexArrayVertexAttribOffsetEXT(vao, buffers[0], 0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glVertexArrayVertexAttribOffsetEXT(vao, buffers[1], 1, 2, GL_FLOAT, GL_FALSE, 0, 0);*/

    GLuint vao = 0;
    glCreateVertexArrays(1, &vao);
    glVertexArrayElementBuffer(vao, buffers[2]);

    glEnableVertexArrayAttrib(vao, 0);
    glEnableVertexArrayAttrib(vao, 1);

    glVertexArrayAttribFormat(vao, 0, 3, GL_FLOAT, GL_FALSE, 0);
    glVertexArrayAttribFormat(vao, 1, 2, GL_FLOAT, GL_FALSE, 0);

    glVertexArrayVertexBuffer(vao, 0, buffers[0], 0, 0);
    glVertexArrayVertexBuffer(vao, 1, buffers[1], 0, 0);

    glVertexArrayAttribBinding(vao, 0, 0);
    glVertexArrayAttribBinding(vao, 1, 1);

    glBindVertexArray(vao);
Edited by Chris_F

Share this post


Link to post
Share on other sites

You've probably already checked, but are you getting any GL errors? Either at draw time or after you've created the VAO?

 

No errors, no debug output warnings, just a blank screen.

Share this post


Link to post
Share on other sites

This doesn't work either. Again, no errors.

 

GLuint vao = 0;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[2]);
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

    glBindVertexBuffer(0, buffers[0], 0, 0);
    glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, 0);
    glVertexAttribBinding(0, 0);

    glBindVertexBuffer(1, buffers[1], 0, 0);
    glVertexAttribFormat(1, 2, GL_FLOAT, GL_FALSE, 0);
    glVertexAttribBinding(1, 1);

Share this post


Link to post
Share on other sites

Ah right, I thought the stride could still be inferred when the binding index and attribute index were linked! Reading the extension spec again, I had misread a sentence which was referring to glVertexAttribPointer, not to the stride for vertex buffers.

 

So no, not a driver bug, it sounds like it's working as intended.

Share this post


Link to post
Share on other sites

This topic is 1196 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this