Устройство Direct3D10 и Direct3D11 - SIISII/DirectX GitHub Wiki

Устройство Direct3D является, по сути, программным интерфейсом, позволяющим управлять работой видеоадаптера. В Direct3D10 оно обеспечивает создание различных ресурсов и выполнение собственно рендеринга. В Direct3D11 эти функции разделены: устройство Direct3D обеспечивает создание ресурсов и определение поддерживаемых оборудованием возможностей Direct3D, а собственно рендеринг выполняется с помощью так называемых контекстов устройства.

Возможно создание нескольких устройств — как правило, чтобы обеспечить вывод изображения в различные окна одновременно. Объекты, созданные с помощью некоторого устройства, могут использоваться только с этим устройством. Это касается и разделяемых объектов: они позволяют разным устройствам совместно использовать некоторые данные, однако собственно разделяемые объекты, обеспечивающие доступ к этим данным, всё равно должны использоваться только со своими устройствами.

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

Создание устройства в зависимости от используемой версии Direct3D выполняется одной из следующих функций:

В каждой из этих пар функций первая функция создаёт лишь само устройство Direct3D, а вторая функция — и устройство Direct3D, и связанную с ним цепочку переключения буферов. Последняя может быть создана отдельно с помощью соответствующей функции фабрики DXGI, причём обычно такой вариант является более предпочтительным (в современных программах она большинстве случаев создаётся вызовом метода IDXGIFactory2::CreateSwapChainForHwnd).

Из всех перечисленных функций наиболее полный набор параметров имеет D3D11CreateDeviceAndSwapChain, чей прототип выглядит следующим образом:

HRESULT  D3D11CreateDeviceAndSwapChain(
    IDXGIAdapter                *pAdapter,
    D3D_DRIVER_TYPE              DriverType,
    HMODULE                      Software,
    UINT                         Flags,
    const D3D_FEATURE_LEVEL     *pFeatureLevels,
    UINT                         FeatureLevels,
    UINT                         SDKVersion,
    const DXGI_SWAP_CHAIN_DESC  *pSwapChainDesc,
    IDXGISwapChain*             *ppSwapChain,
    ID3D11Device*               *ppDevice,
    D3D_FEATURE_LEVEL           *pFeatureLevel,
    ID3D11DeviceContext*        *ppImmediateContext);
  • pAdapter — указатель на интерфейс адаптера, для которого следует создать устройство. Если указан nullptr, устройство создаётся для первого из адаптеров, возвращаемых при их перечислении. Какая именно из потенциально доступных функций перечисления имеется в виду, не совсем ясно: документация говорит о функции IDXGIFactory1::EnumAdapters, однако эта функция изначально определена в интерфейсе IDXGIFactory, появившимся в составе DirectX 10, а не в IDXGIFactory1 из DirectX 11, где определена функция IDXGIFactory1::EnumAdapters1. Скорей всего, эти функции первым всегда возвращают один и тот же адаптер (к которому подключён монитор, считающийся в системе основным); это всегда так для систем, начиная с Windows 8 (в них обе функции перечисляют адаптеры в одинаковом порядке).

  • DriverType — тип адаптера, задаваемый одной из следующих констант:

    • D3D_DRIVER_TYPE_HARDWARE (D3D10_DRIVER_TYPE_HARDWARE для функций создания устройства Direct3D10 или Direct3D10.1) — реальное аппаратное устройство. Во всех обычных случаях используется только этот тип;

    • D3D_DRIVER_TYPE_REFERENCE (D3D10_DRIVER_TYPE_REFERENCE) — эталонное программное устройство. Осуществляет рендеринг чисто программными средствами на центральном процессоре; может использоваться для получения изображения, каким оно должно быть в соответствии с правилами Direct3D (например, для отладки драйверов аппаратуры). Всегда поддерживает все функциональные возможности Direct3D соответствующей версии;

    • D3D_DRIVER_TYPE_NULL (D3D10_DRIVER_TYPE_NULL) — пустое программное устройство, не способное осуществлять рендеринг вообще; используется для отладки вызовов API, не связанных с рендерингом;

    • D3D_DRIVER_TYPE_SOFTWARE (D3D10_DRIVER_TYPE_SOFTWARE) — чисто программное устройство; в Direct3D10 объявлено, но не используется. Данное устройство, в отличие от эталонного и WARP-устройств, реализовано в динамически загружаемой библиотеке (DLL), явно указываемой приложением с помощью параметра Software;

    • D3D_DRIVER_TYPE_WARP (D3D10_DRIVER_TYPE_WARP) — программное устройство, выполняющее сравнительно быстрый рендеринг, используя только центральный процессор (см. Windows Advanced Rasterization Platform. Этот тип устройства в Direct3D10 может использоваться лишь в случае, если ОС поддерживает Direct3D11.

  • Software — хэндл динамически загружаемой библиотеки, реализующей программный рендеринг для устройства типа D3D_DRIVER_TYPE_SOFTWARE. При использовании устройств любых других типов должен быть равен нулю.

  • Flags — битовая маска, которая может включать следующие флаги.

    • D3D11_CREATE_DEVICE_SINGLETHREADED (D3D10_CREATE_DEVICE_SINGLETHREADED) — вызовы устройства Direct3D будут осуществляться только из одного потока, поэтому внутренняя блокировка для упорядочивания доступов использоваться не должна; её отсутствие слегка повышает производительность. По всей видимости, функции устройства можно вызывать из разных потоков и при наличии этого флага, но при этом необходимо гарантировать, чтобы в любой момент времени выполняется лишь один вызов.

    • D3D11_CREATE_DEVICE_DEBUG (D3D10_CREATE_DEVICE_DEBUG) — устройство Direct3D создаётся с отладочным слоем.

    • D3D10_CREATE_DEVICE_SWITCH_TO_REF — одновременное создание аппаратного и эталонного программного устройств Direct3D10, что позволяет переключаться между ними с целью отладки (см. интерфейс ID3D10SwitchToRef). В Direct3D11 флаг D3D11_CREATE_DEVICE_SWITCH_TO_REF объявлен, но сама эта возможность не поддерживается.

    • D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS (D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS) — запрет использования многопоточности внутри самого Direct3D (во всяком случае, для WARP-устройства), что в некоторых случаях может упростить отладку или профилирование.

    • D3D11_CREATE_DEVICE_BGRA_SUPPORT (D3D10_CREATE_DEVICE_BGRA_SUPPORT) — запрет создания устройства, если оно не способно поддерживать форматы данных с обратным порядком цветов (группа форматов DXGI_FORMAT_B8G8R8A8_xxx). Заметим, что данные форматы могут быть доступны и без этого флага, его наличие лишь гарантирует, что устройство их поддерживает.

      Этот флаг доступен, начиная с Windows 7 и обновлённой Windows Vista. Он не может указываться в функциях D3D10CreateDevice и D3D10CreateDeviceAndSwapChain, хотя при указании в последующих версиях этих функций его применение возможно и для аппаратуры, поддерживающей лишь DirectX 10, но не 10.1 или последующие версии. Его наличие необходимо для взаимодействия Direct2D с ресурсами Direct3D.

    • D3D10_CREATE_DEVICE_ALLOW_NULL_FROM_MAP — при обнаружении нехватки памяти некоторые функции вместо выдачи исключения должны возвращать nullptr.

      Этот флаг можно использовать только в Windows 7. Он отсутствует в Direct3D11.

    • D3D10_CREATE_DEVICE_STRICT_VALIDATION — этот флаг объявлен зарезервированным и не должен использоваться; в Direct3D11 он отсутствует.

    • D3D11_CREATE_DEVICE_DEBUGGABLE (D3D10_CREATE_DEVICE_DEBUGGABLE) — сохранение информации, полезной для отладки шейдеров. Какая именно информация сохраняется, зависит от драйвера. Этот флаг поддерживается, начиная с Direct3D11.1 (неясно, идёт ли речь лишь о необходимости поддержки Direct3D11.1 на уровне ОС, т. е., по сути, о подходящей версии системы и обновлений на неё, или же о принципиальной невозможности использования с Direct3D11).

    • D3D11_CREATE_DEVICE_PREVENT_ALTERING_LAYER_SETTINGS_FROM_REGISTRY (D3D10_CREATE_DEVICE_PREVENT_ALTERING_LAYER_SETTINGS_FROM_REGISTRY) — запрещает подключение отладочного слоя устройства извне программы, т. е. с помощью параметров реестра, через DirectX Control Panel или из Visual Studio.

      Обычно этот флаг устанавливается в версиях программы, предназначенных для распространения среди конечных пользователей. Он не предотвращает возможность подключения отладочного слоя из поздних версий Visual Studio, работающих под Windows 8.1 или позднейшими версиями ОС; для этой цели в них следует использовать метод ID3D11DeviceContext2::IsAnnotationEnabled (доступен только для Direct3D11).

      Этот флаг доступен лишь при наличии поддержки Direct3D11.1 (неясно, можно ли его использовать с Direct3D11.0, хотя с Direct3D10 он допустим). Он автоматически подключает отладочный слой.

    • D3D11_CREATE_DEVICE_DISABLE_GPU_TIMEOUT — запрещает обнаружение таймаута графического процессора, что позволяет выполнять на нём вычисления, требующие более двух секунд времени (при его отсутствии ОС обнаруживает отсутствие ответа ГП и выполняет его сброс).

      Этот флаг поддерживается, начиная с Direct3D11.1 (неясно, идёт речь именно о Direct3D или о поддержке в ОС).

    • D3D11_CREATE_DEVICE_VIDEO_SUPPORT — запрещает создание устройства, если его драйвер не соответствует драйверной модели WDDM 1.2, появившейся в Windows 8, что каким-то образом связано с возможностями воспроизведения видео.

      Этот флаг поддерживается, начиная с Direct3D11.1 (неясно, идёт речь именно о Direct3D или о поддержке в ОС).

  • pFeatureLevels — указатель на массив значений типа D3D_FEATURE_LEVEL, задающих в порядке убывания предпочтительности требуемый уровень функциональных возможностей создаваемого устройства. Если этот указатель равен nullptr, то предполагается, что уровни понижаются от D3D_FEATURE_LEVEL_11_0 до D3D_FEATURE_LEVEL_9_1 включительно.

    Для создания устройства уровня Direct3D11.1 этот параметр должен указывать на массив, первый элемент которого содержит значение D3D_FEATURE_LEVEL_11_1. Однако следует учитывать, что, если аппаратура не поддерживает данный уровень, функция создания устройства завершится неудачно с кодом E_INVALIDARG независимо от того, была ли в массиве указана какая-либо альтернатива. Соответственно, если программа способна работать и с Direct3D11.1, и с более ранними версиями, ей может потребоваться вызывать функцию дважды: сначала при попытке создать устройство Direct3D11.1, а при её неудачном завершении — для создания устройства более низкого уровня.

    Функции, создающие устройство Direct3D10, не имеют аналогичного по назначению параметра; они всегда создают устройство уровня D3D10_FEATURE_LEVEL_10_0. Функции создания устройства Direct3D10.1 имеют параметр HardwareLevel, который задаёт требуемый уровень функциональности и должен быть равен одной из констант типа D3D10_FEATURE_LEVEL1. Если приложение, использующее Direct3D10.1, способно работать с более низкими уровнями функциональности, оно должно несколько раз вызывать функцию создания устройства, постепенно понижая требования к функциональности, до тех пор, пока устройство не будет успешно создано.

  • FeatureLevels — число элементов в массиве, заданном предыдущим параметром.

  • SDKVersion — версия используемого SDK, должна быть равна D3D11_SDK_VERSION (в функциях создания устройства Direct3D10 или Direct3D10.1 соответствующий параметр равен D3D10_SDK_VERSION или D3D10_1_SDK_VERSION соответственно).

  • pSwapChainDesc — адрес структуры типа DXGI_SWAP_CHAIN_DESC, задающей характеристики цепочки переключения буферов (см. описание работы с цепочками, где приведены в том числе сведения о создании цепочки с использованием функции IDXGIFactory2::CreateSwapChainForHwnd и структуры DXGI_SWAP_CHAIN_DESC1, являющейся расширенным вариантом DXGI_SWAP_CHAIN_DESC).

  • ppSwapChain — адрес переменной, в которую будет помещён указатель на интерфейс созданной цепочки переключения буферов.

  • ppDevice — адрес переменной, в которую будет помещён указатель на интерфейс созданного устройства типа ID3D11Device. В функциях, создающих устройства Direct3D10 или Direct3D10.1, имеется такой же параметр, но тип интерфейса будет соответствовать версии Direct3D API.

    Заметим, что тип интерфейса устройства не связан с функциональным уровнем: и для Direct3D11.1, и для Direct3D9.1, и для любых уровней функциональности между этими двумя значениями будет возвращён один и тот же интерфейс устройства типа ID3D11Device. Последующие версии интерфейса могут быть получены обычным вызовом метода IUnknown::QueryInterface.

  • pFeatureLevel — адрес переменной, в которой будет сохранено значение типа D3D_FEATURE_LEVEL, показывающее функциональный уровень созданного устройства. Этот параметр может быть равен nullptr, если программа не нуждается в информации о фактически поддерживаемом функциональном уровне.

  • ppImmediateContext — адрес переменной, в которой сохраняется указатель на интерфейс немедленного контекста устройства Direct3D11 типа ID3D11DeviceContext. Немедленный контекст используется для собственно выполнения рендеринга.

    У функций создания устройства Direct3D10 или Direct3D10.1 аналогичного параметра нет, поскольку там все операции рендеринга осуществляются через само устройство, а не через его немедленный контекст.

Уничтожение устройства

Как и любой другой COM-интерфейс, устройство Direct3D автоматически уничтожается, когда счётчик ссылок на него снижается до нуля. Поэтому для его уничтожения необходимо сначала уничтожить все интерфейсы, порождённые через данное устройство, а потом освободить сам интерфейс устройства обычной метода IUnknown::Release.

Поддерживаемые функциональные возможности

Основной набор функциональных устройств, поддерживаемых устройством, определяется установленным уровнем функциональности, который сохраняется функциями D3D11CreateDevice и D3D11CreateDeviceAndSwapChain в переменной, адрес которой задан параметром pFeatureLevel (если программа указывала только один допустимый уровень при вызове функции создания устройства и последняя завершилась успешно, нужды сохранять уровень нет, так как будет установлен именно он).

Некоторые возможности являются необязательными. Чтобы определить, поддерживаются ли они конкретным устройством, следует использовать методы ID3D11Device::CheckFeatureSupport и ID3D11Device::CheckFormatSupport.

Direct3D10 и 10.1 не имеют средств для проверки дополнительных функциональных возможностей. В Direct3D10 можно лишь проверить поддержку тех или иных форматов данных с помощью метода ID3D10Device::CheckFormatSupport; Direct3D10.1 добавляет возможность проверки используемого уровня средств (метод ID3D10Device1::GetFeatureLevel).

Объекты-дети устройства

Ряд объектов, создаваемых методами устройства (например объекты состояний, шейдеры, контексты), называется детьми этого устройства. В случае устройства Direct3D10 или Direct3D10.1 они являются наследниками интерфейса ID3D10DeviceChild, порождённого прямо от IUnknown и определяющего следующие методы.

В случае устройства Direct3D11 дети являются наследниками интерфейса ID3D11DeviceChild, также порождённого прямо от IUnknown и определяющего аналогичные методы:

Интерфейс устройства

Для работы с устройствами Direct3D предусмотрены интерфейсы устройств Direct3D10 и Direct3D11.