glTexSubImage2D очень медленно на видеокарте Intel - PullRequest
10 голосов
/ 18 октября 2011

Моя видеокарта - мобильная Intel 4 серии.Я обновляю текстуру, меняя данные каждый кадр, вот мой основной цикл:

for(;;) {
    Timer timer;

    glBindTexture(GL_TEXTURE2D, tex);
    glBegin(GL_QUADS); ... /* draw textured quad */ ... glEnd();
    glTexSubImage2D(GL_TEXTURE2D, 0, 0, 0, 512, 512,
        GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
    swapBuffers();

    cout << timer.Elapsed();
}

Каждая итерация занимает 120 мс.Тем не менее, вставка glFlush до glTexSubImage2D приводит к увеличению времени итерации до 2 мс.

Проблема не в формате пикселя. Я пробовал использовать форматы пикселей BGRA, RGBA и ABGR_EXT вместе с пикселем.типы UNSIGNED_BYTE, BYTE, UNSIGNED_INT_8_8_8_8 и UNSIGNED_INT_8_8_8_8_EXT.Внутренний пиксельный формат текстуры - RGBA.

Порядок вызовов имеет значение. Перемещение загрузки текстуры перед четырехугольным рисунком, например, исправляет медлительность.

Я такжепопробовал это на карте GeForce GT 420M, и там он работает быстро.У моего реального приложения есть проблемы с производительностью на картах не-Intel, которые исправляются вызовами glFlush, но я еще не перевел их в тестовый пример.

Есть какие-нибудь идеи о том, как это отладить?

Ответы [ 3 ]

5 голосов
/ 18 октября 2011

Одна проблема заключается в том, что glTexImage2D выполняет полную повторную инициализацию объекта текстуры.Если изменяются только данные, но формат остается тем же, используйте glTexSubImage2D, чтобы ускорить процесс (просто напоминание).

Другая проблема заключается в том, что, несмотря на название, непосредственный режим, т.е. glBegin (…)… GlEnd () вызовы рисования не являются синхронными, то есть вызовы возвращаются задолго до того, как графический процессор завершил рисование.Добавление glFinish () синхронизирует.Но также будет делать вызовы ко всему, что изменяет данные, все еще необходимые для операций с очередями.Так что в вашем случае glTexImage2D (и glTexSubImage2D) должны ждать завершения рисования.

Обычно лучше всего делать все загрузки энергозависимых ресурсов либо в начале функции рисования, либо во время блока SwapBuffers в отдельном потокечерез буферные объекты.Именно по этой причине были введены буферные объекты, чтобы обеспечить асинхронную, но напряженную работу.

3 голосов
/ 18 октября 2011

Я предполагаю, что вы на самом деле используете эту текстуру для одного или нескольких ваших квадов?

Загрузка текстур - одна из самых дорогих операций. Поскольку ваши данные текстуры меняются каждый кадр, загрузка неизбежна, но вы должны попытаться сделать это, когда текстура не используется шейдерами. Помните, что glBegin(GL_QUADS); ... glEnd(); на самом деле не рисует квадр, а запрашивает, чтобы графический процессор отображал квадр. До завершения рендеринга текстура будет заблокирована. В зависимости от реализации это может привести к ожиданию загрузки текстуры (ala glFlush), но это также может привести к сбою загрузки, и в этом случае вы теряете мегабайты пропускной способности PCIe и драйвер должен повторить попытку.

Похоже, у вас уже есть решение: загрузите все новые текстуры в начале кадра. Так какой у тебя вопрос?

ПРИМЕЧАНИЕ. Встроенная графика Intel в любом случае ужасно медленная.

1 голос
/ 18 октября 2011

Когда вы делаете вызов Draw (glDrawElements, прочее), драйвер просто добавляет этот вызов в буфер и позволяет графическому процессору использовать эти команды, когда это возможно.

Если этот буфер должен был использоваться полностьюна glSwapBuffers это будет означать, что после этого графический процессор будет простаивать, ожидая, пока вы отправите новые команды.

Драйверы решают эту проблему, позволяя графическому процессору отставать на один кадр.Это первая причина, по которой блокируется glTexSubImage2D: драйвер ждет, пока графический процессор больше не использует его (в предыдущем кадре) для начала передачи, так что вы никогда не получите полуобновленные данные.

Другая причина в том, что glTexSubImage2D является синхронным.Il также будет блокировать в течение всей передачи.

  • Вы можете решить первую проблему, сохранив 2 текстуры: одну для текущего кадра, другую для предыдущего кадра.Загрузите текстуру в первом, но рисуйте вторым.
  • Вторую проблему можно решить с помощью объекта буфера GL_TEXTURE_BUFFER, который допускает асинхронную передачу.

В вашем случаеЯ подозреваю, что вызов glTexSubImage2D непосредственно перед тем, как glSwapBuffer добавляет дополнительную синхронизацию в драйвере, тогда как рисование четырехугольника перед тем, как glSwapBuffer просто добавляет команду в буфер.120 мс - это, вероятно, ошибка драйвера: даже Intel GMA не требуется 120 мс для загрузки текстуры 512x512.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...