为什么 glDeleteBuffers 和 glDeleteVertexArrays 这么慢?
Why are glDeleteBuffers and glDeleteVertexArrays so slow?
在我的程序流程中的某个时刻,我生成了 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 and glDeleteBuffers are designed to only be run on initialization and cleanup, respectively. Calling them during runtime is bad.
但我不确定如何在不调用上述函数的情况下摆脱这些 VBO 和 VAO。
我想过将所有要删除的网格添加到队列中,并且每帧只删除其中的几个,慢慢清空队列,但这并不是正确的解决方案。我想到的另一个(可能的)解决方案是使用实例化渲染,但据我所知,当我每帧进行 1000 次以下绘制调用时,非实例化渲染也应该可以正常工作。我的程序在任何给定时间都不会有超过 1000 个网格对象,我什至不确定这会解决我的问题。
更新:除了下面的回答给我指明了正确的方向外,我还发现我实际上并没有删除 ~0-300 个 VBO,而是 48 的一个因子更多的!难怪性能被扼杀了。因此,如果其他人遇到同样的问题,请彻底检查您的代码执行的 glDeleteBuffers 数量。
你在那里遇到了一些心理障碍。您似乎认为 "per mesn: {one vertex attribute == one VBO}",但这不是它应该如何工作的。您应该做的是使用一个单一的大型 VBO,并将其用作您分配块的内存池,每个块都包含一些数据。
因此,您不仅将单个网格的所有顶点属性放入一个公共 VBO 中,还将多个网格放入一个 VBO 中。
另外,您似乎在每次渲染迭代时都在创建和删除 VBO 和 VAO。为什么?网格是否在每一帧之间发生显着变化?如果是这样,那一定是癫痫导致了观看;烘焙到几何数据中的网格变形不需要重新创建缓冲区,您只需用 glBufferSubData
.
覆盖数据
在我的程序流程中的某个时刻,我生成了 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 and glDeleteBuffers are designed to only be run on initialization and cleanup, respectively. Calling them during runtime is bad.
但我不确定如何在不调用上述函数的情况下摆脱这些 VBO 和 VAO。
我想过将所有要删除的网格添加到队列中,并且每帧只删除其中的几个,慢慢清空队列,但这并不是正确的解决方案。我想到的另一个(可能的)解决方案是使用实例化渲染,但据我所知,当我每帧进行 1000 次以下绘制调用时,非实例化渲染也应该可以正常工作。我的程序在任何给定时间都不会有超过 1000 个网格对象,我什至不确定这会解决我的问题。
更新:除了下面的回答给我指明了正确的方向外,我还发现我实际上并没有删除 ~0-300 个 VBO,而是 48 的一个因子更多的!难怪性能被扼杀了。因此,如果其他人遇到同样的问题,请彻底检查您的代码执行的 glDeleteBuffers 数量。
你在那里遇到了一些心理障碍。您似乎认为 "per mesn: {one vertex attribute == one VBO}",但这不是它应该如何工作的。您应该做的是使用一个单一的大型 VBO,并将其用作您分配块的内存池,每个块都包含一些数据。
因此,您不仅将单个网格的所有顶点属性放入一个公共 VBO 中,还将多个网格放入一个 VBO 中。
另外,您似乎在每次渲染迭代时都在创建和删除 VBO 和 VAO。为什么?网格是否在每一帧之间发生显着变化?如果是这样,那一定是癫痫导致了观看;烘焙到几何数据中的网格变形不需要重新创建缓冲区,您只需用 glBufferSubData
.