glBufferSubData работает очень медленно на многих устройствах Android

#opengl-es #opengl-es-2.0 #opengl-es-3.0

#opengl-es #opengl-es-2.0 #opengl-es-3.0

Вопрос:

Я запросил около 2 миллионов буферов gl для общего доступа и обновил данные для вершины и индекса с помощью glBufferSubData, это отлично работает на моих устройствах iOS. в то время как, когда я тестирую его на своих устройствах Android, он работает очень-очень медленно.

Я нашел несколько заметок с официального сайта: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBufferSubData.xhtml

что на самом деле означает «этот рендеринг должен выйти из конвейера, прежде чем хранилище данных сможет быть обновлено»?

Комментарии:

1. » Я запросил около 2 миллионов буферов gl для общего доступа » Вы имеете в виду, что у вас есть буфер размером 2 МБ, или что у вас на самом деле есть 2 миллиона отдельных буферов?

2. всего один буфер размером 2 МБ

Ответ №1:

Разница в производительности, которую вы видите, скорее всего, связана не просто с различием iOS / Android, а будет очень специфичной как для вашего использования API, так и для реализации glBufferSubData в драйвере. Не видя больше кода или не зная, какие показатели производительности вы собираете, трудно комментировать дальше.

что на самом деле означает «этот рендеринг должен выйти из конвейера, прежде чем хранилище данных сможет быть обновлено»?

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

Рассмотрим следующий пример. В хорошем случае у нас может быть что-то вроде этого:

  • glBufferSubData в буфер 1 с помощью ABCDE
  • Вызов Draw с использованием буфера 1
  • glBufferSubData в буфер 2 с помощью FGHIJ
  • Вызов Draw с использованием буфера 2
  • Буферы подкачки <—— Точка синхронизации, драйвер должен дождаться завершения рендеринга перед заменой буферов

Однако, если вы перезаписываете тот же буфер, вы получите это вместо.

  • glBufferSubData в буфер 1 с помощью ABCDE
  • Вызов Draw с использованием буфера 1
  • glBufferSubData в буфер 1, перезаписывая с помощью FGHIJ <—— Точка синхронизации, поскольку драйвер должен убедиться, что буфер закончил использоваться первым вызовом draw, прежде чем изменять данные
  • Вызов Draw с использованием обновленного буфера 1
  • Буферы подкачки <—— Точка синхронизации, драйвер должен дождаться завершения рендеринга перед заменой буферов

Как вы можете видеть, потенциально вы можете получить вторую точку синхронизации. Однако, как упоминалось ранее, это несколько зависит от драйвера. Например, некоторые драйверы могут быть в состоянии обнаружить случай, когда секция буфера, которую вы обновляете, не используется предыдущим вызовом draw, в то время как другие могут этого не делать. Вероятно, что-то подобного рода вызывает разницу в производительности, которую вы видите.