Using DXCore to enumerate adapters

DXCore is an adapter enumeration API for DirectX devices, so some of its facilities overlap with those of DXGI.

DXCore enables the exposure of new device types to user mode, such as MCDM (Microsoft Compute Driver Model), for use with Direct3D 12, DirectML, and Windows Machine Learning. DXCore, unlike DXGI, does not provide any information about display-related technology or properties

In the next few sections, we'll take a look at the main features of DXCore with some code examples (written in C++/WinRT). The code examples shown below are extracted from the full source code listing that you can find in the topic Minimal DXCore application.

Create an adapter factory

You begin DXCore adapter enumeration by creating an adapter factory object, which is represented by the IDXCoreAdapterFactory interface. To create a factory, include the dxcore.h header file, and call the DXCoreCreateAdapterFactory free function.

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

Retrieve an adapter list

Unlike with DXGI, a newly-created DXCore adapter factory doesn't automatically create a snapshot of the adapter state of the system. Instead, DXCore creates that snapshot when you explicitly retrieve an adapter list object, which is represented by the IDXCoreAdapterList interface.

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

Select an appropriate adapter from the list

This section demonstrates how, given an adapter list object, you could find the first hardware adapter in the list.

The IDXCoreAdapterList::GetAdapterCount method tells you the number of elements in the list, and IDXCoreAdapterList::GetAdapter retrieves a specific adapter by index.

You can then query the properties of that adapter, by following these steps.

  • First, to confirm that it's valid to retrieve the value of a given property for this adapter on this operating system version, you call IDXCoreAdapter::IsPropertySupported. Pass a value of the DXCoreAdapterProperty enumeration to identify which property you're querying about.
  • Optionally confirm the size of the property value with a call to IDXCoreAdapter::GetPropertySize. For a property such as DXCoreAdapterProperty::IsHardware, which is a simple Boolean, this step isn't necessary.
  • And, finally, retrieve the property's value by calling 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;
    }
}

Select the preferred adapter by sorting an adapter list

You can sort a DXCore adapter list by calling the IDXCoreAdapterList::Sort method.

The DXCoreAdapterPreference enumeration defines values that representing sort criteria. Pass an array of those values to Sort, and then read off the first adapter in the resulting sorted list.

To determine whether a sort type is going to be understood by Sort, first call 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;
}

Query and set adapter state (properties)

You can retrieve and set the state of a specified state item of an adapter by calling the IDXCoreAdapter::QueryState and IDXCoreAdapter::SetState methods.

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));
}

In practice, before calling QueryState and SetState, you should call IsQueryStateSupported to confirm that querying the state kind is available for this adapter and operating system (OS).

Adapter list freshness

Should an adapter list become stale due to changing system conditions, it will be marked as such. You can determine an adapter list's freshness by polling its IDXCoreAdapterList::IsStale method.

More conveniently, though, you can subscribe to notifications for conditions such as staleness. To do that, pass DXCoreNotificationType::AdapterListStale to IDXCoreAdapterFactory::RegisterEventNotification, and safely store the returned cookie for use later.

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)
{
    ...
}

You can then generate a new, current, adapter list object from the factory object that you already have. Handling these conditions is critical to your ability to seamlessly respond to events such as adapter arrival and removal (whether that be a GPU, or a specialized compute adapter), and to appropriately shift workloads in response.

Before you destroy the adapter list object, you must use the cookie value to unregister that object from notifications by calling IDXCoreAdapterFactory::UnregisterEventNotification. If you don't unregister, then a fatal exception is raised when the situation is detected.

HRESULT hr = factory->UnregisterEventNotification(m_eventCookie);

Display information

Note

DXCore doesn't itself provide any display information. Where necessary, you should use the Windows Runtime DisplayMonitor class to retrieve this information. An adapter's LUID provides a common identifier that you can use to map a DXCore adapter to DisplayMonitor.DisplayAdapterId information. To obtain an adapter's LUID, pass DXCoreAdapterProperty::InstanceLuid to the IDXCoreAdapter::GetProperty method.

See also