Перенос из Direct3D 11 в Direct3D 12
В этом разделе приведены некоторые рекомендации по переносу из пользовательского графического модуля Direct3D 11 в Direct3D 12.
- Создание устройства
- Выделенные ресурсы
- Зарезервированные ресурсы
- Отправка данных
- Шейдеры и объекты шейдеров
- Отправка работы на GPU
- Синхронизация ЦП и GPU
- Привязка ресурсов
- Состояние ресурса
- Буферные цепочки
- Фиксированная функция отрисовки
- Шансы и концы
- Связанные статьи
Создание устройства
Как 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:
- ID3D11Resource
- ID3D11Buffer и ID3D11Device::CreateBuffer
- ID3D11Texture1D и ID3D11Device:CreateTexture1D
- ID3D11Texture2D и ID3D11Device::CreateTexture2D
- ID3D11Texture3D и ID3D11Device::CreateTexture3D
В 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 с компилятором DXC. Необходимо проверить поддержку модели шейдера 6 с помощью CheckFeatureSupport и D3D12_FEATURE_SHADER_MODEL.
Отправка работы на GPU
В Direct3D 11 мало контроля над тем, как работа отправляется, поскольку это в значительной степени регулируется драйвером, хотя некоторый контроль возможен через вызовы
При отправке работы в 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 и т. д. | УстановитьСостояниеКонвейера |
OMSetBlendState | OMSetBlendFactor |
OMSetDepthStencilState | OMSetStencilRef |
OMSetRenderTargets | OMSetRenderTargets |
RSSetViewports | RSSetViewports |
RSSetScissorRects | RSSetScissorRects |
IASetPrimitiveTopology | IASetPrimitiveTopology |
IASetVertexBuffers | IASetVertexBuffers |
IASetIndexBuffer | IASetIndexBuffer |
ResolveSubresource | ResolveSubresource |
CopySubresourceRegion | CopyBufferRegion |
ОбновитьПодресурс | CopyTextureRegion |
CopyResource | CopyResource |
Примечание.
Список команд, созданный с помощью D3D12_COMMAND_LIST_TYPE_BUNDLE, похож на отложенный контекст. Direct3D 12 также поддерживает возможность одновременного доступа к некоторым функциям немедленного контекста при выполнении рендеринга через D3D12_COMMAND_LIST_TYPE_COPY и D3D12_COMMAND_LIST_TYPE_COMPUTE типы списков команд.
Синхронизация ЦП и GPU
В Direct3D 11 синхронизация ЦП и GPU была в значительной степени автоматической, и приложению не нужно поддерживать состояние физической памяти.
в Direct3D 12 приложение должно явно управлять двумя временными шкалами (ЦП и 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 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 . В первую очередь приложение должно сообщать водителю об изменении использования ресурсов. Например, если ресурс используется в качестве целевого объекта отрисовки, а затем он должен использоваться в качестве входных данных для шейдера вершин в следующем вызове рисования, то для выполнения целевой операции отрисовки может потребоваться короткая приостановка в операции gpu перед обработкой шейдера вершин.
Эта система обеспечивает финозернистую синхронизацию (задержки GPU) графического конвейера обработки, а также очистку кэша и, возможно, некоторые изменения макета памяти (например, декомпрессия представления целевого рендеринга в представление глубины и трафарета).
Это называется барьером перехода. Существуют и другие типы барьеров: в Direct3D 11 ID3D11DeviceContext2::TiledResourceBarrier позволял использовать одну и ту же физическую память для двух различных текстурируемых ресурсов. В Direct3D 12 это называется "барьером перекрытия". Барьеры синтаксиса можно использовать как для тайлованных, так и для расположенных ресурсов в Direct3D 12. Кроме того, существует барьер UAV. В Direct3D 11 все операции отправки и рисования UAV должны быть сериализованы, даже если эти операции могут быть конвейерированы или работать параллельно. Для Direct3D 12 это ограничение удаляется путем добавления барьера 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 с использованием фенса, чтобы дождаться готовности данных. См. предикат. |
Скрытый счетчик БПЛА/СО | Приложение отвечает за выделение счетчиков 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 можно выделить дополнительную кучу. |