Skip to content

Latest commit

 

History

History

inflight_frames

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

Кадры в полёте

Зависимости: local_shadertoy2.

В данном задании нам предстоит научиться ускорять графические приложения потенциально в 2 раза, лучше понять что такое асинхронность и пайплайнинг, а также научиться профилировать ваши приложения.

Перед началом

  1. Обновите репозиторий курса.
  2. Скопируйте решение задания локальный Shadertoy 2 в эту папку.
  3. Установите Tracy profiler. Для Windows распространяется готовый бинарь, но на Linux вам придётся скомпилировать его руками. Имейте в виду, что если у вас Ubuntu старее чем 24.04, вам придётся компилировать Tracy со флажком LEGACY, заставив его использовать X11 вместо Wayland.
  4. Вспомните материал с занятий по асинхронности GPU и CPU.

Задание

Шаг 1

Во-первых, чтобы сопоставить таймлайны CPU и GPU, нам придётся расставить немножко маркеров Tracy в вашем коде. Сделайте это по аналогии с семплом shadowmap при помощи ETNA_PROFILE_GPU для профилирования работы и GPU и CPU и ZoneScoped для профилирования только CPU. Не забудьте добавить вызовы ETNA_READ_BACK_GPU_PROFILING и FrameMark каждый кадр. Соберите вашу программу в конфигурации RelWithDebInfo. В сборе Release профилирование отключено, а в сборке Debug выключены оптимизации и результаты замеров будут нерепрезентативны. Запустите Tracy и вашу программу, подключите Tracy к ней, запишите некоторое количество кадров и посмотрите внимательно на то, как выглядит трейс. Если Tracy не хочет подключаться, обновите репозиторий, почистите кэш сборки и попробуйте ещё раз. Какие выводы можно сделать, сопоставив GPU и CPU маркеры?

Чтобы эмулировать более крупной приложение, добавьте и на CPU и на GPU дополнительной "бесполезной" работы, чтобы кадр занимал на CPU в районе 8 миллисекунд, а на GPU чуть меньше 16 миллисекунд. На CPU для этого можно использовать обычный sleep посреди записи команд, а на GPU повысьте качестве трассировки SDF. Также будьте аккуратны: в зависимости от угла под которым вы смотрите на сцену, время занимаемое на GPU на трассировку SDF может отличаться.

Ещё раз посмотрите в профайлер и сопоставьте маркеры на CPU и GPU. Тратим ли мы время в ожидании чего-нибудь? Меняется ли результат если отключить в коде vsync?

Шаг 2

На данный момент ваше приложение скорее всего передаёт данные с CPU на GPU только через буферы команд. Пуш-константы свои данные на самом деле хранят тоже прямо в буфере команд. К счастью или к сожалению, Etna написана так, чтобы буферы команд "просто работали" даже после выполнения следующего шага без какой либо дополнительной работы с вашей стороны.

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

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

Шаг 3

В коде инициализации Etna поправьте параметр numFramesInFlight на 2 или 3. Ещё раз посмотрите в профайлер. Что изменилось?

Если вы всё сделали правильно, общая частота кадров приложения должна вырасти. Однако, есть один нюанс. Попробуйте сделать шейдер ещё медленнее, чтобы в вашем приложении было <10 FPS. Подвигайте мышкой и узрите артефакты.

Конечно же, эти артефакты не заметны при высокой частоте кадров, однако если бы мы передавали более чувствительные к валидности данные чем координаты мышки, например индекс по которому нужно обращаться в массив, то мы бы быстро словили легендарный device lost (аналог segmentation fault но на GPU).

Вспомним, что uniform buffer — область памяти, общая для CPU и GPU. Посмотрите ещё раз в профайлер. В какой момент CPU пишет ваш юниформ буфер, а в какой момент его читает GPU?

Шаг 4

Исправьте артефакты при помощи двойной буферизации. Иначе говоря, создайте 2 разных юниформ буфера и чередуйте их при записи чётных и нечётных кадров. Если вы выставили numFramesInFlight в 3, то буферизацию придётся делать тройной.

Если вы любите аккуратный код, вас может заинтересовать шаблон etna::GpuSharedResource. Примеры того как его использовать вы можете найти в коде Этны.

Замечание

В дальнейших домашках тоже рекомендуется пользоваться Tracy для понимания, какие места являются "узкими" в ваших приложениях, а также использовать frames-in-flight.