崩溃glDrawElements

时间:2013-08-23 13:09:31

标签: opengl

我的应用程序崩溃了“glDrawElements”(和glDrawArrays)。

我想知道,崩溃的原因是什么?

目前我已经拥有:

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
  • 当我有很多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(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)

2 个答案:

答案 0 :(得分:3)

在解除绑定VAO之后,不应禁用顶点属性数组。在OpenGL 3核心上下文中,第二个取消绑定VAO,您不再具有要应用的顶点数组命令的上下文;你必须总是有一个VAO绑定或这些命令将是无效的操作。

此外,VAO持久存储顶点数组状态。这个想法不是每次绘制东西时都启用或禁用状态,而是绑定一个已经设置了所有必要状态的VAO。

以下是您应该如何考虑使用Vertex Array Objects设置顶点数组。由于VAO存储了大部分状态,因此您无需执行禁用顶点数组或取消绑定VBO以防止状态泄漏的操作。只要想要绘制不同的顶点数组,只需更改绑定的VAO即可。

阶段1: GL顶点数组/缓冲区对象初始化

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  

第2阶段:绘制网格实例

When an Object (instance of Mesh) is Rendered:

  - Bind Mesh's VAO

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

  -> glDrawElements

此外,如果您的软件设置正确(例如,使用顶点阵列绘制的所有内容都有自己的VAO来管理状态),则实际上不需要解除绑定VAO。考虑应用纹理,在绘制内容后很少取消绑定纹理。你指望下一批你知道它需要什么样的纹理状态;如果它需要不同的纹理(或根本不需要),那么 it 应该是改变纹理状态的东西。在每批次之后恢复纹理状态是浪费资源,因此恢复顶点阵列状态。


在旁注中,我正在查看您的OpenGL跟踪并遇到了您可能不知道的事情。您正在使用GL_UNSIGNED_BYTE索引,这些索引由API提供,但不一定由硬件支持。在许多硬件(例如任何桌面GPU)上GL_UNSIGNED_SHORT是首选索引类型(即使对于非常小的顶点集合)。很容易假设使用GL_UNSIGNED_BYTE会节省空间,因此当你的顶点数少于256时会增加吞吐量,但它实际上可以让你离开“快速路径”。如果硬件不支持8位索引,那么驱动程序不可避免地必须在提交
之后将索引转换为16位。在这种情况下,它会增加驱动程序的工作量,并且不会遗漏任何GPU内存。

答案 1 :(得分:0)

如果在调用glVertexAttribPointer时缓冲区绑定到GL_ARRAY_BUFFER,则指针将被视为缓冲区内的偏移量。否则它被认为是指向系统内存的指针。因此,如果没有缓冲区绑定并且您传递了无效指针(例如零(期望绑定了缓冲区)),GL会尝试无效读取并且程序崩溃。

glDrawElements也是如此,如果缓冲区绑定到GL_ELEMENT_ARRAY_BUFFER,则指针参数将被视为缓冲区内的偏移量。

这里,GL_ARRAY_BUFFER缓冲区只需要在gl * Spinter()调用期间绑定gl * Pointer()和GL_ELEMENT_ARRAY_BUFFER。

启用客户端状态调用glEnableVertexAttribArray而不提供指针也会导致崩溃。

修改

我相信VAO只是记录顶点属性数组,绑定缓冲区和指向这些缓冲区的指针的配置。要使用,请在设置所有内容之前绑定VAO,就像打算进行绘制调用一样,然后取消绑定。现在,当你绑定那个VAO时,状态就会恢复,你可以简单地进行一次绘制调用而不需要大量的GL调用。

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)

现在进行绘制调用,绑定VAO,绘制(),解除绑定。

最后,对于glEnableVertexAttribArray和glVertexAttribPointer我不知道,但索引是否需要是统一变量位置?