Сколько производительности делают условные и неиспользуемые пробоотборники/текстуры, добавляемые к пиксельным шейдерам SM2/3?

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

Я понятия не имею, насколько большая производительность влияет на эти две вещи, но тем более, что мы поддерживаем SM2.0 на интегрированных графических чипах, проблема неэффективности. Таким образом, передача текстуры внутри и без использования означает дополнительные дополнительные накладные расходы? И используется ли с помощью if, чтобы добавить пару инструкций или может сильно повлиять на вещи из-за киосков и т.д., Как при оптимизации ЦП?

Ответ 1

Настройка текстуры на GPU занимает некоторое время процессора, но она достаточно мала по сравнению с фактической стоимостью batch. Что еще более важно, он не должен иметь никакого влияния на фактическое выполнение шейдера, если шейдер никогда не ссылается на него.

Теперь можно обрабатывать ветвление тремя способами:

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

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

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

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

Поскольку группы фрагментов имеют экранную локальность, это помогает, если ваши ветки имеют сходную локальность на экране. См. Эту диаграмму:

http://http.developer.nvidia.com/GPUGems2/elementLinks/34_flow_control_01.jpg

Теперь шейдерный компилятор, как правило, очень хорошо подходит для выбора того, какой из последних двух методов использовать (для первого метода компилятор будет встроен для вас, но вам нужно сделать несколько версий шейдеров самостоятельно). Но если вы оптимизируете производительность, полезно увидеть фактический вывод компилятора. Для этого используйте fxc.exe в утилитах DirectX SDK с параметром /Fc <file>, чтобы получить представление разборки скомпилированного шейдера.

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

Дополнительная ссылка: Графики GPU 2: Глава 34. Идиомы управления потоком GPU.