Эта статья была задумана как дань старой традиции: нам хотелось полюбоваться дорогими системами с несколькими GPU, как это было в 2014 и 2016 годах, а потом мы готовились с разочарованием признать, что технологии SLI и CrossFire уже утратили всякую практическую ценность. Но вместо этого получилось своего рода продолжение наших недавних публикаций про API нового поколения, ведь большинство игр из нашей тестовой методики поддерживают Direct3D 12. Под этим API пара видеокарт работают совсем по-иному, нежели в Direct3D 11, и нет никакого смысла ограничиваться сравнением под формально устаревшим, но все еще преобладающим интерфейсом Direct3D 11.
А что касается главного вопроса (осталась ли какая-то польза в SLI и CrossFire), то придется признать, что похороны двухадаптерных систем снова откладываются! Да, в связи со сменой API возникли новые проблемы, связанные и c реализаций Multi-Adapter в Direct3D 12, и с пропускной способностью шины PCI Express, и с пресловутой процессорозависимостью игр. Но, с другой стороны, именно Direct3D 12 несет в себе возможности для того, чтобы их преодолеть.
Мультиадаптерный рендеринг в Direct3D 11
Для начала признаем намеренную неточность в названии статьи, которую могли заметить читатели, следящие за состоянием дел в области игровой графики. Действительно, марка CrossFire ушла в отставку еще в прошлом году. Теперь AMD описывает мультиадаптерные системы термином mGPU, поскольку сфера использования CrossFire (как и NVIDIA SLI) ограничена Direct3D 11, а кто, как не AMD, больше всех приветствует переход к Direct3D 12. Тем не менее сама технология никуда не делась, и даже в настройках драйвера Radeon по-прежнему называется именно так.
В целом оба производителя дискретных GPU сейчас прохладно относятся к мультиадаптерному рендерингу. Это заметно по тому, как сократилось разнообразие конфигураций, в которых работают SLI и CrossFire. Пропали видеокарты на основе двух графических процессоров, без которых прежде не обходилось ни одно обновление архитектуры. Драйверы AMD и NVDIA официально поддерживают не больше двух GPU. А ведь в 2011 году мы тестировали связки из трех и четырех видеокарт класса GeForce GTX 580, и в то время игры могли вполне неплохо загрузить три ускорителя высшего эшелона. К тому же NVIDIA загнала SLI в самый верх своей продуктовой линейки: младшей видеокартой в серии GeForce 10, которая имеет разъемы SLI, является сравнительно мощный и дорогой ускоритель GeForce GTX 1070.
Конечно, именно мощные видеокарты, как правило, и устанавливают парами, а утраченная возможность использовать три или четыре графических процессора по большей части была полезна только для набора рекордных баллов в 3DMark. Но потеря интереса к SLI и CrossFire со стороны хозяев рынка видеокарт отражает общий застой этого направления, к которому привело несоответствие между сложностью технических задач и низким спросом со стороны рядовых геймеров.
В концептуальном плане рендеринг при помощи множественных GPU — это вполне очевидная идея, которая логически следует из высокого параллелизма вычислений, но на практике такие технологии всегда были довольно-таки капризны и требовали постоянного внимания со стороны драйверописателей. В рамках Direct3D 11 функцию разделения нагрузки между несколькими видеоадаптерами целиком выполняет драйвер. Игровой движок, как и в случае одиночного GPU, отдает команды общей очередью, а драйвер распределяет их так, чтобы, пока первый графический процессор создает свой кадр видеоряда, второй GPU занимается следующим кадром (метод AFR — Alternate Frame Rendering). Для полноты картины стоит заметить, что мультиадаптерный рендеринг не сводится к AFR. В редких случаях используется метод SFR (Split Screen Rendering), в котором каждый GPU обрабатывает свою часть единого кадра, а Direct3D 12 предусматривает и более сложные режимы, но о последнем — чуть позже.
В идеале процедура мультиадаптерного рендринга в Direct3D 11 прозрачна для игрового движка и не требует дополнительных усилий от его разработчиков, но на практике все совсем не так просто. При использовании метода AFR нужно считаться с ограничениями в тех ситуациях, когда существуют зависимости между последовательными кадрами, а это практически неизбежно в современных играх. Как следствие, адекватная работа мультиадаптерной системы возможна только при наличии профилей настроек для каждой конкретной игры, благодаря которым драйвер получает подсказки о том, чем занимается движок, а разработчикам игры — в идеале — нужно понимать, что пытается сделать драйвер. Полезно использовать и проприетарный API (такой как NVAPI для GPU NVIDIA), открывающий доступ к GPU в обход уровня абстракции Direct3D, но даже в идеальных условиях не от каждой игры можно добиться хорошего масштабирования быстродействия на нескольких адаптерах.
Свой вклад в эту проблему вносит и пресловутая «процессорозависимость»: графические чипы сейчас развиваются быстрее, нежели быстродействие CPU архитектуры x86 с небольшим числом потоков, и это заметно даже в конфигурациях с одной мощной видеокартой, не говоря уже о двух. Наконец, как мы раз за разом видим по результатам группового теста GPU в какой-нибудь популярной игре, единственный адаптер высшего эшелона, скорее всего, удовлетворит любого геймера. С другой стороны, и разница в качестве изображения между низкими и максимальными настройками качества графики уже не та, что в золотые времена SLI и CrossFire. В результате побуждение наращивать кадровую частоту любой ценой сошло на нет, а раз так, то какой смысл для людей, работающих над драйверами GPU, вкладывать усилия в нишевую технологию мультиадаптерного рендеринга? Пока работа продолжается (особенно со стороны NVIDIA), но с пришествием Direct3D 12 ситуация может полностью измениться — причем как в лучшую, так и в худшую сторону.
Мультиадаптерный рендеринг в Direct3D 12
Новый графический API Microsoft предусматривает два различных подхода к программированию мультиадаптерного рендеринга. В режиме Implicit Multi-Adapter задачу разделения работы между GPU выполняет драйвер — как в Direct3D 11, со всеми его плюсами и минусами. С другой стороны, в режиме Explicit Multi-Adapter ресурсами графических процессоров целиком распоряжается игровой движок, и это одновременно и благословение, и проклятие, ведь в таком случае все зависит от готовности разработчиков вкладывать силы в поддержку Multi-Adapter.
При должном старании программисты смогут извлечь из связки GPU быстродействие, принципиально недостижимое в предыдущей версии API. В частности, можно отказаться от AFR и применять сложные методы распределения нагрузки между адаптерами — такие как конвейеризация кадров (Frame Pipelining), при которой несколько GPU выполняют различные этапы рендеринга одного кадра, а проблема зависимостей между соседними кадрами отсутствует как таковая. Кроме того, конвейеризацию можно использовать в пользу качества рендеринга, а не частоты смены кадров. К примеру, загрузить второй GPU расчетом глобального освещения, трассировки лучей, физики и так далее.
У Explicit Multi-Adapter есть два метода реализации: Linked Node и Unlinked Node. Первый метод — это аналог SLI и CrossFire в рамках новой парадигмы мультиадаптерного рендеринга. Как и в этих проприетарных технологиях, работающих на уровне драйвера под Direct3D 11, здесь несколько адаптеров представлены общими очередями команд: графика, вычисления общего назначения и очередь Copy для передачи данных по шине PCI Express. Проще говоря, игра «видит» несколько адаптеров как один, а принадлежность команды определенному GPU определяется так называемой маской узла.