понедельник, 27 мая 2019 г.

Энергосбережение и профилирование

Видеокарты gtx 1070 в ноутбуке и RTX 2080 в ПК одинаково снижают частоты при рисовании простой графики. Таким образом, если кадр рисуется за 20мкс, то частоты снизятся так, чтобы кадр рисовался за 1-2мс. Обычно это даже хорошо - меньше нагрузка и соответственно меньше нагрев и меньше шума от вентиляторов. Но для замеров производительности это вносит огромные искажения. Теперь сложно оценить реальную скорость рисования/вычислений, остается только оценивать относительное время выполнения и то если частоты в этот момент не меняются.
Это касается замеров времени через FPS (количество кадров в секунду) и через встроенные в графические апи команды (например vkCmdWriteTimestamp в vulkan). RenderDoc для vulkan замеряет время именно таким способом, из-за чего результаты получаются некорректными. RenderDoc для DirectX 12 работает иначе и стабильно выдает корректное время. Профайлеры от производителей GPU тоже должны замерять время на максимальной частоте, но это надо проверять.

Как это можно обойти:

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

2. При увеличении нагрузки частоты также поднимаются. То есть можно сначала "прогреть" GPU, а потом делать точные замеры.

3. В NVAPI и в DX12 есть функция для установки стабильных частот на GPU.

понедельник, 13 мая 2019 г.

Anti-aliased SDF shadow

Пока делал volumetric light придумал как сделать anti-aliasing для теней и как раз попался простой пример с тенью в который я и добавил свой алгоритм.


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

воскресенье, 5 мая 2019 г.

Неявная оптимизация

В современных GPU есть множество разных оптимизаций, о которых не все знают.

Delta color compression
При рисовании в текстуру происходит сжатие данных без потерь, в глобальную память передается уже сжатые данные, что увеличивает пропускную способность памяти. Чтение текстуры в шейдере может работать со сжатыми данными, что немного увеличивает производительность. Но чтение/запись текстуры в вычислительном шейдере всегда приводит к разжатию данных, что отнимает некоторое время.
Некоторые форматы (например fp16) содержат слишком зашумленые данные, что снижает эффективность сжатия, поэтому иногда стоит использовать форматы с большей битностью (например fp32 вместо fp16), чтобы увеличить эффективность сжатия.
На Mali сжатие поддерживается только на RGBA8 формате.
На Adreno упоминаний про DCC нет, но есть хардварное сжатие которое работает для камеры, видео, RGB текстур и тд.


Hardware occlusion culling
На данный момент реализовано в Nvidia и Mali.
Подробности о том, как это реализовано на Nvidia я не нашел. В idTech6, например, для Nvidia выключается GPU occlusion culling, потому что его заменяет хардварная реализация, для AMD он включен.
На новых Mali используется Visibility buffer. Первым проходом записывается только индекс вершины и инстанса и происходит тест глубины. Работает почти так же быстро как depth only pass. Далее идет проход по всем пикселям и для них выполняется вершиный шейдер для рассчета остальных аттрибутов, затем выполняется фрагментный шейдер. Для большей оптимизации рекомендуется хранить позиции вершин отдельно от остальных аттрибутов, так как они читаются в разных проходах.
Возможно в новых GPU от Intel также появится hardware occlusion culling также основанный на visibility buffer.
УAMD в патентах есть вариант с кулингом на вычислительных шейдерах, но реализации в железе пока нет.

Out of order rasterization
Обычно порядок в котором рисуются полигоны строго документирован, железо и драйвер могут вносить некоторые оптимизации, но это не должно влиять на результат. Для depth only pass порядок вывода примитивов не имеет значения, значит драйвер может рисовать их максимально эффективно.
На AMD эту оптимизацию можно включать вручную: link


Кэширование атомиков
На современных GPU есть быстрый кэш для нескольких атомиков, информации по Nvidia я не нашел, а в описании AMD по архитектуре GCN 3 говорится о кэше для 3х атомиках, если атомиков будет больше - будет работать заметно медленнее.


Android hardware scaling
В мобильных девайсах есть оптимизации для воспроизведения видео, например хардварное масштабирование изображения. Этот механизм можно использовать и для игр рисуя в свопчейн меньшего размера, вместо того чтоб делать масштабирование в шейдере это будет сделано в драйвере.
Подробное описание


Graphics vs Compute
С появлением GPGPU видеокарты стали оптимизировать и для вычислительных задач, часто вычислительные шейдеры выполняются параллельно, если есть свободные ядра (CU) и между ними нет зависимости. Рисование работает иначе - только рисование в один фреймбуфер может быть распараллелено, это не очень эффективно, если размер фреймбуфера небольшой, тогда часть ядер простаивают. Вычислительные шейдеры не могут работать параллельно с рисованием. Для решения этой проблемы сначала AMD, а затем и Nvidia добавили async compute queue (только Vulkan и DX12), тогда рисование и вычисления могут выполняться параллельно.
Документация по Vulkan не запрещает параллельное рисование и параллельные вычисления с рисованием, это все ограничения железа и возможно скоро производители решат эту проблему.