среда, 2 ноября 2011 г.

Driver Concurrent Creates

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

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

В отличие от своих предшественников, Direct3D 11 был спроектирован для поддержки мультипоточности. Вкратце, её поддержка заключается в двух возможностях:

1) Driver Concurrent Creates
2) Driver Command Lists

Первая функциональность позволяет создавать объекты (текстуры, буферы, шейдеры) в разных потоках, а вторая - формировать command buffer в отдельном потоке с дальнейшем "вливанием" его в общий контекст рендеринга. Обе эти функциональности опциональны и зависят от видеодрайвера. Если драйвер их не поддерживает, рантайм будет их эмулировать, но без надежды получить выигрыш в производительности.

В DirectX Caps Viewer в разделе "DXGI 1.1 Devices \ Reference \ Direct3D 11" каждый может посмотреть, поддерживает ли текущий драйвер эти "фичи" (как оказалось, утилита может привирать). Сразу скажу, что Driver Command Lists на момент написания этого поста не реализованы ни у AMD, ни у NVidia. О причинах можно только догадываться. Поддержка Driver Concurrent Creates может варьироваться от системы к системе, но обычно она присутствует.

Создание шейдеров на основе скомпилированного байткода вычислительно ресурсоёмкая задача: рантайм должен распарсить и валидировать байткод, а драйвер - соптимизировать его под конкретную архитектуру и транслировать в машинный код GPU. Использование нескольких ядер CPU в целях ускорения этой задачи оправданно, и если драйвер Direct3D 11 поддерживает эту функциональность, её можно задействовать.

Я решил поиграться с мультипоточной загрузкой шейдеров и написал небольшое тестовое приложение. Исходный код расположен здесь (проект для Visual Studio 2008). Суть его проста: сравнить время загрузки одного и того же количества шейдеров используя один и несколько потоков. Для начала я скрестил Win32 и консольное приложения: нет окна и обработчика оконных сообщений, зато есть консоль с HWND. Для инициализации Direct3D достаточно просто создать устройство, во всём остальном нет надобности. Далее я взял несколько простых шейдеров из состава DirectX SDK, байткод которых заставил грузиться в цикле энное количество раз. Для простоты количество создаваемых потоков равно количеству физических ядер CPU, т. е. по одному на ядро. В конце время выполнения обоих тестов сравнивается и подсчитывается фактор ускорения (он может плавать, что естественно).

С установленными видеокартами (и драйверами) AMD для Core 2 Quad я получил ускорение приблизительно 1.8X, для Core i5 - 2X-2.5X. Что интересно, для NVidia ускорение составляет ~3X, при этом скорость создания шейдеров значительно медленнее, чем в случае с AMD. Не четырёхкратное ускорение, конечно же, но и эти показатели неплохи. Интересно было бы запустить тест на новых 8-ядерных FX-81xx от AMD. Если кому-то выпадет такая возможность - пишите. Также неплохо попробовать использовать в тесте более разнообразные и тяжёлые пиксельные и вычислительные шейдеры.

P.S. Не пытайтесь запускать программу из-под отладчика - в этом случае она ведёт себя некорректно.

Комментариев нет:

Отправить комментарий