Search code examples
opengljogl

Why glBufferSubData for element buffer must be called outside of glBindVertexArray?


I'm trying to replace contents of element buffer in this hello world example https://github.com/jvm-graphics-labs/hello-triangle/blob/master/src/main/java/gl4/HelloTriangleSimple.java and I managed to do it with some minor changes by using glBufferSubData, but I'm curious about one peculiarity - in my display method I have to call glBufferSubData before I call glBindVertexArray:

gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName.get(Buffer.ELEMENT));
elementBuffer.rewind();
elementBuffer.put(elementData).rewind();
gl.glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, elementBuffer.capacity() * Short.BYTES, elementBuffer);
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
gl.glBindVertexArray(vertexArrayName.get(0));

If I do it after glBindVertexArray, I'm getting only black window. The strange thing is that GL_ARRAY_BUFFER can be updated after glBindVertexArray. What is the difference between vertex buffer and element buffer behind this observation?


Solution

  • The GL_ELEMENT_ARRAY_BUFFER object is stored in the vertex array objects state vector.

    If a Vertex Array Object is bound the an element buffer can be attached to it by

    gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName.get(Buffer.ELEMENT));
    

    But if you do

    gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
    

    then the name of the element buffer object is replaced by 0 and the reference to the elements is broken. This causes that gl.drawElements won't work any more for the this VAO, because it doesn't refer to any index list.


    Further note, there is always a vertex array object. The vertex array object 0 is the default vertex array object which is only valid when you use a compatibility profile context (not core).

    This means that

    gl.glBindVertexArray(0);
    gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName.get(Buffer.ELEMENT));
    

    will associate a element buffer to the default vertex array object (0). This is perfectly valid in compatibility profile context.


    See the OpenGL 4.6 API Compatibility Profile Specification; 10.3.1 Vertex Array Objects; page 393:

    The name space for vertex array objects is the unsigned integers, with zero reserved by the GL to represent the default vertex array object. The command

    void GenVertexArrays( sizei n, uint *arrays );
    

    returns n previous unused vertex array object names in arrays.

    ...

    A vertex array object is created by binding a name returned by GenVertexArray with the command

    void BindVertexArray( uint array );
    

    array is the vertex array object name. The resulting vertex array object is a new state vector, comprising all the state and with the same initial values listed in tables 23.3 and 23.4.
    BindVertexArray may also be used to bind an existing vertex array object. If the bind is successful no change is made to the state of the bound vertex array object, and any previous binding is broken.

    Table 23.4, Vertex Array Object State
    ELEMENT_ARRAY_BUFFER_BINDING, VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, VERTEX_ATTRIB_BINDING, VERTEX_ATTRIB_RELATIVE_OFFSET, VERTEX_BINDING_OFFSET, VERTEX_BINDING_STRIDE, VERTEX_BINDING_DIVISOR, VERTEX_BINDING_BUFFER.