Почему glDeleteBuffers и glDeleteVertexArrays такие медленные? - PullRequest
0 голосов
/ 27 апреля 2019

В какой-то момент в потоке моей программы я генерирую от 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 кадров в секунду, и удаление 70 из этих объектов сетки занимает около 30 мс (и удаление 110 из нихзанимает 75 мс).Это создает заметный сбой в производительности, поскольку один кадр должен занимать максимум ~ 16 мс.

Разве это не правильный способ избавиться от VBO и VAO?Я прочитал в другом вопросе ( glDeleteBuffers медленнее, чем glBufferData ), что

glGenBuffers и glDeleteBuffers предназначены для запуска только при инициализации и очистке, соответственно.Вызывать их во время выполнения плохо.

, но я не уверен, как можно избавиться от этих VBO и VAO без вызова вышеуказанных функций.

Я думал о добавлении всех мешей-to-быть-удаленным в очередь и удаляющим только пару из них каждый кадр, медленно опустошая очередь, но это не похоже на правильное решение.Другое (возможное) решение, о котором я подумал, - это использование экземпляра рендеринга, но, насколько я понимаю, когда я выполняю до 1000 вызовов отрисовки на кадр, неэкземплярный рендеринг тоже должен работать нормально.В моей программе никогда не будет намного больше 1000 объектов Mesh в любой момент времени, и я даже не уверен, что это решит мою проблему.

ОБНОВЛЕНИЕ: Помимо приведенного ниже ответа, указывающего мне в правильном направлении, ятакже обнаружил, что я на самом деле не удаляю ~ 0-300 VBO, но с коэффициентом 48 больше!Не зря представление было убито.Поэтому, если у кого-то еще возникла такая же проблема, тщательно проверьте количество glDeleteBuffers, которое выполняет ваш код.

1 Ответ

3 голосов
/ 27 апреля 2019

Вы столкнулись с каким-то умственным препятствием.Кажется, вы думаете, что "per mesn: {один атрибут вершины == один VBO}" , но это не так, как это должно работать.Вам нужно использовать один большой VBO и использовать в качестве пула памяти, из которой вы выделяете чанки, каждый из которых содержит некоторые данные.

Таким образом, вы помещаете не только все атрибуты вершины одной сетки вобычный VBO, вы также помещаете несколько сеток в один VBO.

Также создается впечатление, что вы создаете и удаляете свои VBO и VAO на каждой итерации рендеринга.Зачем?Меняются ли сетки между каждым кадром?Если это так, это должно вызывать эпилепсию;деформации сетки, вставленные в данные геометрии, не требуют воссоздания буферов, вы просто перезаписываете данные с помощью glBufferSubData.

...