Перенос из 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. Выделенный ресурс — это ресурс, имеющий как виртуальное адресное пространство, так и физические страницы, связанные с ним. Это концепция модели памяти драйвера устройств Microsoft Windows 2 (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 для графического ядра), который затем присоединяется к списку команд перед вызовом рисования с вызовом 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*
Рисование, DrawInstanced DrawInstanced
DrawIndexed, DrawIndexedInstanced DrawIndexedInstanced
Подготовка к отправке Подготовка к отправке
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 , является simliar в отложенный контекст. Direct3D 12 также поддерживает возможность доступа к некоторым функциям немедленного контекста одновременной отрисовки через D3D12_COMMAND_LIST_TYPE_COPY и D3D12_COMMAND_LIST_TYPE_COMPUTE типы списков команд.

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

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

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

Основным объектом для синхронизации временных шкал является объект ID3D12Fence. Операция заборов довольно простая, они позволяют GPU сигнализировать о завершении задачи. 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, где между ними существует одно сопоставление.

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

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

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

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

 

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

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

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

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

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

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

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

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

Цепочка буферов 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 ресурса (мини-уровень детализации) Это было перемещено в статический дескриптор SRV MinLOD.
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