Дерево устранения избыточности состояния OpenGL, приоритеты состояния рендеринга

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

Мой пакетный дизайн дерева начинается с самых дорогих состояний и добавляет листы вниз для каждого менее дорогого состояния.

Пример: Корень дерева: Шейдеры / Программы Братья и сестры: Состояния смешивания ... a.s.o.

Итак, мой вопрос: какие звонки в этом списке, скорее всего, являются самыми дорогими:

  • программа привязки
  • текстуры переплета
  • буферы привязки
  • текстура буферизации, данные вершин
  • привязка целей рендеринга
  • glEnable / glDisable
  • уравнение состояния наложения, цвет, функции, colorWriteMask
  • глубина состояния трафарета depthFunc, stencilOperations, stencilFunction, writeMasks

Также интересно, какой метод будет быстрее:
- Соберите все команды рисования с возможностью пакетной обработки в буфер с одной вершиной и вызовите только 1 вызов отрисовки (этот метод также заставит обновлять преобразования матрицы для каждой вершины на стороне процессора)
- Не выполнять пакетную обработку вообще и рендерить много мелких вызовов отрисовки, только пакетную систему частиц ...

PS: Цели рендеринга всегда будут меняться до или после, в зависимости от использования.

Прогресс на данный момент:

  • Андон М. Коулман: Самая дешевая привязка однородных массивов и вершинных массивов, дорогие FBO, привязки текстур
  • datenwolf: программы делают недействительным государственный кеш

1: Состояния фреймбуфера
2: Программа
3: Связывание текстуры
...
N: Связывание массива вершин, Равномерное связывание

Текущее дерево выполнения в WebGL:

  • Программа
  • Указатели атрибутов
  • Текстура
  • Состояние смешивания
  • Состояние глубины
  • Состояние трафарета спереди / сзади
  • Состояние растеризатора
  • Состояние сэмплера
  • Привязать буфер
  • Рисовать массивы

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

Загрузка текстур / программ / шейдеров / буферов происходит перед рендерингом в дополнительной очереди, для будущей многопоточности, а также для того, чтобы убедиться, что контекст инициализирован, прежде чем что-либо с ним делать.

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


person Zeto    schedule 26.08.2014    source источник
comment
Какая у вас целевая версия GL? В вашем списке отсутствуют изменения состояния целевого объекта рендеринга (FBO), которые являются очень дорогими (но не обязательно проблема в зависимости от версии).   -  person Andon M. Coleman    schedule 26.08.2014
comment
Спасибо за совет, я хотел ввести управление FBO вскоре после того, как заработала базовая архитектура.   -  person Zeto    schedule 26.08.2014
comment
Меня интересует любая версия, но большая часть OpenGLES 2, 3 кстати. просто укажите версию, о которой вы что-то знаете :)   -  person Zeto    schedule 26.08.2014
comment
Я могу сказать вам, что массив вершин и однородные состояния - это самые дешевые состояния, которые вы можете изменить во всех реализациях GL, а состояния FBO и привязка текстур, как правило, являются самыми дорогими. Я не могу дать вам список, как в вашем вопросе, только крайние его края. Я также хотел бы отметить, что большая часть расходов связана не с первоначальным вызовом, например, glBindXXX (...), а с тем, что происходит, когда вы выполняете вызов отрисовки после изменения 20 нечетных состояний, и все они должны быть проверены сразу.   -  person Andon M. Coleman    schedule 26.08.2014
comment
Что для вас дороже (текстура против программы) и (текстура против состояния смешивания / глубины / трафарета / растеризатора / сэмплера)   -  person Zeto    schedule 26.08.2014
comment
Определенно программы, потому что изменение программы всегда приводит к недействительности кеша кода. Поэтому после изменения программы графический процессор должен запускаться с кешем холодного выполнения. Сэмплер-штаты больше похожи на униформу, но не так дешевы. Следует также отметить, что порядок затрат зависит от используемого драйвера и графического процессора, а также от программы, которая выполняется на графическом процессоре в данный момент. Как показывает практика, все, что делает кеш холодным, является серьезным убийцей производительности. Трудно переоценить важность согласованности кеша и шаблонов доступа для производительности графического процессора.   -  person datenwolf    schedule 26.08.2014
comment
Приведу пример: когда мы реализовали систему, описанную в документе dx.doi.org/10.1364 /BOE.5.002963 в какой-то момент я мог добиться 100-кратного увеличения пропускной способности за счет ничего не подозревающего переупорядочения доступа к данным и еще 10-кратного увеличения за счет улучшения выравнивания данных. Хотя это была вся работа с CUDA, а не с OpenGL (с которой я добился повышения производительности), она проливает свет на то, насколько деликатны графические процессоры, когда дело доходит до их шаблонов доступа к данным.   -  person datenwolf    schedule 26.08.2014
comment
Спасибо за документ, ну, моя основная цель - создать хороший метод высокоуровневой пакетной обработки, чтобы CUDA или OpenGL не внесли никаких изменений для меня ^^, но я уверен, что реализации могут отличаться ^^   -  person Zeto    schedule 26.08.2014


Ответы (2)


Относительные затраты на такие операции, конечно, будут зависеть от модели использования и вашего общего сценария. Но вы можете найти слайды презентации Nvidia "Beoynd Porting" в качестве полезного руководства. . Позвольте мне особенно воспроизвести здесь слайд 48:

Относительная стоимость изменения состояния

  • В снижении стоимости ...
  • Цель рендеринга ~ 60 К / с
  • Программа ~ 300К / с
  • ROP
  • Привязка текстур ~ 1,5 М / с
  • Формат вершины
  • Наручники UBO
  • Единообразные обновления ~ 10M / s

Это не соответствует напрямую всем пунктам вашего списка. Например. glEnable/glDisable может повлиять на что угодно. Кроме того, привязки буфера GL не являются чем-то, что непосредственно видит графический процессор. Привязки буфера - это в основном состояние на стороне клиента, конечно, в зависимости от цели. Изменение состояния смешивания будет изменением состояния ROP и так далее.

person derhass    schedule 26.08.2014
comment
Спасибо за слайд, я скоро его проверю, есть еще одна вещь, которая меня интересует: если процессор и графический процессор используют одну и ту же память, это память, копируемая на новый адрес, или они просто делятся указателями на нее ? Примером сценария может служить Архитектура устройства iOS. - person Zeto; 26.08.2014
comment
Если я измерю время выполнения, будет ли это только на стороне процессора или также будет учитываться время графического процессора? Может быть, с помощью glFinish? - person Zeto; 26.08.2014
comment
@Zeto: Вся эта память полностью зависит от реализации. Я не знаю ничего конкретного об архитектуре iOS. Что касается времени: вы измеряете только процессорное время. На настольном GL есть расширение GL_ARB_timer_query, которое позволяет измерять Время работы графического процессора. Не знаю, есть ли что-то похожее на GLES. Также могут быть внешние инструменты отладки и профилирования GL (ES) и платформенно-зависимые API для счетчиков производительности. - person derhass; 27.08.2014
comment
спасибо за совет, да, у меня есть инструменты от Apple, которые также намекают мне на избыточность, я должен проверить, могу ли я измерить время выполнения одной команды, могу ли я создать список выше таким образом ... - person Zeto; 27.08.2014

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

Со всеми этими оговорками:

  • Переключение целевого объекта рендеринга (FBO) обычно обходится довольно дорого. Однако сильно зависит от платформы и архитектуры. Например, если у вас есть какая-то форма архитектуры на основе плиток, ожидающий рендеринг, который в идеале должен быть отложен до конца кадра, может быть завершен и списан. Или в более «классических» архитектурах могут быть сжатые цветовые буферы или буферы, используемые для раннего тестирования глубины, которые необходимо учитывать при переключении целей рендеринга.

  • Обновление данных текстуры или буфера невозможно оценить в общих чертах. Очевидно, это сильно зависит от того, сколько данных обновляется. Вопреки некоторым заявлениям в Интернете, вызовы типа glBufferSubData() и glTexSubImage2D() не обычно вызывают синхронизацию. Но они включают копии данных.

  • Связывающие программы не должны быть очень дорогими, но, как правило, они более тяжелы, чем изменения состояния, указанные ниже.

  • Связывание текстур в большинстве случаев относительно дешево. Но это действительно зависит от обстоятельств. Например, если вы используете графический процессор с VRAM, а текстуры в данный момент нет во VRAM, это может вызвать копирование данных текстуры из системной памяти в VRAM.

  • Единые обновления. Предположительно это очень быстро на некоторых платформах. Но на самом деле для других это умеренно дорого. Так что здесь много вариаций.

  • Настройка состояния вершины (включая привязку VBO и VAO) обычно выполняется быстро. Это должно быть так, потому что это так часто делается большинством приложений, что очень быстро может стать узким местом. Но есть те же соображения, что и для текстур, где буферная память может быть скопирована / отображена, если она не использовалась в последнее время.

  • Обновления общего состояния, такие как состояния наложения, состояние трафарета или маски записи, обычно выполняются очень быстро. Но могут быть очень существенные исключения.

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

person Reto Koradi    schedule 27.08.2014
comment
Спасибо, я всегда использую собственные шейдеры фрагментов и вершинные шейдеры. Но все же я предлагаю внешний класс Effect, который может использоваться разработчиком для изменения шейдеров фрагментов, но я вставляю код своего движка в исходный файл, чтобы гарантировать функциональность. - person Zeto; 27.08.2014
comment
Теперь у меня работает версия WebGL, выполненная на js, потому что разработка идет довольно быстро ... Я начну стресс-тест сегодня днем ​​и изменю приоритеты дерева пакетов, могу ли я получить некоторые полезные данные таким образом, какие швы будут более медленно - person Zeto; 27.08.2014
comment
Что бы вы предпочли для теста? Кстати. все говорят, что я могу измерить только время ЦП, но не ГП, из-за клиентской ‹› Серверной архитектуры на некоторых устройствах - person Zeto; 27.08.2014