Reputation: 1051
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
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)
Upvotes: 1
Views: 6792
Reputation: 43369
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.
Upvotes: 3
Reputation: 17396
If a buffer is bound to GL_ARRAY_BUFFER when you call glVertexAttribPointer, the pointer is taken to be an offset within the buffer. Otherwise it's taken to be a pointer to system memory. Thus, if there's no buffer bound and you pass an invalid pointer such as zero (expecting a buffer is bound), GL attempts an invalid read and the program crashes.
The same thing for glDrawElements, if a buffer is bound to GL_ELEMENT_ARRAY_BUFFER the pointer argument is taken to be an offset within the buffer.
Here, GL_ARRAY_BUFFER buffers only need to be bound during gl*Pointer() calls and GL_ELEMENT_ARRAY_BUFFER during glDrawElements() calls.
Enabling a client state Calling glEnableVertexAttribArray and not supplying a pointer will also cause a crash.
edit
I believe a VAO simply records the configuration of vertex attributes arrays, bound buffers and the pointers into those buffers. To use, bind the VAO before setting up everything as though you were going to make a draw call, then unbind. Now when ever you bind that VAO, the state is restored and you can simply make a draw call without a huge bunch of GL calls.
bind VAO
for each attrib,
call glEnableVertexAttribArray //in the next draw call, use the VBO I'm about to set up.
bind VBO
call glVertexAttribPointer //use data in bound VBO with size,stride,offset
unbind VBOconfig
end for
unbind VAO
//not certain but are attrib arrays still enabled after unbinding VAO (maybe disabling is unnecessary)
now for a draw call, bind the VAO, draw(), unbind.
Lastly, for glEnableVertexAttribArray and glVertexAttribPointer I don't know but does the index need to be the uniform variable location?
Upvotes: 0