что такое mgpu directx 12
DirectX 12 Multi-GPU: пока работает
Одно из самых важных нововведений в DirectX 12 – это так называемый «asymmetric multi-GPU», функция, позволяющая соединять и запускать вместе видеопроцессоры от разных брендов, при условии поддержки определенного общего уровня технологий (в случае Ashes of Singularity – это Direct3D 12_0). Для работы этой функции недостаточно иметь две видеокарты с поддержкой DirectX 12, нужно также использовать их на приложениях, которые поддерживают DirectX 12. Проще говоря, если вы думаете, что прошлогодние игры на DirectX 11 заработают быстрее с этой функцией – ну, в общем, вы думаете неправильно. Команда Anandtech решила проверить заявления Microsoft о работоспособности этой функции и собрала систему с несколькими видеочипами, используя карты Radeon R9 Fury X и GeForce GTX 980 Ti. Выводы получились интересные.
Для начала, действительно, самый распространенный метод работы с несколькими картами – AFR, когда каждая карта обрабатывает только определенную часть кадров – работает. При его включении появился больше чем 50-процентный прирост производительности, но, увы, далеко не такой большой, как если бы использовались карты одного бренда в связке CrossFire или SLI. Во-вторых, на производительность влияло то, какая из видеокарт выбрана как основная. В Anandtech обнаружили, что конфигурация, в которой основной была R9 Fury X (то есть, к ней был подключен монитор), а GTX 980 Ti была вторичной, работала немного быстрее, чем при обратном варианте. Также через Multi-GPU работает запуск разных видеопроцессоров одного производителя (к примеру, GTX 980 Ti и GTX TITAN X). В чем же главный и неоспоримый плюс этой функции? В том, что система с R9 Fury X и GTX 980 Ti во всех тестах вела себя абсолютно стабильно.
Остается только гадать, сколько продлится это идиллическое состояние индустриальных стандартов, и сколько пройдет времени, прежде чем (может быть) производители видеочипов обнаружат, что это не идет на пользу их коммерческой выгоде. Судя по всему, и AMD, и NVIDIA потратили на мультичиповую оптимизацию довольно много ресурсов. И также только в несколько отдаленном будущем мы точно узнаем, какую часть этих ресурсов они предпочтут пустить на обеспечение мультичиповой производительности в унифицированной системе, а сколько – на собственные разработки SLI и CrossFire.
Интересующимся подробностями и хорошо читающим по-английски мы предлагаем ссылку на полный отчет Anandtech о проведенных тестах.
DirectX 12 Multi-GPU Explicit Multi-Adapter (AMD и NVIDIA под DirectX 12 в смешанном режиме)
На данный момент обсуждения идут, в основном, вокруг низкоуровневых тестов DirectX 12, поскольку меньшая избыточная вычислительная нагрузка обещает прирост производительности. Новый API позволяет использовать видеокарты AMD и NVIDIA одновременно, теоретически складывая их ресурсы производительности.
DirectX 12 Multi-GPU Explicit Multi-Adapter или Multi Display Adapter – такими терминами сегодня описывается взаимодействие разных GPU. Технология стала возможной благодаря доступу к API на более глубоком уровне. Теперь разработчики получают более эффективные средства управления памятью и многими другими компонентами «железа». Работа систем multi-GPU под DirectX 11 была полностью в руках разработчиков драйверов. Под DirectX 12 «власть» перешла к разработчикам игр. Издание Anandtech провело первые тесты Multi-GPU Explicit Multi-Adapter. Для теста издание получило специальный билд игры Ashes of Singularity от Oxides Games.
Технология Multi-GPU
Но сначала позвольте сказать пару слов о технологии multi-GPU: появление интерфейса PCI Express для взаимодействия видеокарты и остальной системы привел к тому, что AMD и NVIDIA смогли использовать технологию AFR (Alternate Frame Rendering) для простой поддержки multi-GPU. AFR подразумевает поочередное вычисление кадров на каждом GPU. Вносить какие-либо изменения в игру или игровой движок при этом не требуется. Разработчикам AMD и NVIDIA достаточно внести в драйверы соответствующую поддержку, чтобы отличия по времени вывода отдельных кадров не приводили к появлению артефактов. AMD представила технологию сглаживания кадров Frame Pacing, NVIDIA тоже ответила собственной аппаратно-программной технологией. Кроме того, синхронизация частоты кадров между GPU и панелью дисплея в виде FreeSync и G-Sync позволяет минимизировать появление артефактов.
Но выбор аппаратной платформы оставался ограниченным. NVIDIA позволяла взаимодействие только идентичных моделей видеокарт, AMD предоставила большую гибкость, по крайней мере, использование видеокарт на одном GPU (например, Radeon R9 290 и Radeon R9 290X). Конечно, тому есть причина – видеокарты разного уровня производительности не могут в AFR рассчитывать кадры за сравнимое время. Решение может заключаться в технологии SFR (Spit Frame Rendering), но она так и не стала популярной. О SFR мы поговорим чуть позже.
Впрочем, уже совершались попытки объединить видеокарты разных производителей без использования официальных режимов SLI и Crossfire. В 2010 году LucidLogix представила технологию Hydra. С помощью дополнительного чипа и программного обеспечения технология распределяла вызовы DirectX и OpenGL между совместимыми видеокартами. Но при этом имелись весьма серьезные ограничения по аппаратной базе и по программной поддержке. Все это привело к тому, что технология Hydra так и не смогла набрать популярность, уйдя в небытие.
DirectX 12 и Multi-Adapter
С появлением DirectX 12 Microsoft представила три режима multi-adapter. В самом простом случае используется упомянутая выше технология AFR с видеокартами одного производителя AMD или NVIDIA. Но данный режим ограничивает возможности игровых разработчиков, но вместе с тем уменьшает вероятность потенциального возникновения ошибки из-за глубокого доступа к «железу». Большая часть работы для поддержки выполняется в драйвере, а не под DirectX 12.
DirectX 12 обеспечивает более глубокий доступ к «железу» даже в системах multi-GPU. Для этого Microsoft представила режим Explicit Multi-Adapter (EMA). В нем игровые разработчики явно задают параметры поддержки multi-GPU. Для каждого одиночного GPU определяется доступ к памяти, описывается взаимодействие GPU между собой – и вся эта поддержка должна быть запрограммирована заранее. Ответственность за работу связки видеокарт теперь полностью лежит в руках разработчиков, что привносит определенные риски. Дополнительные усилия разработчиков не стоит недооценивать, а ошибки должен будет исправлять разработчик, а не Microsoft, AMD или NVIDIA.
В режиме EMA возможны два разных режима: Linked Mode и Unlinked Mode. В режиме Unlinked Mode обеспечивается базовая функциональность EMA, в режиме Linked Mode функциональность расширяется, но ограничения по используемому в комбинации «железу» становятся более строгими. Например, можно использовать только системы SLI и CrossFire под DirectX 12. В режиме Unlinked Mode вы можете комбинировать разные видеокарты, в том числе и от разных производителей. Возможна комбинация дискретного и интегрированного GPU.
В режиме Unlinked Mode каждый графический процессор считается самостоятельной аппаратной единицей, со своей памятью, командным процессором и т.д. EMA под DirectX 12 позволяет обмениваться данными между аппаратными единицами, причем на глубоком уровне, а не просто готовыми кадрами. Можно обмениваться частично просчитанными кадрами или данными в буферах, что позволяет выйти на новые уровни совместного рендеринга на нескольких GPU. На первый взгляд все звучит просто, стал возможен обмен данными, что открывает доступ к алгоритмам, ранее недоступным. Но на практике все сложнее. Данные придется передавать по интерфейсу PCI Express, что намного медленнее связи между GPU и локальной видеопамятью, да и задержки довольно большие. Так что разработчикам следует определить, какие данные имеет смысл передавать между GPU, чтобы интерфейс PCI Express не стал «узким местом». Также следует определиться, в каком виде передавать данные. У разных производителей и даже разных поколений GPU зачастую используются разные форматы данных, которые не всегда просто перевести из одного в другой. Придется прилагать дополнительные усилия, необходимые для реализации EMA в Unlinked Mode. Впрочем, фокусом Unlinked Mode в EMA является все же совместная работа дискретных и интегрированных GPU, но и здесь могут использоваться GPU разных производителей.
Режим Linked Mode можно рассматривать как форму SLI или Crossfire под DirectX 12, аппаратные ресурсы в Linked Mode комбинируются в своего рода «видеокарту». Пользователь и игровой движок «видят» только один GPU и память. Аппаратные ресурсы здесь будут использоваться более тесно и глубоко, что открывает больше возможностей, но при этом накладываются дополнительные ограничения на «железо». Самый большой потенциал производительности можно будет раскрыть через Linked Mode, а самый большой уровень гибкости – через Unlinked Mode. Если разработчики хотят приложить минимальные усилия, и им достаточно базовой функциональности системы multi-GPU, то достаточно поддержать простой вариант EMA, доверившись квалификации разработчиков драйверов AMD и NVIDIA. Но поскольку только разработчики игры в полной мере владеют всеми нюансами своего продукта, то поддержка Linked и Unlinked Mode тоже весьма желательна.
EMA в Ashes of Singularity
Oxides Games и Ashes of Singularity на прошлой неделе открыли ранний доступ Steam к своей игре. Стратегия реального времени должна выйти в 2016 году. Она станет первой игрой данного жанра с поддержкой DirectX 12, а разработчики Oxides Games первыми постарались полностью задействовать возможности DirectX 12. AMD и Microsoft в сотрудничестве со студией разработчиков смогли построить технологическую демонстрацию на основе игры. Для демонстрации EMA разработчики Oxides Games использовали технологию AFR. Они управляли распределением кадров по отдельным GPU – ранее эту работу выполнял драйвер. Также разработчикам пришлось самостоятельно решать вопрос передачи кадров от дополнительных GPU на основной, а также реализовывать сглаживание частоты кадров (Frame Pacing). Технология AFR лучше всего работает при использовании идентичных видеокарт, поскольку они справляются с расчетом кадров за близкое время. В любом случае, данная реализация идет дальше, чем привычные варианты AMD и NVIDIA. Вы можете комбинировать разные GPU от разных производителей, что позволяет одновременно работать, например, GeForce GTX Titan X с GeForce GTX 980 Ti. Но для работы все видеокарты должны поддерживать DirectX 12. И наши коллеги Anandtech провели многочисленные тесты.
Игра Ashes of Singularity по-прежнему находится в альфа-состоянии. И поддержка Unlinked Mode EMA является экспериментальной. Можно использовать только определенную комбинацию драйверов AMD и NVIDIA, но результаты оказались намного лучше, чем можно было ожидать. Oxides Games сначала будет улучшать Unlinked Mode, после чего перейдет к поддержке Linked Mode. Здесь ожидается прирост производительности в диапазоне 5-10%.
Ниже приведены результаты первых тестов:
Пару слов о результатах. Прирост производительности пары Radeon R9 X Fury и Radeon R9 Fury оказался весьма впечатляющим, то же самое можно сказать о смешанном режиме Radeon R9 Fury X и GeForce GTX 980 Ti. Выбор других основных видеокарт дает уже меньшую разницу. От Unlinked Mode могут выиграть даже старые видеокарты.
В BUILD 2015 Microsoft уже представила функционирующий режим Unlinked Mode в теории, но появление независимых тестов можно назвать хорошим признаком, указывающим на текущее состояние разработки. Но все же пока еще можно говорить только о раннем состоянии перехода с DirectX 11 на DirectX 12. Пройдет несколько месяцев, прежде чем на рынке начнут появляться игры. А до поддержки DirectX 12 всеми разработчиками пройдут годы. То же самое касается реализации всех сопредельных технологий. Большинство разработчиков наверняка довольно быстро воспользуются преимуществом производительности благодаря уменьшению избыточной нагрузки. Но до повсеместной реализации EMA, режимов Unlinked и Linked Mode пройдет намного больше времени. Геймерам пока только остается ждать соответствующей поддержки со стороны разработчиков.
DirectX 12 — от Леонардо да Винчи к современному искусству
Компьютерная графика — обширная и быстроразвивающаяся дисциплина. С каждым годом интерфейсы прикладного программирования становятся более гибкими, что позволяет на их основе реализовывать более сложные алгоритмы формирования и обработки изображений. Однако возможности интерактивной графики не достигли уровня пакетов 3d-моделирования и визуализации. Все это подталкивает к активным исследованиям в данной области.
DirectX 12 — компонент интерфейса программирования высокопроизводительной графики. Основные цели нового интерфейса — снижение CPU-оверхеда драйвера, понижение уровня абстрагирования оборудования, возможность объединения графических карт на уровне API (до этого существовали только vender-specific решения CrossFireX, NVIDIA SLI). Официально выпущен Microsoft в июле 2015.
Статья рассчитана на тех, кто уже работал с графическими библиотеками (OpenGL, DirectX 11). Однако для людей, которые планирует начать изучение графики именно с 12 версии возможно тоже будет полезной.
В ней мы рассмотрим следующие темы:
Окружение
DirectX 12 является частью Windows SDK в Windows 10. В качестве IDE используем Visual Studio, язык программирования C++. Для работы с DirectX, необходимо подключить хедеры d3d12.h dxgi1_6.h и библиотеки d3d12.lib, dxguid.lib, dxgi.lib, d3dcompiler.lib. Все это лежит в стандартных каталогах Windows SDK. Так же распространяется «D3D12 Helper Library» в виде одного заголовочного файла d3dx12.h, она позволяет сократить количество boilerplate кода. Его можно просто скачать по адресу d3dx12.h и вложить в проект.
Краткое описание графического пайплайна
В основе графической библиотеки лежат функции рисования, которые запускают графический конвейер — программно-аппаратное средство визуализации трехмерной графики. Аппаратная составляющая представлена видеоадаптером, программная — драйвером. Графический конвейер можно представить в виде черного ящика, разделенного на этапы и выполняющего необходимые преобразования. Содержимое этого черного ящика может быть различным. Выполняемые преобразования зависят от назначения графической системы, стоимости, требуемого уровня универсальности и многих других факторов. Также, конкретный видеоадаптер — сложный механизм, правила работы которого зачастую известны лишь непосредственно производителю.
Итак, на сегодняшний день процесс визуализации трехмерной сцены выглядит в общих чертах следующим образом.
Преобразование вершин
Каждая вершина имеет определенный набор атрибутов таких, как позиция, цвет, текстурные координаты, вектор нормали или все векторы из касательного пространства и, возможно, некоторые другие. Трансформация вершин — это первая стадия графического конвейера. На этом этапе входными данными являются атрибуты конкретной вершины, над которыми производятся математические преобразования. Эти операции включают трансформацию позиции вершины, генерацию и преобразование текстурных координат, расчет освещения для каждой отдельной вершины, а также любые другие операции, которые необходимо выполнить на уровне вершин. Каждая вершина обрабатывается параллельно с другими вершинами на доступных ядрах графического ускорителя. Основной результат вершинной программы — преобразовать координаты из модельного пространства в специальное пространство отсечения (clip space).
Построение примитивов и растеризация
Входные данные этого этапа — трансформированные вершины, а также информация о их соединении. Из этих данных осуществляется сборка геометрических примитивов. В результате получается последовательность треугольников, линий или точек. Над этими примитивами может производиться отсечение плоскостям, определенными в программе. Также на этом этапе могут быть отброшены задние треугольники объектов. Определяются эти треугольники по направлению обхода вершин (по часовой стрелке или против). Какое направление обхода соответствует заднему треугольнику задается через графическое API. Полигоны, прошедшие отсечение, могут растеризироваться.
Текстурирование и окрашивание
Над атрибутами примитивов, растеризированных в набор фрагментов, на этой стадии проводится необходимая интерполяция, а также последовательность математических преобразований и операций текстурирования, что определяет конечный цвет каждого фрагмента. Также на этом этапе может определяться новая глубина или даже исключение фрагмента из буфера кадра.
Пофрагментные операции
На этом этапе проводится ряд пофрагментных тестов, таких как тест отсечения (scissor test), тест трафарета (stencil test) и тест глубины (depth test). Эти тесты определяют конечный вид, цвет и глубину фрагмента перед обновлением экранного буфера. Если какой-либо тест проходит с ошибкой, то фрагмент не обновляется. После тестов выполняется операция смешивания, которая комбинирует финальный цвет фрагмента с текущим цветом пиксела, а итоговый результат записывается в экранный буфер. Операция смешивания выполняется на этом этапе, поскольку стадия текстурирования и окрашивания не имеют доступа к экранному буферу.
Более детальное устройство конвейера можно посмотреть в спецификации DirectX 11 (документ по DiretcX 12 затрагивает лишь изменения с предыдущей версией)
Новые возможности DirectX 12
Мы переходим от теоретической части непосредственно к описанию конкретных возможностей DirectX 12.
Состояния
В 11 версии программистам известны различные функции изменения состояний графического ускорителя: RSSetState(), OMSetDepthStencilState(), OMSetBlendState(). Оказалось, что такой подход плохо ложится на оборудование. В конечном итоге драйвер устанавливает адаптеру одно монолитное состояние, а отдельные вызовы или некоторые комбинации состояний могли приводить к непредсказуемым задержкам со стороны драйвера. В новой версии инженеры переосмыслили этот подход и исключили атомарное изменений состояний, теперь они объединены в одно — PSO (Pipeline State Object). Такое нововведение кажется более удобным со стороны пользователя: теперь не нужно беспокоиться о «висячих состояниях», которые остались с прошлых проходов. Более того, для лучшей эффективности установки, теперь дополнительно требуется передавать информацию о всех прикрепленных ресурсах в шейдер через Root Signature (об этом ниже).
Команды
В ранних версиях пользователи отправляли команды через так называемый immideate context. Под капотом создавались отложенные командные очереди и по мере заполнения отправлялись оборудованию. Необходимо отметить, что в DirectX 11 существует возможность создания deferred context. В DirectX 12 immideate context был исключен и deferred концепция стала основной. Теперь программист должен заполнить deferred command list, и в необходимый момент отправить его на исполнение.
Таким образом, реализация двойной и тройной буферизаций теперь выглядит более явно: создаются соответствующее количество command list, как только они заполнены, CPU переходит в режим ожидания свободного листа.
Здесь же стоит упомянуть о ресурсах, которые прикреплены к конкретному командному листу. Теперь удаление ресурса, использующегося на GPU, ведет к непредсказуемым последствиям. Например, раньше легально было выполнить Release() для текстуры которая еще используются — драйвер автоматически отследит, когда ресурс перестанет использоваться и только после этого удалит его.
Синхронизация
Для возможности отслеживания работы GPU, DirectX 12 предоставляет концепцию fence, которая инкапсулирована объектом ID3D12Fence интерфейсом. Fence — это целое число, которое представляет выполненную работу GPU на текущий момент. Сначала происходит эмитинг следующего «свободного» значения, вызывая ID3D12CommandQueue::Signal() в командной очереди. Затем с помощью ID3D12Fence::SetEventOnCompletion(UINT64 Value, HANDLE hEvent) происходит ассоциирование значения с примитивом winapi event. Теперь поток с помощью WaitForSingleObject() над подготовленным event-ом может приостановить выполнение до момента выполнения всей работы, предшествующий контрольному значению. Как только вся работа на GPU выполнится, значение в fence обновится, вызов WaitForSingleObject() разблокируется и поток продолжит выполнение.
Прикрепление ресурсов
Биндинг ресурсов в шейдер — одна из самых запутанных тем современного DirectX.
Обзор
В DirectX 11 использовалась следующая модель биндинга: каждый ресурс устанавливался в шейдер соответствующим вызовом API. Например, для установки двух текстур (если не задумываться о семплерах) в 5 и 6 слоты пиксельного шейдера применялся следующий код:
Где GetShaderResourceView() возвращает указатель на объект типа ID3D11ShaderResourceView.
В шейдере затем текстуры использовались так:
Такая система достаточно удобная со стороны программиста, но с точки зрения графического ускорителя нет. Допустим, нам необходимо прикрепить текстуру на чтение в шейдере. Как должна быть передана информация о текстуре? Если мы заглянем в документацию GCN ISA, найдем следующий параграф:
All vector memory operations use an image resource constant (T#) that is a 128- or 256-bit value in SGPRs. This constant is sent to the texture cache when the instruction is executed. This constant defines the address, data format, and characteristics of the surface in memory.
Это означает, что для того чтобы описать текстуру, нам нужен этот небольшой дескриптор (128 или 256-битный), который нужно поместить в любое место памяти. Если мы прочтем остальную часть документации, мы заметим, что этот же шаблон также используется для всех других типов ресурсов. Фактически, когда дело доходит до доступа к ресурсу, понятие «слот» бессмысленно. Графический адаптер оперирует дескрипторами: текстуры (T#), сэмплера (S#) или константы (V#). С Direct3D 12 эти дескрипторы, наконец, отображаются непосредственно на дескрипторы оборудования — некоторая память GPU.
Дескрипторы
Сейчас ресурсы не прикрепляются в графический пайплайн прямо через вызовы методов, прикрепление происходит опосредовано через дескрипторы. Дескриптор — небольшой кусочек памяти, который содержит информацию о ресурсе (GPU виртуальный адрес, и, например, количество мипов, формат). Множество дескрипторов хранятся в дескрипторной куче — это просто массив дескрипторов фиксированного размера. Дескрипторные кучи могут содержать информацию о разных типах ресурсов:
CBVs, UAVs, SRVs могут содержаться в одной дескрипторной куче, а описания семплеров — в отдельной. Это разделение выражает тот факт, что семплеры в ускорителе обрабатываются отдельно.
Выше мы упомянули так называемые shader visible ресурсы. Соответственно, существуют non shader visible ресурсы:
Такие views ресурсов предназначаются только для прикрепления ресурса в пайплан (но не для использования в шейдере), и поэтому их нужно создавать в отдельной non shader visible дескрипторной куче (это задается флагом D3D12_DESCRIPTOR_HEAP_FLAGS::D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE при создании кучи).
Есть еще одна группа view’s, для которых дескрипторы (и, соответственно, дескрипторная куча) не требуются:
Представлены типами D3D12_INDEX_BUFFER_VIEW и D3D12_VERTEX_BUFFER_VIEW соответственно. То есть описания индексных и вершинных буферов содержатся в указанных выше структурах и затем передаются напрямую в Pipeline State Object. Вся память в PSO автоматически версионируется драйвером.
Таким образом, теперь вместо создания множества объектов типа ID3D11. View, мы создаем дескрипторы в дескрипторной куче.
Root signature
Root signature — объект DirectX 12 API который задает соответствие лэйаута дескрипторов и данных в слоты шейдера. Это, в некотором смысле, действительно сигнатура шейдера только с точки зрения использования ресурсов. Root signature не содержит конкретных дескрипторов и данных, она лишь задает лэйаут (устройство) дескрипторов, которые биндятся уже позднее на этапе рендеринга.
Root signature состоит из массив записей, которые называются root parameter. Действительные данные root parameter устанавливаются в рантайме и называются root arguments. Меняя root argument, меняются данные которые читает шейдер. Root parameter бывают трех типов:
Максимальный размер root signature — 64 DWORDs. Типы отсортированы по возрастанию уровня косвенности доступа ресурса в шейдере, но по убыванию возможностей.
Root constant это встроенное в root signature 32-битное значение, которое используется в шейдере как constant buffer. Предназначается для наиболее активно изменяющихся констант (например, MVP матрицы), но имеет жесткие ограничения на максимальный размер (всего поместится 4 матрицы). Так же такие данные доступны в шейдере с нулевым уровнем косвенности, и имеют более быстрый доступ чем все остальные способы. Полностью версионируются драйвером: их можно «установить и забыть».
Приложение может поместить дескрипторы напрямую в root signature во избежании хранения дескрипторов в куче дескрипторов — это второй способ inline descriptors. Пример таких данных — константа per object. Таким образом, не нужно беспокоиться о свободном месте в куче дескрипторов. Имеет первый уровень косвенности. Версионируется сам дескриптор (то есть описание ресурса), но ресурс который описывает этот дескриптор должен быть доступен до завершения его использования на GPU. Установка конкретных данных производится, например, методом ID3D12GraphicsCommandList::SetGraphicsRootConstantBufferView, в него передается индекс root parameter нашего inline descriptor и виртуальный адрес буфера.
Мы подошли к третьему, основному и универсальному способу прикрепления ресурсов. Таблица дескрипторов содержит массив descriptor range. Descriptor range — описание непрерывной цепочки дескрипторов определенного типа. Описание одной записи в таблицы дескрипторов проще показать кодом:
Видим, что RangeType — указывает тип дескриптора, NumDescriptors — количество, BaseShaderRegister — номер регистра внутри шейдера. Остальные параметры служат для расширенной настройки и пока не будем их рассматривать. В рантайме дескрипторы устанавливаются методом ID3D12GraphicsCommandList::SetGraphicsRootDescriptorTable, в него передается индекс root parameter нашей таблицы дескрипторов и первый дескриптор. Все дескрипторы, указанные в описании таблицы дескрипторов, подхватываются автоматически. Из этого следует, что они должны располагаться непрерывно друг за другом в descriptor heap.
Заключение
Мы рассмотрели некоторые возможности DirectX 12. Если вам интересная данная тема или любая другая из области компьютерной графики, отписывайтесь в комментариях.