使用 DXCore 枚举适配器

DXCore 是 DirectX 设备的适配器枚举 API,因此其某些设施与 DXGI 的枚举 API 重叠。

DXCore 支持将新设备类型公开到用户模式,例如 MCDM (Microsoft 计算驱动程序模型) ,以便与 Direct3D 12DirectMLWindows 机器学习 一起使用。 DXCore 与 DXGI 不同,不提供有关显示相关技术或属性的任何信息

在接下来的几个部分中,我们将介绍 DXCore 的主要功能,其中一些代码示例 (用 C++/WinRT) 编写。 下面所示的代码示例是从可以在 “最小 DXCore 应用程序”主题中找到的完整源代码列表中提取的。

创建适配器工厂

通过创建由 IDXCoreAdapterFactory 接口表示的适配器工厂对象来开始 DXCore 适配器枚举。 若要创建工厂,请包含 dxcore.h 头文件,并调用 DXCoreCreateAdapterFactory 免费函数。

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

检索适配器列表

与 DXGI 不同,新建的 DXCore 适配器工厂不会自动创建系统的适配器状态的快照。 相反,DXCore 会在显式检索由 IDXCoreAdapterList 接口表示的适配器列表对象时创建该快照。

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 按索引检索特定适配器。

然后,可以按照以下步骤查询该适配器的属性。

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

通过对适配器列表进行排序来选择首选适配器

可以通过调用 IDXCoreAdapterList::Sort 方法对 DXCore 适配器列表进行排序。

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

实际上,在调用 QueryStateSetState 之前,应调用 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);

显示信息

注意

DXCore 本身不提供任何显示信息。 如有必要,应使用 Windows 运行时 DisplayMonitor 类检索此信息。 适配器的 LUID 提供了一个通用标识符,可用于将 DXCore 适配器映射到 DisplayMonitor.DisplayAdapterId 信息。 若要获取适配器的 LUID,请将 DXCoreAdapterProperty::InstanceLuid 传递给 IDXCoreAdapter::GetProperty 方法。

另请参阅