Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Чип Apple M1, установленный в новых MacBook Air, MacBook Pro и Mac Mini, уже стал предметом множества обсуждений, статей о бенчмарках и публикаций в блогах. Скорость и производительность его действительно впечатляют, особенно касаемо производительности на ватт.
Но конкретно сейчас мы остановимся подробнее на трассировке лучей — в частности, на трассировке лучей через API Metal, анонсированный на WWDC-2020.
Для тестов в данной статье использовались Mac Mini и интерактивный трассировщик пути ChameleonRT, а сравнение проводилось с DirectX, Vulkan, OptiX и Embree.
Подробнее о ChameleonRT
ChameleonRT — интерактивный трассировщик пути с открытым исходным кодом, созданный для изучения различных API трассировки лучей. Он предоставляет бэкэнд для таких API, как DirectX Ray Tracing, Vulkan KHR Ray Tracing и OptiX 7, а теперь и Metal. Также он поддерживает бэкэнд Embree для быстрой многопоточной и ускоренной с помощью SIMD трассировки лучей на ЦП через Embree, ISPC и TBB. Код рендеринга в каждом случае практически идентичен. На выходе получаются пиксельные данные с возможными небольшими различиями, связанными с различиями в библиотеках трассировки лучей и языках шейдеров.
ChameleonRT отличается от популярных приложений для тестирования трассировки лучей, таких как CineBench, LuxMark и Blender Benchmark. Он представляет собой минимально необходимый для тестирования интерактивный трассировщик путей. CineBench, LuxMark и Blender Benchmark отлично подходят для получения полного представления о том, какую производительность ожидать от производственного рендерера. Однако в производственном рендерере происходит гораздо больше, чем просто трассировка лучей: в нем заложена поддержка сложной геометрии, материалов и эффектов, используемых в фильмах, а масштабные кодовые базы сложно переносятся на новую архитектуру или API.
ChameleonRT — их полная противоположность, поддерживающая только один тип геометрии — треугольные мэши — и один тип материала – Disney BRDF. Остальной код написан в целом аналогично другим бенчмаркам для достижения производительной интерактивной трассировки пути, но в то же время так, чтобы его было довольно просто читать. Например, рендереры здесь используют итеративную трассировку лучей вместо рекурсивной, а также только простую стратегию сэмплинга, и не поддерживают эффекты cutout. Использование итеративной трассировки лучей полезно как для ЦП, так и для ГП, хотя для последнего особенно важно — ведь нагрузки при вызове программной рекурсивной трассировки лучей могут существенно повлиять на производительность. Точно так же игнорирование cutout эффектов позволяет рендерерам ГП пропускать использование hit-шейдеров. Они будут вызваны уже во время обхода BVH после нахождения пересечения с треугольником. Аппаратное ускорение обхода BVH приводит к возникновению большого количества возвратов между фиксированной функцией обхода BVH и ядрами для запуска hit-шейдера, что ограничивает производительность оборудования.
Что такое трассировщик пути? Трассировка пути — это метод рендеринга фотореалистичных изображений путем симуляции переноса света в сцене. Это метод Монте-Карло, случайным образом выбирающий пути прохождения света, попадающего в камеру, отражаясь от объектов в сцене. Он реализуется посредством отслеживания пути в направлении от камеры обратно через всю сцену. Для получения изображения без шума необходимо выполнить сэмплинг большого количества световых путей. Трассировка пути не ограничивается применением только в фотореалистичный изображениях. Она также широко используется в кинорендерерах, таких как Renderman от Pixar, Hyperion от Disney, Arnold от Autodesk и Manuka от Weta.
Трассировка лучей на ГП через Metal
Трассировка лучей в новом Metal API похожа на встроенную трассировку лучей в DirectX или Vulkan. Чтобы узнать подробнее, что представляет из себя Metal, можно посмотреть видео с WWDC 2020 и ознакомиться с этим кодом. Встроенная поддержка трассировки лучей позволяет приложениям выполнять вызовы трассировки лучей в шейдерах на любом этапе — например, в шейдерах фрагментов/пикселей, вершинных шейдерах, вычислительных шейдерах и т. д. Также она позволяет включать эффекты трассировки лучей — например, точные отражения и тени — в стандартный пайплайн растеризации. Ее можно использовать в вычислительном шейдере для реализации автономного рендерера на основе трассировки пути. ChameleonRT — автономный трассировщик путей, использующий подход вычислительных шейдеров для Metal.
Трассировка лучей в Metal выполняется следующим образом: вы загружаете свою геометрию, строите над ней примитивные структуры ускорения нижнего уровня, затем создаете инстансы, ссылающиеся на эти структуры, и строите структуру ускорения верхнего уровня поверх этих инстансов. Для рендеринга сцены нужно запустить вычислительный шейдер и непосредственно рейкасты в структуру ускорения верхнего уровня, чтобы получить возвраты от ее пересечений с лучами. Результаты пересечения несут данные о пересекающихся примитивах и геометрии, а при использовании инстансов — и об инстансах. Затем ваш шейдер ищет геометрические данные об объекте, в который попал рейкаст, и закрашивает его, после чего можно продолжить процесс трассировки пути.
В настоящее время Metal поддерживает только встроенную трассировку лучей, в отличие от DirectX и Vulkan, которые также обеспечивают поддержку программной трассировки. Она, в свою очередь, используется для реализации автономных средств рендеринга трассировки лучей — именно этот подход ChameleonRT использует в DirectX и Vulkan. OptiX поддерживает только программную трассировку лучей, что требует создания таблицы привязки шейдеров (Shader Binding Table, SBT) для предоставления API таблицы функций, вызываемых при пересечении определенных объектов в сцене. SBT трудно настраивать и отлаживать, однако их потенциальное преимущество в том, что так графический процессор получает возможность переупорядочивать и группировать вызовы функций для уменьшения расхождения потоков. При встроенной трассировке лучей разработчику необходимо произвести все это вручную или вовсе от этого отказаться (подробнее см. другое видео с WWDC20).
Те, кто уже знаком с Metal, наверняка помнят предыдущий алгоритм расчета пересечения лучей. Новая встроенная поддержка трассировки лучей пошла еще дальше, позволяя рендереру полностью перейти на ГП. Предыдущий алгоритм собирал пакеты лучей, находил пересечения в сцене и записывал полученные результаты в память. То есть, нужно было запустить несколько вычислительных шейдеров для отслеживания первичных лучей и создания теневых и вторичных, затем отследить теневые лучи и продолжить вторичные и после этого произвести фильтрацию завершенных контуров. Для этого требуется значительно больший объем памяти и вычислений, что приводит к повышенной нагрузке на рендерер. Такой подход также не очень хорошо подходит для дополнения стандартных пайплайнов растеризации эффектами трассировки лучей. Подобные решения хороши для рендеринга сложных фильмов и могут быть эффективно реализованы с помощью встроенной трассировки лучей. Например, оно используется в Hyperion от Disney. Вот отличное видео, объясняющее, как это работает.
Трассировка лучей в Metal во многом похожа на другие API, но оптимизирована для более простого использования. Например, для сравнения приведем код, необходимый для сборки и сжатия BVH в DirectX или Vulkan и Metal. API OptiX обеспечивает аналогичное упрощение — вот ссылка на сборку BVH в OptiX в качестве примера. Также приятным бонусом идет возможность иметь шаблоны и функциональные возможности стилей C++ в языке шейдеров — это функция Metal, использующая CUDA для кода на стороне устройства.
Однако в этой простоте есть и свои недостатки. Например, в то время как в DirectX, Vulkan и OptiX вы можете контролировать, где выделяется память для структуры ускорения, Metal вам не оставляет никакого выбора. В результате вы не можете выделить структуры ускорения в MTLHeap и поэтому, чтобы убедиться, что они доступны для вашего пайплайна рендеринга, вы должны сами пометить их как используемые в цикле — вместо простого вызова useHeap.
// Использование структуры ускорение верхнего уровня
[command_encoder setAccelerationStructure:bvh->bvh atBufferIndex:1];
// Помечаем все структуры ускорения мэшей как используемые
for (auto &mesh : bvh->meshes) {
[command_encoder useResource:mesh->bvh usage:MTLResourceUsageRead];
}
Если у вас много BVH нижнего уровня, как это бывает в сценах с большим количеством инстансов, могут возникнуть дополнительные нагрузки. Было бы неплохо иметь возможность выделить структуры ускорения в куче и заменить этот цикл одним [commandencoder useHeap: dataheap-> heap];
Этот API также значительно упрощается за счет того, что он не включает программную трассировку лучей и требует только структуру в виде таблицы привязки шейдеров при реализации настраиваемых геометрий или других операций, которые должны выполняться во время обхода (например, cutout). Код для управления настройкой SBT в DirectX, Vulkan и OptiX составляет значительную часть вспомогательного кода в бэкэнде для каждого API, и хорошо, что этого нет в Metal, не работающем с настраиваемой геометрией или cutout текстурами. Однако в модели SBT графический процессор может группировать или переупорядочивать вызовы функций, но это меньше касается встроенной трассировки лучей, в случае которой такая информация недоступна для драйвера. Действительно ли текущие драйверы для DirectX, Vulkan и OptiX на это способны – вопрос к разработчикам, но теоретически это возможно. В конце концов, вы можете обнаружить, что реализуете что-то вроде более простого аналога SBT для поиска необходимых данных о примитивах/мэшах/инстансах в вашей сцене в буферах аргументов, как это реализовано в ChameleonRT. Тогда же вам необходимо реализовать операции, происходящие во время обхода (настраиваемая геометрия, прозрачность cutout).
Быстрая трассировка лучей на ЦП с библиотеками Intel
В результатах CineBench от AnandTech можно заметить, что CineBench использует Embree — библиотеку трассировки лучей на ЦП от Intel, обеспечивающую оптимизированный обход структуры ускорения и ядер пересечения примитивов, оказывая такую же нагрузку на ЦП, что и новые API трассировки лучей на ГП. Embree была выпущена в 2011 году и с тех пор нашла широкое применение в кино, науке и других сферах.
ChameleonRT также поддерживает бэкэнд Embree, использующий Embree для быстрого обхода лучей и пересечения примитивов, ISPC — для программирования SIMD и TBB — для многопоточности. На самом деле, запустить его на M1 Arm довольно просто. Существует AArch64/NEON порт Embree — Embree-aarch64, — недавно получивший обновления от команды Apple с целью добавления AVX2 в бэкэнд NEON. Embree в значительной степени оптимизирован для ширины SIMD, равной 8, поэтому, даже несмотря на то, что в данном случае нужно использовать 2 вектора NEON, чтобы он действовал как один вектор AVX2, так можно обеспечить лучшую производительность, чем бэкэнд шириной 4 на NEON.
ISPC — компилятор для программирования SIMD на ЦП, в котором пишутся скалярные программы, компилирующиеся для параллельной работы — по одному экземпляру программы на векторную дорожку. Каждая программа обрабатывает свои фрагменты данных параллельно с другими программами. Это что-то вроде GLSL или HLSL, работающих на ЦП, где скалярная программа выполняется параллельно с использованием SIMD. ОднакоISPC уже поддерживает NEON и AArch64, так что включение в него комбинации macOS+AArch64/NEON оказалось довольно простым. Для этого можно использовать такой PR.
Наконец, хотя TBB — библиотека Intel для многопоточности, она не имеет никакого отношения к конкретной архитектуре ЦП. Все, что нам нужно, — это собрать TBB для AArch64.
Бенчмарки
Теперь, когда ChameleonRT работает на ЦП и ГП чипа M1, можно провести несколько тестов. Для сравнения аналогичные тесты были проведены на i7-1165G7 в XPS 13 (тут стоит заметить, что у него могут возникнуть проблемы с нагреванием), на i7-4790K и на i9-9920X на Ubuntu. Что касается ГП, для сравнения был взят RTX 2070. Непосредственно M1 использовался с 16 ГБ оперативной памяти Mac Mini.
Для начала приведем цифры CineBench, о которых говорилось ранее:
CPU | Рейтинг CineBench R23 | Относительно M1 |
i7-1165G7 | 4026 | 0,52x (M1 в ~1,93 раза быстрее) |
i7-4790K | 4579 | 0,59x (M1 в ~1,70 раза быстрее) |
Apple M1 | 7783 | — |
i9-9920X | 14793* | 1,9x (M1 в ~1,9 раза медленнее) |
Таблица 1. Результаты CineBench R23 на протестированных системах. Примечание: i9-9920X работает на Ubuntu, для которой CineBench недоступен.
Для тестов в ChameleonRT были использованы две сцены, показанные ниже: Sponza и San Miguel. Sponza — небольшая сцена с 262 тысячами треугольников, San Miguel — хороший челлендж для интерактивной трассировки лучей с 9,96 миллионами треугольников. Обе рассматриваются BVH билдером как суп из треугольников — то есть, создается единая структура ускорения нижнего уровня, содержащая все треугольники в сцене. Это дает BVH билдеру максимально возможную информацию о распределении геометрии, чтобы он мог построить высококачественную структуру ускорения. Обе сцены скачаны с этого сайта и повторно экспортированы в Blender, чтобы заменить группы материалов на формат OBJ, поскольку ChameleonRT поддерживает далеко не все форматы материалов. В тестах происходит рендеринг изображения разрешением 1280x720px для ~ 200 кадров, после чего снимаются значения средней частоты кадров (FPS) и миллиона лучей за секунду (MRay/s).
Справедливые сравнения
Под справедливым мы понимаем сравнение с другим мобильным процессором, в данном случае — i7-1165G7 на XPS 13, использующем Embree. Результаты сравнения здесь оказались немного больше в пользу M1, поскольку XPS 13 сильнее нагревается. Также приведены результаты для i7-4790K. Поначалу при запуске конфигурации для Embree в ChameleonRT XPS 13 может даже превзойти i7-4790K, но впоследствии он замедляется из-за нагрева.
i7-1165G7 имеет расширение AVX512, что позволяет ISPC запускать 16 потоков параллельно. В свою очередь, i7-4790K поддерживает AVX2, позволяя ISPC запускать 8 потоков параллельно. На M1 можно использовать ISPC для компиляции NEON с двойной подкачкой, то есть выполнения SIMD шириной 8 в 4-х разрядных регистрах NEON. Embree на M1 настроен для использования AVX2 на NEON, так как Embree оптимизирован для ширины SIMD, равной 8.
CPU | FPS | MRay/s |
i7-1165G7 (AVX512) | 1,56 | 8,7 |
i7-4790K (AVX2) | 1,83 | 10,2 |
Apple M1 | 1,72 | 9,6 |
Таблица 2. Результаты тестов рендеринга Sponza с использованием Embree.
CPU | FPS | MRay/s |
i7-1165G7 (AVX512) | 1,07 | 6,1 |
i7-4790K (AVX2) | 1,33 | 7,6 |
Apple M1 | 1,30 | 7,4 |
Таблица 3. Результаты тестов рендеринга San Miguel с использованием Embree.
Крайне несправедливые сравнения
Это сравнения трассировки лучей Metal на M1 с трассировкой лучей DirectX на RTX 2070 и Embree на i9-9920X. Понятно, что при таких сравнениях M1 будет не слишком конкурентоспособным, но все равно любопытно было проверить. RTX 2070 имеет TDP, равное 175 Вт, и аппаратное ускорение трассировки лучей, в то время как весь чип M1 оценивается примерно в 20-24 Вт и не имеет ускорения трассировки. i9-9920X имеет TDP, равное 165 Вт, и поддерживает AVX512 (с шириной SIMD 16) и AVX2 (ширина SIMD 8). Как видно из предыдущих тестов, поддержка более широкой SIMD (AVX2) на i7-4790K по-прежнему обеспечивает серьезную конкуренцию M1. Также в этих тестах выяснилось, что i9-9920X работает лучше всего при использовании AVX2. В тестах Трэвиса Даунса было замечено, что использование AVX512 на некоторых процессорах может привести к понижению тактовой частоты. В зависимости от того, насколько оптимизирована рабочая нагрузка для SIMD, на самом деле она может работать лучше при более высоких тактовых частотах и более узкой ширине SIMD, как в данном случае. Обратите внимание, что на i7-1165G7 AVX512 работает немного лучше, чем AVX2.
CPU | FPS | MRay/s |
i9-9920X (AVX2) | 6,02 | 33,6 |
Apple M1 | 1,72 | 9,6 |
Таблица 4. Крайне несправедливые тесты Sponza с использованием Embree.
CPU | FPS | MRay/s |
i9-9920X (AVX2) | 4,46 | 25,3 |
Apple M1 | 1,30 | 7,4 |
Таблица 5. Крайне несправедливые тесты San Miguel с использованием Embree.
GPU | FPS | MRay/s |
RTX 2070 (DirectX Ray Tracing) | 135,5 | 757 |
Apple M1 (Metal) | 3,60 | 20,1 |
Таблица 6. Крайне несправедливые тесты Sponza на ГП.
GPU | FPS | MRay/s |
RTX 2070 (DirectX Ray Tracing) | 63,8 | 362 |
Apple M1 (Metal) | 2,06 | 11,7 |
Таблица 7. Крайне несправедливые тесты San Miguel на ГП.
Подводя итог
Итак, M1 на CineBench показал производительность в 1,93 раза большую, чем i7-1165G7, но при тестах на ChameleonRT в обеих сценах в среднем он был всего в 1,16 раза быстрее. Точно так же M1 показал себя на CineBench в 1,70 раза более производительным, чем i7-4790K, но на самом деле оказался 1,05 раза медленнее в среднем по двум сценам. Что из этого следует?
Важно иметь в виду, что тесты на ChameleonRT не идентичны CineBench. В производственном рендерере, таком как CineBench, происходит гораздо больше вещей, чем в таком минималистичном, как ChameleonRT. Такие задачи, как пересечение более богатых геометрий, оценка более сложных моделей материалов и т. д., могут составлять значительную часть общего времени выполнения в производственном рендерере. ChameleonRT, с другой стороны, не включает ничего из этого и просто тестирует производительность обхода лучей. Таким образом, если мы получим аналогичную производительность с Embree на M1, но другие вещи в CineBench окажутся быстрее, мы можем получить более высокие относительные оценки в CineBench, чем только при оценке производительности трассировки лучей.
В целом M1 очень неплох — как в плане производительности, так и бесшумности. О его практически полностью бесшумной работе действительно есть что сказать: его не было слышно ни в описанных выше тестах, ни при параллельной сборке LLVM для сборки ISPC.
Что действительно хотелось бы увидеть в будущих чипах M*, так это поддержку SIMD с шириной 8 и трассировки лучей с аппаратным ускорением. При запуске Embree на оборудовании с поддержкой SSE4 (SIMD шириной 4) обнаружилось, что он примерно в 1,6-1,8 раза медленнее, чем при работе с AVX2 (SIMD шириной 8). Даже если предположить, что мы получаем скорость всего в 1,6 раза больше на M1 с SIMD шириной 8, это приведет к тому, что с Embree частота кадров окажется ~ 2,75 FPS на Sponza и ~ 2,06 FPS на San Miguel.
Поддержка трассировки лучей с аппаратным ускорением на графическом процессоре также не была бы лишней. Но даже текущий уровень производительности впечатляет для столь легкого чипа, учитывая, что у него нет таких тепловых проблем, как, скажем, у XPS 13, и он может обеспечить несколько лучшую производительность на процессоре с шириной 1/4 SIMD (4 против 16), а также имеет API графического процессора, который обеспечивает в этих тестах ускорение в 1,6-2 раза по сравнению с ЦП.
Интересно посмотреть, какое оборудование Apple планирует для high-end сегмента.