为什么glDeleteBuffers和glDeleteVertexArrays这么慢?

时间:2019-04-27 09:43:42

标签: opengl lwjgl vbo vao

在程序流程的某个时刻,我会生成0到300个网格之间的任意位置,每个网格都像这样:

public Mesh(float[] vertices, byte[] indices, float[] textureCoordinates)
{
    vao = glGenVertexArrays();
    glBindVertexArray(vao);

    vbo = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, BufferUtils.createFloatBuffer(vertices), GL_STATIC_DRAW);
    glVertexAttribPointer(ShaderProgram.VERTEX_ATTRIB, 3, GL_FLOAT, false, 0, 0);
    glEnableVertexAttribArray(ShaderProgram.VERTEX_ATTRIB);

    tbo = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, tbo);
    glBufferData(GL_ARRAY_BUFFER, BufferUtils.createFloatBuffer(textureCoordinates), GL_STATIC_DRAW);
    glVertexAttribPointer(ShaderProgram.TCOORD_ATTRIB, 2, GL_FLOAT, false, 0, 0);
    glEnableVertexAttribArray(ShaderProgram.TCOORD_ATTRIB);

    ibo = glGenBuffers();
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, BufferUtils.createByteBuffer(indices), GL_STATIC_DRAW);

    glBindVertexArray(0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

当用户按下按钮时,这些网格物体需要再次删除,因此我对这些网格物体中的每个对象运行清理方法:

public void cleanup()
{
        glDeleteBuffers(vbo);
        glDeleteBuffers(tbo);
        glDeleteBuffers(ibo);
        glDeleteVertexArrays(vao);
}

问题是我试图以60 fps的速度运行,删除这些网格对象中的70个大约需要30毫秒(删除其中的110个对象需要75毫秒)。这会造成明显的性能问题,因为一帧最多需要16毫秒。

这不是处置VBO和VAO的正确方法吗?我在另一个问题(glDeleteBuffers slower than glBufferData)中读到了

  

glGenBuffers和glDeleteBuffers分别设计为仅在初始化和清除时运行。在运行时调用它们是不好的。

但是我不确定如何在不调用上述函数的情况下摆脱这些VBO和VAO。

我已经考虑过将所有要删除的网格物体添加到队列中,并且每帧仅删除其中的几个网格物体,然后慢慢清空队列,但这似乎不是正确的解决方案。我想到的另一个(可能)解决方案是使用实例渲染,但是据我了解,当我每帧进行1000次以下绘画调用时,非实例渲染也应该可以正常工作。我的程序在任何给定时间都不会有超过1000个Mesh对象,而且我什至不确定这是否可以解决我的问题。

更新:除了下面给出正确方向的答案外,我还发现我实际上并没有删除〜0-300个VBO,而是增加了 48 个因素!难怪表演被杀死了。因此,如果其他任何人遇到同样的问题,请彻底检查您的代码正在执行的glDeleteBuffers数量。

1 个答案:

答案 0 :(得分:3)

您在这里遇到了一些精神障碍。您似乎认为“每一个消息:{一个顶点属性==一个VBO}” ,但这并不是它应该工作的方式。您应该做的是使用一个大型VBO,并将其用作一个内存池,从中分配大块,每个大块都保存一些数据。

因此,您不仅将单个网格的所有顶点属性都放入了一个普通的VBO中,而且还将多个网格都放入了一个VBO中。

同样,您似乎在每个渲染迭代中都创建和删除VBO和VAO。为什么?网格在每一帧之间是否会发生巨大变化?如果是这样,那一定是癫痫症引起的注意。烘焙到几何数据中的网格变形不需要重新创建缓冲区,只需使用glBufferSubData覆盖数据即可。