Jump to content
  • Advertisement
Sign in to follow this  
kloffy

VAO - Is it necessary to redo setup each time buffer data changes?

This topic is 2683 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

I am a bit surprised that it seems like my VAOs get invalidated each time that I provide new buffer data. Are you really supposed to do glEnableClientState and setup gl*Pointers all over again after each glBufferSubData? That would make VAOs pretty useless for dynamic vertex data, wouldn't it?

I was hoping that it would be more like this:


// Initialization (Once)

glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);

glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);

glBufferData(GL_ARRAY_BUFFER, size * sizeof(vertex_t), vertices, GL_DYNAMIC_DRAW);

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glVertexPointer(3, GL_FLOAT, sizeof(vertex_t), (GLvoid*)(0 * sizeof(vec3_t)));
glNormalPointer(GL_FLOAT, sizeof(vertex_t), (GLvoid*)(1 * sizeof(vec3_t)));
glColorPointer(4, GL_FLOAT, sizeof(vertex_t), (GLvoid*)(2 * sizeof(vec3_t)));
glTexCoordPointer(2, GL_FLOAT, sizeof(vertex_t), (GLvoid*)(2 * sizeof(vec3_t) + sizeof(vec4_t)));

glBindVertexArray(0);


// Update (Each Frame)

glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);

glBufferSubData(GL_ARRAY_BUFFER, 0, size * sizeof(vertex_t), vertices);

glBindVertexArray(0);


// Render (Each Frame)

glBindVertexArray(vao);
glBindTexture(GL_TEXTURE_2D, texture);

glDrawArrays(GL_TRIANGLES, 0, size);

glBindVertexArray(0);

However, it seems like I need to do this in order for it to work:


// Update (Each Frame)

glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);

glBufferSubData(GL_ARRAY_BUFFER, 0, size * sizeof(vertex_t), vertices);

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glVertexPointer(3, GL_FLOAT, sizeof(vertex_t), (GLvoid*)(0 * sizeof(vec3_t)));
glNormalPointer(GL_FLOAT, sizeof(vertex_t), (GLvoid*)(1 * sizeof(vec3_t)));
glColorPointer(4, GL_FLOAT, sizeof(vertex_t), (GLvoid*)(2 * sizeof(vec3_t)));
glTexCoordPointer(2, GL_FLOAT, sizeof(vertex_t), (GLvoid*)(2 * sizeof(vec3_t) + sizeof(vec4_t)));

glBindVertexArray(0);

Is this reallly necessary or am I doing something else wrong?

Share this post


Link to post
Share on other sites
Advertisement
You probably destroying some bindings, because you bind the vao in your update function.

glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);


with this code you are overwriting some stuff in the vao. I'm not quite sure why it won't work after this, but I guess this is the cause.

just get rid of those two vao bindings in you update function.

Share this post


Link to post
Share on other sites
Thank you for your suggestion. Unfortunately, if I don't bind the VAO during update I get really glitchy output. It looks like the data in the buffer is scrambled or some invalid/faulty data is being read.

FYI, I also tried this version:


// Initialization 1 (Once)

glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);

glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glVertexPointer(3, GL_FLOAT, sizeof(vertex_t), (GLvoid*)(0 * sizeof(vec3_t)));
glNormalPointer(GL_FLOAT, sizeof(vertex_t), (GLvoid*)(1 * sizeof(vec3_t)));
glColorPointer(4, GL_FLOAT, sizeof(vertex_t), (GLvoid*)(2 * sizeof(vec3_t)));
glTexCoordPointer(2, GL_FLOAT, sizeof(vertex_t), (GLvoid*)(2 * sizeof(vec3_t) + sizeof(vec4_t)));

glBindVertexArray(0);


// Initialization 2 (Once)

glBindBuffer(GL_ARRAY_BUFFER, vbo);

glBufferData(GL_ARRAY_BUFFER, size * sizeof(vertex_t), vertices, GL_DYNAMIC_DRAW);


// Update (Each Frame)

glBindBuffer(GL_ARRAY_BUFFER, vbo);

glBufferSubData(GL_ARRAY_BUFFER, 0, size * sizeof(vertex_t), vertices);


// Render (Each Frame)

glBindVertexArray(vao);
glBindTexture(GL_TEXTURE_2D, texture);

glDrawArrays(GL_TRIANGLES, 0, size);

glBindVertexArray(0);

Using this version, no geometry is visible at all (only the clear color). So it seems that the order of passing the data and setting up the VAO does matter.

Share this post


Link to post
Share on other sites
No more comments? Some input on the correct order of operations when using VAOs would already help a lot. Putting it in pseudo code, this is how I would expect things to work (but they don't):


Initialization:
Bind VAO
Bind Buffer
Upload Buffer Data
Enable Client States
Setup Pointers
Unbind VAO

Update/Render Loop:
Bind Buffer
Update Buffer Data

Bind VAO
Draw
Unbind VAO

Share this post


Link to post
Share on other sites
mm, dont really know whats wrong, but here some random stuff.

  • There is no need to generate, bind and submit data to the VBO while the VAO is active, they don't have anything to do with the VAO state
  • maybe check your stride and offset values(both are in bytes) again, look also at teh part of your code which fills your data array
  • use Stream_Draw when you are updating the buffer every frame
  • also when updating use this code, it's faster because the driver has less problems managing the memory
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, size * sizeof(vertex_t), null, GL_STREAM_DRAW);
    glBufferSubData(GL_ARRAY_BUFFER, 0, size * sizeof(vertex_t), vertices);




    here is some pseudo code how I do it:

    Initialization:
    Generate n BOs
    Bind first upload index data
    Bind other BO

    upload vertex data to it
    Loop until all vertex BOs are filled

    Generate VAO
    Bind VAO
    Bind Index Buffer
    Enable Client States

    Bind a BO
    Set all its vertex pointers
    Loop until all Attributs are set
    Unbind VAO

    Update/Render Loop:
    Bind BO which data changed
    upload data
    Loop until each BO is updated

    Bind VAO
    Set up render state (Textures, Shader, Uniforms, Lighting ...)
    render
    Unbind VAO

Share this post


Link to post
Share on other sites
Thanks again! It's very useful to have an example of how it should work. Unfortunately, I wont be able to implement all of your suggestions, because I am developing for iOS (OpenGL ES 1.1). This might also be the source of my problems - maybe there are some quirks with VAOs, which are only supported as an extension. However, I still find it more likely that the error is somewhere in my code.

I'm lead to believe that the stride and offset values are fine, because they work when I set them each time before rendering. Unfortunately GL_STREAM_DRAW is not available, so I can't try that. I'm really surprised that your suggested way of updating data should be faster - wouldn't it set all the data to zeros before writing the new data? (I'm not familiar with the effect of passing a null pointer in this context.)

In any case, I'll go through my code once again and compare it with the pseudo code you posted.

Share this post


Link to post
Share on other sites
the thing with calling it with null is that it tells the driver that u don't care anymore about the data.
So the new data get uploaded to an other address space then the old one. And the old gets deleted any time in the future

If u just upload new data the driver has to make sure that every operation on the old data has finished, then he has to sync everything and so on, which can take quite some time in a worst case.

Share this post


Link to post
Share on other sites

GL ES 1.1 supports VAO?

No. As I mentioned, the older iOS devices (GL ES 1.1) support it through an extension (see OpenGL ES Programming Guide for iOS - Platform Notes).

I've gotten a little sidetracked, as this was only supposed to be a slight optimization (it's one of the "best practices" in the aforementioned guide). When I come back to this, it would probably make sense to write a minimal example program demonstrating the problem...

Share this post


Link to post
Share on other sites
I see.

As for VAO, from what I understand, you only need to setup a VAO once. Then you use it with

glBindVertexArray(vao);
glDrawArrays or glDrawRangeElements or glDrawElements


I imagine that anything else can be considered a driver bug. Unfortunately, my experience is limited. I just did a test with VAO. I rendered 2 triangles with 2 different VAO just to make sure it works as I expect.
I am surprised we don't even have a decent example on the Wiki.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!