问题描述
我的应用程序在glDrawElements"(和 glDrawArrays)上崩溃.
我想知道崩溃的原因是什么?
目前我知道:
Foreach 网格- 绑定 VBO/VAO如果(VAO 为空)- 绑定 VAO(id)- 绑定 VBO(id)Foreach 属性- glEnableVertexAttribArray- glVertexAttribPointer结束 foreach- 解除绑定VAO(0)- 解除绑定VBO(0)Foreach 属性- glDisableVertexAttribArray结束 foreach万一- 绑定 IBO(id)- 绑定程序/着色器(id)->送制服->绘制元素结束 foreach
- 当我有很多 VBO/VAO/IBO 时,我的应用程序在 glDrawElements 上崩溃
- 使用不同的设备,当我有很多 VAO/VBO/IBO 时,我得到了奇怪的人工制品
我认为我的缓冲区有些奇怪(比如冲突),绑定的正确顺序是什么?我需要在哪里解绑 VAO、VBO、IBO、程序、纹理……?
当我删除一个几何体时,看起来崩溃了,他的缓冲区从 opengl 中删除了(因为我不再使用它们了).所以我认为我的缓冲区总是有界的.
OpenGL 跟踪:
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(目标 = GL_ARRAY_BUFFER,缓冲区 = 0)glBindBuffer(目标 = GL_ELEMENT_ARRAY_BUFFER,缓冲区 = 7)glUseProgram(程序= 0)glUseProgram(程序= 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, -1,0,70202.802.802.802.802.802.802.0.0.0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0.0.0.0.0.0.0.702.8022.1815264, 15.627364, 15.64632])glActiveTexture(纹理= GL_TEXTURE0)glBindTexture(目标 = GL_TEXTURE_2D,纹理 = 1)glUniform1i(位置 = 8,x = 0)glDisable(上限 = GL_BLEND)glBlendFunc(sfactor = GL_LINES, dfactor = GL_POINTS)glEnable(上限 = 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, -1.0.1])glUniform3fv(位置 = 3, 计数 = 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(模式= GL_TRIANGLE_STRIP,计数= 4,类型= GL_UNSIGNED_BYTE,索引= 0x0)
在解除绑定 VAO 之后, 不应禁用顶点属性数组.在 OpenGL 3 核心上下文中,当您解除绑定 VAO 时,您不再有可应用顶点数组命令的上下文;您必须始终绑定 VAO,否则这些命令将是无效操作.
此外,VAO 持久存储顶点数组状态.这个想法不是每次你画东西时都启用或禁用状态,你只需绑定一个已经设置了所有必要状态的 VAO.
以下是您应该如何考虑使用顶点数组对象设置顶点数组.由于 VAO 存储大部分状态,因此您不必执行诸如禁用顶点数组或取消绑定 VBO 之类的操作来防止状态泄漏.每当您想绘制不同的顶点数组时,只需更改绑定的 VAO.
阶段 1: GL 顶点数组/缓冲区对象初始化
网格构建时:- 生成 VAO、VBO、IBO- 绑定 VAO、VBO、IBO-> 上传顶点数据到 VBO-> 上传索引数组到 IBOForeach 属性 - 设置属性指针 (n)- 启用属性数组 (n)结束 Foreach第 2 阶段:绘制网格实例
当一个对象(网格的实例)被渲染时:- 绑定网格的 VAO- 绑定程序/着色器(id)-> 送制服-> glDrawElements此外,如果您的软件设置正确(例如,使用顶点数组绘制的所有内容都有自己的 VAO 来管理状态),那么取消绑定 VAO 确实是不必要的.考虑应用纹理,您很少会在绘制某些内容后解除绑定.您指望您绘制的下一批确切知道它需要什么纹理状态;如果它需要不同的纹理(或根本不需要),那么 it 应该是改变纹理状态的事情.在每批之后恢复纹理状态是一种资源浪费,恢复顶点数组状态也是如此.
附带说明一下,我正在查看您的 OpenGL 跟踪,并发现了您可能不知道的一些内容.您正在使用 GL_UNSIGNED_BYTE
索引,这些索引由 API 提供,但不一定由硬件支持.在许多硬件(例如任何桌面 GPU)上,GL_UNSIGNED_SHORT
是首选索引类型(即使对于非常小的顶点集合).当顶点少于 256 个时,很容易假设使用 GL_UNSIGNED_BYTE
将节省空间并因此增加吞吐量,但它实际上会使您脱离快速路径".如果硬件不支持 8 位索引,那么在您提交索引后,驱动程序不可避免地必须将索引转换为 16 位.在这种情况下,很遗憾,它会增加驱动程序的工作量并且不会节省任何 GPU 内存.
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)
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.
这篇关于glDrawElements 上的崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!