DXCore を使用したアダプターの列挙

DXCore は DirectX デバイス用のアダプター列挙 API であるため、機能の一部は DXGI の機能と重複しています。

DXCore を使用すると、Direct3D 12、DirectML、Windows Machine Learning で使用するために、MCDM (Microsoft Compute Driver Model) などの新しいデバイスの種類をユーザー モードに公開できます。 DXCore では、DXGI とは異なり、ディスプレイ関連のテクノロジまたはプロパティに関する情報が提供されません

以下の数セクションでは、DXCore の主な機能とコード例 (C++/WinRT) をご紹介します。 以下に示すコード例は、「最小 DXCore アプリケーション」トピックにある完全なソース コードリストから抽出されています。

アダプター ファクトリを作成する

DXCore アダプターの列挙を開始するには、IDXCoreAdapterFactory インターフェイスで表されるアダプター ファクトリ オブジェクトを作成します。 ファクトリを作成するには、dxcore.h ヘッダー ファイルを含め、DXCoreCreateAdapterFactory フリー関数を呼び出します。

#include <dxcore.h>
...
winrt::com_ptr<IDXCoreAdapterFactory> adapterFactory;
winrt::check_hresult(::DXCoreCreateAdapterFactory(adapterFactory.put()));

アダプター リストを取得する

DXGI とは異なり、新しく作成された DXCore アダプター ファクトリでは、システムのアダプター状態のスナップショットが自動作成されません。 代わりに、IDXCoreAdapterList インターフェイスで表されるアダプター リスト オブジェクトを明示的に取得すると、DXCore によってそのスナップショットが作成されます。

winrt::com_ptr<IDXCoreAdapterList> d3D12CoreComputeAdapters;
GUID attributes[]{ DXCORE_ADAPTER_ATTRIBUTE_D3D12_CORE_COMPUTE };
winrt::check_hresult(
    adapterFactory->CreateAdapterList(_countof(attributes),
        attributes,
        d3D12CoreComputeAdapters.put()));

リストから適切なアダプターを選択する

このセクションでは、アダプター リスト オブジェクトを指定して、リスト内の最初のハードウェア アダプターを見つける方法を示します。

IDXCoreAdapterList::GetAdapterCount メソッドは、リスト内の要素の数を示し、IDXCoreAdapterList::GetAdapter はインデックスによって特定のアダプターを取得します。

その後、次の手順に従って、そのアダプターのプロパティを照会できます。

  • まず、このオペレーティング システム バージョンでこのアダプターの特定のプロパティの値を取得することが有効であることを確認するには、IDXCoreAdapter::IsPropertySupported を呼び出します。 DXCoreAdapterProperty 列挙の値を渡して、照会するプロパティを特定します。
  • 必要に応じて、IDXCoreAdapter::GetPropertySize の呼び出しでプロパティ値のサイズを確認します。 単純なブール値である DXCoreAdapterProperty::IsHardware などのプロパティの場合、この手順は必要ありません。
  • 最後に IDXCoreAdapter::GetProperty を呼び出して、プロパティの値を取得します。
winrt::com_ptr<IDXCoreAdapter> preferredAdapter;

const uint32_t count{ d3D12CoreComputeAdapters->GetAdapterCount() };

for (uint32_t i = 0; i < count; ++i)
{
    winrt::com_ptr<IDXCoreAdapter> candidateAdapter;
    winrt::check_hresult(
        d3D12CoreComputeAdapters->GetAdapter(i, candidateAdapter.put()));

    bool isHardware{ false };
    winrt::check_hresult(candidateAdapter->GetProperty(
        DXCoreAdapterProperty::IsHardware,
        &isHardware));

    if (isHardware)
    {
        // Choose the first hardware adapter, and stop looping.
        preferredAdapter = candidateAdapter;
        break;
    }

    // Otherwise, ensure that (as long as there are *any* adapters) we'll
    // at least choose one.
    if (!preferredAdapter)
    {
        preferredAdapter = candidateAdapter;
    }
}

アダプター リストを並べ替えて優先アダプターを選択する

DXCore アダプター リストを並べ替えるには、IDXCoreAdapterList::Sort メソッドを呼び出します。

DXCoreAdapterPreference 列挙は、並べ替え条件を表す値を定義します。 これらの値の配列を Sort に渡し、結果の並べ替えられたリストの先頭にあるアダプターを読み取ります。

並べ替えの種類が Sort で認識されるかどうかを判断するには、先に IDXCoreAdapterList::IsAdapterPreferenceSupported を呼び出します。

winrt::com_ptr<IDXCoreAdapter> TryFindHardwareHighPerformanceGraphicsAdapter()
{
    // You begin DXCore adapter enumeration by creating an adapter factory.
    winrt::com_ptr<IDXCoreAdapterFactory> adapterFactory;
    winrt::check_hresult(::DXCoreCreateAdapterFactory(adapterFactory.put()));

    // From the factory, retrieve a list of all the Direct3D 12 Graphics adapters.
    winrt::com_ptr<IDXCoreAdapterList> d3D12GraphicsAdapters;
    GUID attributes[]{ DXCORE_ADAPTER_ATTRIBUTE_D3D12_GRAPHICS };
    winrt::check_hresult(
        adapterFactory->CreateAdapterList(_countof(attributes),
            attributes,
            d3D12GraphicsAdapters.put()));

    DXCoreAdapterPreference sortPreferences[]{
        DXCoreAdapterPreference::Hardware, DXCoreAdapterPreference::HighPerformance };

    // Ask the OS to sort for the highest performance hardware adapter.
    winrt::check_hresult(d3D12GraphicsAdapters->Sort(_countof(sortPreferences), sortPreferences));

    winrt::com_ptr<IDXCoreAdapter> preferredAdapter;

    if (d3D12GraphicsAdapters->GetAdapterCount() > 0)
    {
        winrt::check_hresult(d3D12GraphicsAdapters->GetAdapter(0, preferredAdapter.put()));
    }

    return preferredAdapter;
}

アダプターの状態 (プロパティ) を照会および設定する

IDXCoreAdapter::QueryState メソッドおよび IDXCoreAdapter::SetState メソッドを呼び出すことで、アダプターの指定された状態項目の状態を取得および設定できます。

void SetDesiredMemoryReservation(winrt::com_ptr<IDXCoreAdapter> const& adapter, uint64_t reservation)
{
    DXCoreAdapterMemoryBudgetNodeSegmentGroup nodeSegmentGroup{};
    nodeSegmentGroup.nodeIndex = 0;
    nodeSegmentGroup.segmentGroup = DXCoreSegmentGroup::Local;

    DXCoreAdapterMemoryBudget memoryBudget{};
    winrt::check_hresult(adapter->QueryState(
        DXCoreAdapterState::AdapterMemoryBudget,
        &nodeSegmentGroup,
        &memoryBudget));

    // Clamp the reservation to what's available.
    reservation = std::min<uint64_t>(reservation, memoryBudget.availableForReservation);

    winrt::check_hresult(adapter->SetState(
        DXCoreAdapterState::AdapterMemoryBudget,
        &nodeSegmentGroup,
        &reservation));
}

実際には、QueryState および SetState を呼び出す前に、 IsQueryStateSupported を呼び出して、このアダプターとオペレーティング システム (OS) で状態の種類の照会が可能かどうかを確認する必要があります。

アダプター リストの鮮度

システムの状態の変化によってアダプター リストが古くなった場合は、そのようにマークされます。 アダプター リストの鮮度を確認するには、IDXCoreAdapterList::IsStale メソッドをポーリングします。

さらに便利なのは、鮮度の問題などの条件に関する通知を購読することです。 これを行うには、DXCoreNotificationType::AdapterListStale を IDXCoreAdapterFactory::RegisterEventNotification に渡し、返された cookie を後で使用できるように安全に格納します。

uint32_t m_eventCookie = 0;
...
winrt::check_hresult(factory->RegisterEventNotification(
    m_adapters.get(),
    DXCoreNotificationType::AdapterListStale,
    OnAdapterListStale,
    this,
    &m_eventCookie));
...
static void WINAPI OnAdapterListStale(
    DXCoreNotificationType notificationType,
    IUnknown* staleObject,
    void* context)
{
    ...
}

その後、既に存在するファクトリ オブジェクトから、新しい現在のアダプター リスト オブジェクトを生成できます。 これらの条件の処理は、(GPU、特殊なコンピューティング アダプターなど) アダプターの到着や削除などのイベント にシームレスに応答し、それに応じてワークロードを適切にシフトするために重要です。

アダプター リスト オブジェクトを破棄する前に、cookie 値を使用して IDXCoreAdapterFactory::UnregisterEventNotification を呼び出し、通知からそのオブジェクトを登録解除する必要があります。 登録を解除しないと、状況が検出されたときに致命的な例外が発生します。

HRESULT hr = factory->UnregisterEventNotification(m_eventCookie);

ディスプレイ情報

Note

DXCore 自体からはディスプレイ情報が提供されません。 必要に応じて、Windows ランタイム DisplayMonitor クラスを使用してこの情報を取得する必要があります。 アダプターの LUID は、DXCore アダプターを DisplayMonitor.DisplayAdapterId 情報にマップするために使用できる共通識別子を提供します。 アダプターの LUID を取得するには、DXCoreAdapterProperty::InstanceLuid を IDXCoreAdapter::GetProperty メソッドに渡します。

メディア ワークロードのアダプターを列挙する

IDXCoreAdapterFactory1::CreateAdapterListByWorkload メソッドを使用すると、ワークロード、ランタイム、ハードウェアの種類に対して特定のフィルターを提供できますが、フィルター処理は必要なものに限定することをお勧めします。 その主な理由は、幅広いエンドユーザー構成にわたって互換性を保証するためです。 DXCore を使用して、アダプター リストの最初のエントリで最適なアダプターをアプリに提供できます。必要に応じて、残りの部分を無視できます。 この例では、メディア アクセラレータが DXCore によって優先されるメディア (ビデオ処理) ワークロード用のアダプター リストを作成します。

void EnumerateAcceleratorsForMedia(ComPtr<IDXCoreAdapterList> &accelsForMedia)
{
    ComPtr<IDXCoreAdapterFactory1> adapterFactory;
    winrt::check_hresult(DXCoreCreateAdapterFactory(&adapterFactory));
    
    winrt::check_hresult(adapterFactory->CreateAdapterListByWorkload(
        DXCoreWorkload::Media,
        DXCoreRuntimeFilterFlags::None,
        DXCoreHardwareTypeFilterFlags::None,
        &accelsForMedia));
 
    // Ordering for returned adapter list:
    // - Media only
    // - Media and ML
    // - Media with Compute shaders
    // - Media with full GPU
}

ML ワークロード用の NPU を列挙する

場合によっては、NPU 上で機械学習ワークロードを効率的に処理したい場合など、IDXCoreAdapterFactory1::CreateAdapterListByWorkload のアダプター リストをさらに絞り込む方が適切なこともあります。 この例では、DIRECTX メタ コマンドを使用して ML ワークロードを処理できる NPU で構成されるアダプター リストを提供します。GPU とコンピューティング アクセラレータは省略します。

void EnumerateNPUsForML(ComPtr<IDXCoreAdapterList> &npus)
{
    ComPtr<IDXCoreAdapterFactory1> adapterFactory;
    winrt::check_hresult(DXCoreCreateAdapterFactory(&adapterFactory));
    
    winrt::check_hresult(adapterFactory->CreateAdapterListByWorkload(
        DXCoreWorkload::MachineLearning,
        DXCoreRuntimeFilterFlags::None,
        DXCoreHardwareTypeFilterFlags::NPU,
        &npus));
 
    // Ordering for returned adapter list:
    // - NPUs with metacommands
    // - NPUs with metacommands and compute shaders
}

DirectX ユーザー モード ドライバーの有無を問わずアダプターを列挙する

DXCore は、Direct 3D ユーザー モード ドライバーを提供しない (代わりに、対話のためにプライベート インターフェイスまたは他のライブラリに依存する) MCDM/WDDM デバイスの列挙をサポートします。 これらのデバイスは、 IDXCoreAdapterFactory1::CreateAdapterListByWorkload では列挙できません。このメソッドは、DirectX スタックに関連するユース ケースをサポートするように設計されているためです。 ただし、この限定されたクラスのアダプターは、新しい hardware-type 属性を使用して、IDXCoreAdapterFactory::CreateAdapterList メソッドで列挙できます。 この例では、Direct 3D ランタイムのサポートに関係なく、システム上のすべてのアダプターを列挙し、hardware-type 属性 GUID をキーとしてマップに追加しています。

void EnumerateAllAdapters(std::map<GUID, ComPtr<IDXCoreAdapterList>> &adapterListByType)
{
    ComPtr<IDXCoreAdapterFactory> adapterFactory;
    winrt::check_hresult(DXCoreCreateAdapterFactory(&adapterFactory));
    
    const GUID attributes[] = {
        DXCORE_HARDWARE_TYPE_ATTRIBUTE_GPU,
        DXCORE_HARDWARE_TYPE_ATTRIBUTE_COMPUTE_ACCELERATOR,
        DXCORE_HARDWARE_TYPE_ATTRIBUTE_NPU,
        DXCORE_HARDWARE_TYPE_ATTRIBUTE_MEDIA_ACCELERATOR,
    };
 
    for(uint32_t i = 0; i < ARRAYSIZE(attributes); ++i)
    {
        ComPtr<IDXCoreAdapterList> adapterList = nullptr;
        winrt::check_hresult(adapterFactory->CreateAdapterList(1, attributes[i], &adapterList));
 
        if(adapterList->GetAdapterCount() > 0)
        {
            adapterListByType.insert({attributes[i], adapterList});
        }
    }
}

関連項目