Перечисление адаптеров с использованием DXCore

DXCore — это API перечисления адаптеров для устройств DirectX, поэтому некоторые из его возможностей перекрываются с средствами DXGI.

DXCore позволяет использовать новые типы устройств в пользовательском режиме, например MCDM (Microsoft Compute Driver Model), для использования с Direct3D 12, DirectML и Машинным обучением Windows. DXCore, в отличие от DXGI, не предоставляет никаких сведений о технологии или свойствах, связанных с отображением.

В следующих разделах мы рассмотрим main функции 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 не создает автоматически snapshot состояния адаптера системы. Вместо этого DXCore создает этот snapshot при явном получении объекта списка адаптеров, который представлен интерфейсом 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 извлекает определенный адаптер по индексу.

Затем можно запросить свойства этого адаптера, выполнив следующие действия.

  • Во-первых, чтобы подтвердить допустимость получения значения заданного свойства для этого адаптера в этой версии операционной системы, вызовите 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 , чтобы убедиться, что для этого адаптера и операционной системы доступен запрос типа состояния.

Актуальность списка адаптеров

Если список адаптеров устареет из-за изменения условий системы, он будет помечен как таковой. Вы можете определить актуальность списка адаптеров, опрашивая его метод 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 сам по себе не предоставляет никаких сведений для отображения. При необходимости для получения этих сведений следует использовать класс DisplayMonitor среды выполнения Windows. LUID адаптера предоставляет общий идентификатор, который можно использовать для сопоставления адаптера DXCore со сведениями DisplayMonitor.DisplayAdapterId. Чтобы получить LUID адаптера, передайте DXCoreAdapterProperty::InstanceLuid в метод IDXCoreAdapter::GetProperty .

См. также раздел