Считается ли изменение текстуры (рисование на ней) «изменением состояния»?

11

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

Верно ли это, если я постоянно рисую с помощью текстуры glTexSubImage2D? У меня есть поток данных, поступающих (по сети), который подвергается обработке и затем окрашивается в текстуру по одной строке за раз. Данные представлены визуально в бесконечной прокрутке.

Будет ли лучше рисовать на одной текстуре, отображаемой на одном большом прямоугольнике (прокручивая нарисованные данные в поле зрения)? Идея здесь заключается в том, что мне нужно привязать одну (или две) текстуры в любой момент времени, пока я просто продолжаю рисовать.

Или я должен нарисовать много маленьких прямоугольников (открывая прямоугольник только после завершения рисования)? Я предполагаю, что я бы связал одну текстуру на прямоугольник.

TheBuzzSaw
источник

Ответы:

11

Обновление области памяти в графическом устройстве (текстура, буфер и т. П.) Не совсем то же самое, что изменение состояния рендеринга.

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

С другой стороны, для обновления текстуры / буфера основная стоимость заключается в самой передаче данных. Теоретически, если вы не читаете данные текстуры обратно в ЦП после обновления, не должно быть синхронизации или конвейерных остановок. Однако следует учитывать еще один аспект: накладные расходы API. Даже если объем данных, которые вы отправляете на графическое устройство, невелик, если вы делаете это достаточно часто, в конечном итоге стоимость связи с драйвером / устройством станет больше, чем стоимость передачи данных. Это еще одна причина, почему пакетирование так важно при оптимизации рендерера.

Так что в вашем случае, как мне кажется, наилучшим подходом будет сохранить копию текстуры системной памяти, которую вы обновляете при поступлении новых данных. Установите грязный флаг и объедините как можно больше обновлений в одно glTexSubImageдля всей текстуры (или большой последовательной ее части). Вы также можете поиграть с объектами Pixel Buffer и попытаться выполнить асинхронную передачу данных, чтобы максимально уменьшить задержки конвейера. Если вы можете реализовать какую-то двойную буферизацию, то вы можете записать в одну копию текстуры, в то время как другой обрабатывается. Этот урокисследует этот сценарий. Это мой интуитивный подход, я бы попытался уменьшить количество вызовов API и «пакетировать» обновления текстур. При этом, это очень умозрительно, и вам придется профилировать и сравнивать это с другими подходами, такими как несколько небольших обновлений, чтобы точно знать, какой из них наиболее эффективен в вашем случае использования.

Как примечание, эта презентация от NVidia также актуальна и дает много полезных идей: подход к использованию нулевого драйвера в OpenGL .

glampert
источник
5
Я не знаю наверняка, но я определенно подозреваю, что glTexSubImage на текстуре, которая была визуализирована в последнем или втором кадре, остановит конвейер, поскольку драйверы ПК часто пытаются буферизовать кадр или два, и маловероятно хотеть сделать копии целых текстур из-за крошечного обновления. Поэтому я ожидаю, что для максимальной производительности потребуется двойная или тройная буферизация текстур (или объектов пиксельного буфера).
Джон Калсбек