Перенос из Direct3D 11 в Direct3D 12

В этом разделе приведены некоторые рекомендации по переносу из пользовательского графического модуля Direct3D 11 в Direct3D 12.

Создание устройства

И Direct3D 11, и Direct3D 12 используют аналогичный шаблон создания устройств. Все существующие драйверы Direct3D 12 D3D_FEATURE_LEVEL_11_0 или более поздней версии, поэтому вы можете игнорировать старые уровни функций и связанные с ними ограничения.

Кроме того, помните, что в Direct3D 12 следует явно перечислять сведения об устройстве с помощью интерфейсов DXGI. В Direct3D 11 можно выполнить обратную привязку к устройству DXGI с устройства Direct3D, и это не поддерживается для Direct3D 12.

Создание программного устройства WARP в Direct3D 12 выполняется путем предоставления явного адаптера, полученного из IDXGIFactory4::EnumWarpAdapter. Устройство WARP для Direct3D 12 доступно только в системах с включенной необязательной функцией Графические инструменты .

Примечание

Нет эквивалента D3D11CreateDeviceAndSwapChain. Даже в Direct3D 11 мы не рекомендуем использовать эту функцию, так как зачастую лучше создавать устройство и цепочку переключения в разных шагах.

Зафиксированные ресурсы

Объекты, созданные с помощью следующих интерфейсов в Direct3D 11, преобразуются в так называемые "зафиксированные ресурсы" в Direct3D 12. Зафиксированный ресурс — это ресурс, с которым связано как виртуальное адресное пространство, так и физические страницы. Это концепция модели памяти драйвера 2 устройства Microsoft Windows (WDD2), на которой основан Direct3D 12.

Ресурсы Direct3D 11:

В Direct3D 12 все они представлены ID3D12Resource и ID3D12Device::CreateCommittedResource.

Зарезервированные ресурсы

Зарезервированные ресурсы — это ресурсы, для которых выделено только виртуальное адресное пространство, а физическая память не выделяется, пока не будет выполнен вызов ID3D12Device::CreateHeap. По сути, это та же концепция, что и мозаичного ресурса в Direct3D 11.

Флаги (D3D11_RESOURCE_MISC_FLAG), используемые в Direct3D 11 для настройки плиток ресурсов, а затем сопоставляют их с физической памятью.

  • D3D11_RESOURCE_MISC_TILED
  • D3D11_RESOURCE_MISC_TILE_POOL

Отправка данных

В Direct3D 11 есть внешний вид одного временная шкала (вызывает следующую последовательность, например данные, инициализированные с помощью D3D11_SUBRESOURCE_DATA, затем выполняется вызов ID3D11DeviceContext::UpdateSubresource, а затем вызов ID3D11DeviceContext::Map). Количество созданных копий данных не очевидно для разработчика Direct3D 11.

В Direct3D 12 есть две временные шкалы: gpu временная шкала (настраивается с помощью вызовов CopyTextureRegion и CopyBufferRegion из сопоставляемой памяти) и временная шкала ЦП (определяется вызовами map). Вспомогательные функции предоставляются (в файле d3dx12.h), называемые Updatesubresources, которые используют общий временная шкала. Существует несколько вариантов этой вспомогательной функции: одна использует ID3D12Device::GetCopyableFootprints, другая — механизм выделения кучи, а другая — механизм выделения стека. Эти вспомогательные функции копируют ресурсы в GPU и ЦП через промежуточную промежуточную область памяти.

Как правило, GPU и ЦП имеют собственную копию ресурса, привязанную к собственной временная шкала. Подход с общим временная шкала аналогичным образом поддерживает две копии.

Шейдеры и объекты шейдеров

В Direct3D 11 существует множество объектов шейдера и состояния, а также установка состояния этих объектов с помощью методов создания ID3D11Device и методов ID3D11DeviceContext . Обычно к этим методам выполняется большое количество вызовов, которые затем объединяются во время рисования драйвером для установки правильного состояния конвейера.

В Direct3D 12 этот параметр состояния конвейера был объединен в один объект (CreateComputePipelineState для вычислительной подсистемы и CreateGraphicsPipelineState для графического обработчика), который затем присоединяется к списку команд перед вызовом draw с вызовом SetPipelineState.

Эти вызовы заменяют все отдельные вызовы для задания шейдеров, макета ввода, состояния наложения, состояния растеризатора, состояния трафарета глубины и т. д. в Direct3D 11

  • Методы устройства 11: CreateInputLayout, CreateXShader, CreateDepthStencilStateи CreateRasterizerState.
  • Методы контекста устройства 11: IASetInputLayout, xxSetShader, OMSetBlendState, OMSetDepthStencilStateи RSSetState.

Хотя Direct3D 12 может поддерживать более старые скомпилированные большие двоичные объекты шейдеров, шейдеры должны создаваться с использованием либо модели шейдера 5.1 с API-интерфейсами FXC/D3DCompile, либо с помощью модели шейдера 6 с помощью компилятора DXIL DXC. Необходимо проверить поддержку модели шейдера 6 с помощью CheckFeatureSupport и D3D12_FEATURE_SHADER_MODEL.

Отправка работы в GPU

В Direct3D 11 практически не контролируется способ отправки работы, он в значительной степени обрабатывается драйвером, хотя некоторые возможности управления включаются через вызовы ID3D11DeviceContext::Flush и IDXGISwapChain1::P resent1 .

В Direct3D 12 отправка работы очень явная и контролируется приложением. Основной конструкцией для отправки трудозатрат является ID3D12GraphicsCommandList, который используется для записи всех команд приложений (и по сути похож на отложенный контекст ID3D11). Резервное хранилище для списка команд предоставляется id3D12CommandAllocator, который позволяет приложению управлять использованием памяти списка команд, фактически предоставляя память, которую драйвер Direct3D 12 будет использовать для хранения списка команд.

Наконец , ID3D12CommandQueue — это очередь первого входа, в которой хранится правильный порядок списков команд для отправки в GPU. Драйвер отправляет следующий список команд из очереди только после завершения выполнения в GPU.

В Direct3D 11 отсутствует явная концепция очереди команд. В общей конфигурации для Direct3D 12 открытый список команд D3D12_COMMAND_LIST_TYPE_DIRECT для текущего кадра можно считать аналогичным контексту Direct3D 11. Это обеспечивает многие из одинаковых функций.

D3D11DeviceContext ID3D12GraphicsCommand List
ClearDepthStencilView ClearDepthStencilView
ClearRenderTargetView ClearRenderTargetView
ClearUnorderedAccess* ClearUnorderedAccess*
Draw, DrawInstanced DrawInstanced
DrawIndexed, DrawIndexedInstanced DrawIndexedInstanced
Dispatch Dispatch
IASetInputLayout, xxSetShader и т. д. SetPipelineState
OMSetBlendState OMSetBlendFactor
OMSetDepthStencilState OMSetStencilRef
OMSetRenderTargets OMSetRenderTargets
RSSetViewports RSSetViewports
RSSetScissorRects RSSetScissorRects
IASetPrimitiveTopology IASetPrimitiveTopology
IASetVertexBuffers IASetVertexBuffers
IASetIndexBuffer IASetIndexBuffer
ResolveSubresource ResolveSubresource
CopySubresourceRegion CopyBufferRegion
UpdateSubresource CopyTextureRegion
CopyResource CopyResource

Примечание

Список команд, созданный с помощью D3D12_COMMAND_LIST_TYPE_BUNDLE , соответствует отложенным контекстам. Direct3D 12 также поддерживает функцию abiilty для доступа к некоторым функциям непосредственного контекста , одновременным к отрисовке с помощью D3D12_COMMAND_LIST_TYPE_COPY и D3D12_COMMAND_LIST_TYPE_COMPUTE типов списков команд.

Синхронизация ЦП и GPU

В Direct3D 11 синхронизация ЦП и GPU в основном была автоматической, и приложению не было необходимости поддерживать состояние физической памяти.

В Direct3D 12 приложение должно явно управлять двумя временными шкалами (ЦП и GPU). Это требует, чтобы приложение поддерживало информацию о том, какие ресурсы требуются GPU и как долго. Это также означает, что приложение отвечает за то, чтобы содержимое ресурсов (например, выделенных ресурсов, кучи, распределителей команд) не изменялось до тех пор, пока GPU не завершит их использование.

Объект main для синхронизации временных шкал — это объект ID3D12Fence. Работа с ограждениями довольно проста, они позволяют GPU сигнализировать о завершении задачи. GPU и ЦП могут сигнализировать и ждать на ограждениях.

Как правило, при отправке списка команд для выполнения графический процессор передает сигнал ограждения по завершении (после завершения чтения данных), что позволяет ЦП повторно использовать или уничтожать ресурсы.

В Direct3D 11 флаг ID3D11DeviceContext::Map D3D11_MAP_WRITE_DISCARD по существу рассматривал каждый ресурс как бесконечный объем памяти, в который может записывать приложение (процесс называется переименованием). В Direct3D 12 процесс опять же является явным: необходимо выделить дополнительную память и использовать ограждения для синхронизации операций. Кольцевые буферы (состоящие из больших буферов) могут быть хорошим способом. См. сценарий кольцевого буфера в разделе Управление ресурсами на основе ограждения.

использование кольцевого буфера

Привязка ресурсов

Представления в Direct3D 11 (представления ресурсов шейдера, целевые представления отрисовки и т. д.) в основном заменены в Direct3D 12 понятием дескриптора. Методы создания по-прежнему существуют в Direct3D 12 (например , CreateShaderResourceView и CreateRenderTargetView), которые вызываются после создания кучи дескриптора для записи данных в кучу. Привязка в Direct3D 12 теперь обрабатывается дескрипторными дескрипторами, описанными в корневой сигнатуре, и отправляется с помощью методов SetGraphicsRootDescriptorTable или SetComputeRootDescriptorTable .

Корневые сигнатуры содержат сведения о сопоставлениях между номерами слотов корневой сигнатуры и таблицами дескрипторов, где таблица дескриптора может содержать ссылки на ресурсы, доступные для вершинных шейдеров, пиксельных шейдеров и других шейдеров, таких как буферы констант, представления ресурсов шейдеров и выборки. Эта гибкость отключает пространство регистров HLSL от пространства привязки API в Direct3D 12, в отличие от Direct3D 11, где существует сопоставление "один к одному" между ними.

Одним из последствий этой системы является то, что приложение отвечает за переименование таблиц дескрипторов, что позволяет разработчикам понять затраты на производительность, связанные с изменением даже одного дескриптора на вызов draw.

Новая функция Direct3D 12 заключается в том, что приложение может контролировать, какие дескрипторы являются общими между этапами шейдера. В Direct3D 11 ресурсы, такие как БПЛА, являются общими для всех этапов шейдера. Если включить дескрипторы для определенных этапов шейдера, регистры, используемые отключенными дескрипторами, доступны для использования дескрипторами, включенными для определенного этапа шейдера.

В следующей таблице показан пример корневой сигнатуры.

Корневой слот параметров Запись таблицы дескриптора
0 Диапазон дескриптора VS b0–b13
1 Диапазон дескриптора VS t0–t127
2 Диапазон дескриптора VS s0–s16
3 Диапазон дескриптора PS b0–b13
...
14 Диапазон дескриптора DS s0–16
15 Диапазон общего дескриптора u0–u63

 

Состояние ресурса

В Direct3D 11 состояние ресурса поддерживается не приложением, а драйвером.

В Direct3D 12 поддержание состояния ресурсов становится обязанностью приложения, чтобы включить полный параллелизм в записи списков команд: приложение должно обрабатывать временные шкалы записи для списков команд (которые можно выполнять параллельно) и временные шкалы выполнения, которые должны быть последовательными.

Переход состояния ресурса обрабатывается методом ResourceBarrier . В первую очередь приложение должно информировать драйвер при изменении использования ресурсов. Например, если ресурс используется в качестве целевого объекта отрисовки, а затем он будет использоваться в качестве входных данных для вершинного шейдера при следующем вызове draw, то для завершения целевой операции отрисовки перед обработкой вершинного шейдера может потребоваться короткая приостановка операции GPU.

Эта система обеспечивает тонкую синхронизацию (остановки GPU) графического конвейера, а также очистку кэша и, возможно, некоторые изменения макета памяти (например, отрисовка целевого представления для распаковки трафарета глубины).

Это называется переходным барьером. Существуют и другие виды барьеров. В Direct3D 11 ID3D11DeviceContext2::TiledResourceBarrier включил одну и ту же физическую память, используемую двумя разными мозаичными ресурсами. В Direct3D 12 это называется "барьером псевдонима". Барьеры псевдонимов можно использовать как для плиток, так и для размещенных ресурсов в Direct3D 12. Кроме того, существует барьер для БПЛА. В Direct3D 11 все операции отправки и отрисовки UAV должны быть сериализованы, даже если эти операции могут быть конвейерированы или работать параллельно. Для Direct3D 12 это ограничение снимается путем добавления барьера для БПЛА. Барьер БПЛА гарантирует, что операции БПЛА выполняются последовательно, поэтому, если вторая операция требует завершения первой операции, вторая будет вынуждена ждать добавления барьера. Операция по умолчанию для БПЛА просто заключается в том, что операции будут выполняться как можно быстрее.

Очевидно, что производительность достигается, если рабочая нагрузка может быть параллельной.

Буферные цепочки

Цепочка буферов DXGI является основой для цепочек буферов в Direct3D 11 и 12. Существуют некоторые незначительные различия. В Direct3D 11 три типа цепочки буферов: SEQUENTIAL, DISCARD и FLIP_SEQUENTIAL. Для Direct3D 12 существует только два типа: FLIP_SEQUENTIAL и FLIP_DISCARD. Как отмечалось выше, следует явно создать цепочку буферов с помощью IDXGIFactory4 или более поздней версии и использовать тот же интерфейс для любого перечисления адаптера.

В Direct3D 11 выполняется автоматическая смена обратного буфера: для обратного буфера 0 требуется только одно целевое представление отрисовки. В Direct3D 12 поворот буфера является явным, для каждого обратного буфера должно быть целевое представление отрисовки. Используйте метод IDXGISwapChain3::GetCurrentBackBufferIndex , чтобы выбрать метод для отрисовки. Опять же, эта дополнительная гибкость обеспечивает большую параллелизацию.

Примечание

Хотя существует множество способов настройки приложения, обычно приложения имеют один ID3D12CommandAllocator на буфер цепочки буферов. Это позволяет приложению приступить к созданию набора команд для следующего кадра, пока GPU отрисовывает предыдущий.

Исправлена отрисовка функции

В Direct3D 11 было несколько методов, которые упростили различные операции более высокого уровня, такие как GenerateMips (создание полных цепочек MIP) и DrawAuto (использование потокового вывода в качестве входных данных шейдера без дальнейших входных данных из приложения). Эти методы недоступны в Direct3D 12, приложение должно обрабатывать эти операции путем создания шейдеров для их выполнения.

Шансы и окончания

В следующей таблице показан ряд функций, которые похожи между Direct3D 11 и 12, но не идентичны.

Direct3D 11 Direct3D 12
ID3D11Query ID3D12QueryHeap позволяет группировать запросы, снижая затраты.
ID3D11Predicate Теперь предикация включается путем включения данных в полностью прозрачном буфере. Объект Direct3D 11 ID3D11Predicate заменяется на ID3D12Resource::Map, который должен следовать вызову ResolveQueryData и операции синхронизации GPU с использованием ограждения для ожидания подготовки данных. См. раздел Предикация.
Скрытый счетчик UAV/SO Приложение отвечает за распределение счетчиков SO/UAV и управление ими. См . раздел Счетчики потокового вывода и счетчики UAV.
Ресурсная динамическая MinLOD (минимальный уровень детализации) Он был перемещен в статический MinLOD дескриптора SRV.
Draw*Indirect/DispatchIndirect Непрямые методы рисования объединяются в один метод ExecuteIndirect .
Форматы DepthStencil чередуются Форматы DepthStencil являются планарными. Например, формат глубины 24 бита, 8 бит трафарета будут храниться в формате 24/8/24/8... и т. д. в Direct3D 11, но как 24/24/24... а затем 8/8/8... в Direct3D 12. Обратите внимание, что каждая плоскость является собственным подресурсом в D3D12 (см. подресурсы).
ResizeTilePool Зарезервированные ресурсы можно сопоставить с несколькими кучами. Если пул плиток был бы увеличен в D3D11, в D3D12 можно выделить дополнительную кучу.

 

Видеоруководии по расширенному обучению по DirectX: руководство по переносу DirectX 11 в DirectX 12

Основные сведения о Direct3D 12

Работа с Direct3D 11, Direct3D 10 и Direct2D