Crash on glDrawElements

opengl

My application is crashing on "glDrawElements" (and glDrawArrays).

I would like to know, what can be the cause of the crash?

Currently I've got that:

Foreach mesh

     - Bind VBO/VAO

           if( VAO empty )

                - bind VAO(id)
                - bind VBO(id)

                Foreach attribs
                    - glEnableVertexAttribArray
                    - glVertexAttribPointer
                End foreach

                - unbindVAO(0)
                - unbindVBO(0)

                Foreach attribs
                    - glDisableVertexAttribArray
                End foreach

            endif

     - Bind IBO(id)

     - Bind program/shader(id)
        -> send uniforms

     -> glDrawElements

End foreach
  • My application crash on glDrawElements when I've got many VBO/VAO/IBO
  • With different devices, I've got strange artefact when I've got many VAO/VBO/IBO

I think there is something strange with my buffers (like a conflict), what is the correct order for bindings? Where I need to unbind VAO,VBO,IBO,Program, Texture, … ?

EDIT:

It's look like the crash appear when I delete a geometry, his buffers are removed from opengl (because I don't use them anymore). So I think my buffers are always bounded Oo.

OpenGL Trace:

glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 8)
glEnableVertexAttribArray(index = 2)
glVertexAttribPointer(indx = 2, size = 3, type = GL_FLOAT, normalized = false, stride = 20, ptr = 0x0)
glEnableVertexAttribArray(index = 0)
glVertexAttribPointer(indx = 0, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 20, ptr = 0xc)
glEnableVertexAttribArray(index = 4)
glVertexAttribPointer(indx = 4, size = 2, type = GL_UNSIGNED_SHORT, normalized = true, stride = 20, ptr = 0x10)
glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 0)
glBindBuffer(target = GL_ELEMENT_ARRAY_BUFFER, buffer = 7)
glUseProgram(program = 0)
glUseProgram(program = 6)
glUniformMatrix4fv(location = 2, count = 1, transpose = false, value = [1.6974937, 0.0, 0.0, 0.0, 0.0, 2.100419, -0.49304545, -0.49301255, 0.0, -1.1902374, -0.87008023, -0.8700222, -9.582167, -2.1815264, 15.627364, 15.64632])
glActiveTexture(texture = GL_TEXTURE0)
glBindTexture(target = GL_TEXTURE_2D, texture = 1)
glUniform1i(location = 8, x = 0)
glDisable(cap = GL_BLEND)
glBlendFunc(sfactor = GL_LINES, dfactor = GL_POINTS)
glEnable(cap = GL_DEPTH_TEST)
glUniformMatrix4fv(location = 7, count = 1, transpose = false, value = [50.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 50.0, 0.0, 0.0, -0.1, -150.0, 1.0])
glUniform3fv(location = 3, count = 1, v = [0.8235294, 0.8235294, 0.8235294])
glUniform2fv(location = 0, count = 1, v = [0.0, 0.0])
glUniform2fv(location = 1, count = 1, v = [1.0, 1.0])
glDrawElements(mode = GL_TRIANGLE_STRIP, count = 4, type = GL_UNSIGNED_BYTE, indices = 0x0)

Best Answer

You should not disable vertex attrib arrays after unbinding a VAO. In an OpenGL 3 core context, the second you unbind a VAO you no longer have a context for vertex array commands to apply to; you must always have a VAO bound or these commands will be invalid operations.

Moreover, VAOs store vertex array state persistently. The idea is instead of enabling or disabling states every time you draw something, you just bind a VAO that has all of the necessary states already setup.

Here is how you should be thinking about setting up vertex arrays using Vertex Array Objects. Since the VAO stores most of the state, you do not have to do things like disable vertex arrays or unbind VBOs to prevent state leaks. Just change the bound VAO whenever you want to draw a different vertex array.

Stage 1: GL Vertex Array / Buffer Object Initialization

When Mesh is Constructed:

  - Generate VAO, VBO, IBO
  - Bind     VAO, VBO, IBO

   -> Upload Vertex Data to VBO
   -> Upload Index Array to IBO

  Foreach Attribute <n>
    - Setup  Attrib Pointer (n)
    - Enable Attrib Array   (n)
  End Foreach  

Stage 2: Drawing a Mesh Instance

When an Object (instance of Mesh) is Rendered:

  - Bind Mesh's VAO

  - Bind program/shader(id)
    -> send uniforms

  -> glDrawElements

Also, unbinding a VAO is really unnecessary if your software is setup correctly (e.g. everything that draws using vertex arrays has its own VAO to manage state). Think of applying textures, you rarely unbind a texture after you draw something. You count on the next batch you draw knowing exactly what texture state(s) it needs; if it needs a different texture (or none at all), then it should be the thing to change the texture state. Restoring texture state after every batch is a waste of resources, and so is restoring vertex array state.


On a side note, I was looking at your OpenGL trace and came across something you may not be aware of. You are using GL_UNSIGNED_BYTE indices, which are provided by the API but not necessarily supported by hardware. On a lot of hardware (e.g. any desktop GPU) GL_UNSIGNED_SHORT is the preferred index type (even for very small collections of vertices). It is tempting to assume that using GL_UNSIGNED_BYTE will save space and therefore increase throughput when you have fewer than 256 vertices, but it can actually throw you off the "fast path." If the hardware does not support 8-bit indices, then the driver is inevitably going to have to convert your indices to 16-bit after you submit them. In such cases, it increases driver workload and does not save any GPU memory, sadly.

Related Topic