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
Stage 2: Drawing a Mesh Instance
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 usingGL_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.