PDA

View Full Version : glBindVertexArray and glBufferSubData interactions



solosnake
08-14-2011, 09:30 AM
Hello

Can anyone please suggest to my why calling glBindVertexArray(0) at the end of the following code might cause no geometry to be drawn?

glBindBuffer( GL_ARRAY_BUFFER, instanceMatrixVBO_ );
glBufferSubData( GL_ARRAY_BUFFER, 0, renderCount * sizeof(modelinstancedata), instancesInfo + i );
glBindVertexArray( modelInfo.vertexArrayObject );
glDrawElementsInstanced( modelInfo.layout, modelInfo.indicesCount, GL_UNSIGNED_SHORT, 0, renderCount );
glBindVertexArray( 0 );

The last line "glBindVertexArray( 0 );" causes no geometry to be drawn - comment it out and it all works as expected.

The VBO "instanceMatrixVBO" is referenced in the setup of the "modelInfo.vertexArrayObject" VAO - does this raise any issues?

I think the issue is similar to the one mentioned here: www.gamedev.net/topic/597387-vao-is-it-necessary-to-redo-setup-each-time-buffer-data-changes/ (http://www.gamedev.net/topic/597387-vao-is-it-necessary-to-redo-setup-each-time-buffer-data-changes/) and is related to the uploading of the buffer data made in the loop.

Thanks.

BionicBytes
08-15-2011, 02:30 AM
I'm no expert on VAO since I don't actually use them.
However, your problem appears to be one of ordering.
The VAO binding has to come first so that your buffer upload is updated after selecting the VAO.


glBindBuffer( GL_ARRAY_BUFFER, instanceMatrixVBO_ );
glBufferSubData( GL_ARRAY_BUFFER, 0, renderCount * sizeof(modelinstancedata), instancesInfo + i );
glBindVertexArray( modelInfo.vertexArrayObject );

becomes


glBindVertexArray( modelInfo.vertexArrayObject );
glBindBuffer( GL_ARRAY_BUFFER, instanceMatrixVBO_ );
glBufferSubData( GL_ARRAY_BUFFER, 0, renderCount * sizeof(modelinstancedata), instancesInfo + i );

Now you can unbind the VAO with
glBindVertexArray( 0 );
... if you so wish.

solosnake
08-15-2011, 02:58 AM
Thanks,

I will try this later tonight and see if it works or changes anything, however I *think* I tried this earlier and it didnt actually fix it.

Even if it works, it doesn't fully explain *why* my approach isn't working, or why just unbinding the VAO causes no geometry to appear?

I've printed the relevant topics in the 3.3 specs and will also go through them to try to understand how the updating of buffers thats are referenced in VAOs works.

Some questions:
Can I update the contents of a VB which is referenced by a VAO while that VAO is not currently bound? Does uploading new buffer data to a VB referenced by a VAO in any way affect the other contents of the VAO, or any state of the VAO?Thanks for your help!

PS: Yes I do need to unbind the VAO as the intention is to have a multipass renderer.

elFarto
08-15-2011, 06:56 AM
I think you're problem is that your VAO isn't setup correctly, and binding it is causing the GL_ARRAY_BUFFER attachment point to be clobbered.

Commenting the glBindVertexArray(0); call means the next time round, glBindBuffer will be called with the VAO bound, effectively fixing the VAO.

Can you post your VAO setup code?

Regards
elFarto

solosnake
08-15-2011, 10:10 AM
Hello

Here is the code I use to setup the VAO shown in the above code. (Code is posted as is).

glGenVertexArrays( 1, &details_.vertexArrayObject );

// The resource freeing assumes we correctly pass this point, so
// test that this assumption is upheld here:
if( details_.vertexArrayObject != 0 )
{
glGenBuffers( 2, buffers_ );

// Create the IBO, 16 bit indices
details_.indicesCount = geom->index_count();
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, buffers_[0] );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, details_.indicesCount * sizeof(GLushort), geom->indices(), GL_STATIC_DRAW );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );

// Create VBO
const GLsizeiptr vertexSize = geom->vertex_count() * 3 * sizeof(GLfloat);
const GLsizeiptr texCoordSize = geom->vertex_count() * 2 * sizeof(GLfloat);
const GLsizeiptr bufferSize = texCoordSize + vertexSize;

const GLsizei instanceDataBlockStride = sizeof(modelinstancedata);
const size_t rowSize = sizeof(float) * 4;

glBindBuffer( GL_ARRAY_BUFFER, buffers_[1] );
glBufferData( GL_ARRAY_BUFFER, bufferSize, nullptr, GL_STATIC_DRAW );
glBufferSubData( GL_ARRAY_BUFFER, 0, vertexSize, geom->vertices() );
glBufferSubData( GL_ARRAY_BUFFER, vertexSize, texCoordSize, texs->texture_coords() );
glBindBuffer( GL_ARRAY_BUFFER, 0 );

// VAO for the model
glBindVertexArray( details_.vertexArrayObject );

// Bind the IBO for the VAO
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, buffers_[0] );

// Bind the VBO and setup pointers for the VAO
glBindBuffer( GL_ARRAY_BUFFER, buffers_[1] );

glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) );
glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(vertexSize) );

// Bind the VBO for the incoming instance data:
glBindBuffer( GL_ARRAY_BUFFER, instanceMatrixVBO ); << This is the VBO being updated in the code shown in my 1st post...

// First matrix:
glVertexAttribPointer( 2, 4, GL_FLOAT, GL_FALSE, instanceDataBlockStride, BUFFER_OFFSET(0) );
glVertexAttribPointer( 3, 4, GL_FLOAT, GL_FALSE, instanceDataBlockStride, BUFFER_OFFSET(rowSize * 1) );
glVertexAttribPointer( 4, 4, GL_FLOAT, GL_FALSE, instanceDataBlockStride, BUFFER_OFFSET(rowSize * 2) );
glVertexAttribPointer( 5, 4, GL_FLOAT, GL_FALSE, instanceDataBlockStride, BUFFER_OFFSET(rowSize * 3) );

// Team colour:
glVertexAttribPointer( 6, 4, GL_UNSIGNED_BYTE, GL_TRUE, instanceDataBlockStride, BUFFER_OFFSET(rowSize * 4) );

// Finished with this models VAO:
glBindVertexArray( 0 );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );


This is the setup for the VAO, one per model, for use in instance rendering. The matrices are passed in via a VBO shared by one or more VAOs. The VBO is created beforehand like this:

glGenBuffers( 1, &amp;instanceMatrixVBO_ );
glBindBuffer( GL_ARRAY_BUFFER, instanceMatrixVBO_ );
glBufferData( GL_ARRAY_BUFFER, MAX_INSTANCES_PER_BATCH * sizeof(modelinstancedata), nullptr, GL_STREAM_DRAW );
glBindBuffer( GL_ARRAY_BUFFER, 0 );

Thanks for your time and input, its really appreciated.

At no time during the running does OpenGL generate any errors. I am very frequently checking for this.

Also, I tested the above suggestion to reorder the calls, it does not fix my issue.

solosnake
08-15-2011, 02:04 PM
elFarto I think you were right.

I have it working now :) The VAO did not have the glEnableVertexAttribArray and glVertexAttribDivisor components set correctly (I did not realise these were stored as state in the VAO, however I see now that they are). Previously I was setting this part before binding the VAO, and it must just have been working because after the first call the VAO was bound and my calling glVertexAttribDivisor "fixed" the VAO.

I intend to post the entire renderer code when its done, sometime in the next month or two.

Many thanks guys.

elFarto
08-15-2011, 02:05 PM
I'm at a bit of a loss, that code looks fine. Prehaps you need a few calls to glEnableVertexAttribArray for you VAO.

*edit* Heh, you beat me to the solution by a minute :)

Regards
elFarto