Partilhar via


Usando DXCore para enumerar adaptadores

DXCore é uma API de enumeração de adaptador para dispositivos DirectX, portanto, alguns de seus recursos se sobrepõem aos de DXGI.

O DXCore permite a exposição de novos tipos de dispositivos ao modo de usuário, como MCDM (Microsoft Compute Driver Model), para uso com Direct3D 12, DirectMLe Windows Machine Learning. O DXCore, ao contrário do DXGI, não fornece nenhuma informação sobre tecnologia ou propriedades relacionadas ao monitor

Nas próximas seções, vamos dar uma olhada nos principais recursos do DXCore com alguns exemplos de código (escritos em C++/WinRT). Os exemplos de código mostrados abaixo são extraídos da listagem completa do código-fonte que você pode encontrar no tópico aplicação Minimal DXCore.

Criar uma fábrica de adaptadores

Você começa a enumeração do adaptador DXCore criando um objeto de fábrica do adaptador, que é representado pela interfaceIDXCoreAdapterFactory. Para criar uma fábrica, inclua o arquivo de cabeçalho dxcore.h e chame a função livre DXCoreCreateAdapterFactory.

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

Recuperar uma lista de adaptadores

Ao contrário do DXGI, uma fábrica de adaptadores DXCore recém-criada não cria automaticamente um instantâneo do estado atual do adaptador do sistema. Em vez disso, o DXCore cria esse instantâneo quando você recupera explicitamente um objeto de lista de adaptadores, que é representado pela interfaceIDXCoreAdapterList.

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

Selecione um adaptador apropriado na lista

Esta seção demonstra como, dado um objeto de lista de adaptadores, você pode encontrar o primeiro adaptador de hardware na lista.

O método IDXCoreAdapterList::GetAdapterCount informa o número de elementos na lista e IDXCoreAdapterList::GetAdapter recupera um adaptador específico por índice.

Em seguida, você pode consultar as propriedades desse adaptador, seguindo estas etapas.

  • Primeiro, para confirmar que é válido recuperar o valor de uma determinada propriedade para este adaptador nesta versão do sistema operacional, chame IDXCoreAdapter::IsPropertySupported. Passe um valor da enumeração DXCoreAdapterProperty para identificar sobre qual propriedade está a consultar.
  • Opcionalmente, confirme o tamanho do valor da propriedade com uma chamada para IDXCoreAdapter::GetPropertySize. Para uma propriedade como DXCoreAdapterProperty::IsHardware, que é um booleano simples, esta etapa não é necessária.
  • E, finalmente, recupere o valor da propriedade chamando 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;
    }
}

Selecione o adaptador preferido classificando uma lista de adaptadores

Você pode classificar uma lista de adaptadores DXCore chamando o IDXCoreAdapterList::Sort método.

A enumeração DXCoreAdapterPreference define valores que representam critérios de classificação. Passe uma matriz desses valores para Classificare, em seguida, leia o primeiro adaptador na lista classificada resultante.

Para determinar se um tipo de classificação será compreendido pelo Sort, primeiro chame 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;
}

Consultar e definir o estado do adaptador (propriedades)

Você pode recuperar e definir o estado de um item de estado especificado de um adaptador chamando o IDXCoreAdapter::QueryState e IDXCoreAdapter::SetState métodos.

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

Na prática, antes de chamar QueryState e SetState, deve-se chamar IsQueryStateSupported para confirmar se a consulta do tipo de estado está disponível para este adaptador e sistema operativo (SO).

Atualidade da lista de adaptadores

Se uma lista de adaptadores ficar obsoleta devido à alteração das condições do sistema, ela será marcada como tal. Pode determinar a frescura de uma lista de adaptadores através da verificação do seu método IDXCoreAdapterList::IsStale.

Mais conveniente, porém, você pode assinar notificações para condições como obsolescência. Para fazer isso, passe DXCoreNotificationType::AdapterListStale para IDXCoreAdapterFactory::RegisterEventNotificatione armazene com segurança o cookie retornado para uso posterior.

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

Em seguida, você pode gerar um novo objeto de lista de adaptadores atual a partir do objeto de fábrica que você já tem. Lidar com essas condições é fundamental para sua capacidade de responder perfeitamente a eventos como chegada e remoção do adaptador (seja uma GPU ou um adaptador de computação especializado) e de mudar adequadamente as cargas de trabalho em resposta.

Antes de destruir o objeto de lista de adaptadores, você deve usar o valor do cookie para cancelar o registro desse objeto das notificações chamando IDXCoreAdapterFactory::UnregisterEventNotification. Se você não cancelar o registro, uma exceção fatal será criada quando a situação for detetada.

HRESULT hr = factory->UnregisterEventNotification(m_eventCookie);

Exibir informações

Observação

DXCore em si não fornece nenhuma informação de exibição. Quando necessário, deverá usar a classe DisplayMonitor do Windows Runtime para recuperar estas informações. OLUIDde um adaptador fornece um identificador comum que você pode usar para mapear um adaptador DXCore para informações de DisplayMonitor.DisplayAdapterId. Para obter o LUID de um adaptador, passe DXCoreAdapterProperty::InstanceLuid para o IDXCoreAdapter::GetProperty método.

Enumerar adaptadores para cargas de trabalho de multimédia

Embora o IDXCoreAdapterFactory1::CreateAdapterListByWorkload método permita fornecer filtros específicos para carga de trabalho, tempo de execução e tipo de hardware, recomendamos que você limite a filtragem ao que é essencial. A principal razão para isso é ajudar a garantir a compatibilidade em uma ampla gama de configurações do usuário final. Você pode confiar no DXCore fornecendo seu aplicativo com o adaptador mais adequado na primeira entrada da lista de adaptadores; e você pode ignorar o resto, se necessário. Neste exemplo, criaremos uma lista de adaptadores para uma carga de trabalho de mídia (ou seja, processamento de vídeo) onde os aceleradores de mídia serão priorizados pelo 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
}

Enumerar NPUs para tarefas computacionais de Aprendizagem Automática

Em alguns casos, é apropriado restringir ainda mais a lista de adaptadores para IDXCoreAdapterFactory1::CreateAdapterListByWorkload, como no caso em que você deseja apenas um processamento eficiente de cargas de trabalho de aprendizado de máquina em uma NPU. Este exemplo fornecerá uma lista de adaptadores que consiste em NPUs capazes de processar cargas de trabalho de ML por meio de metacomandos DirectX, omitindo GPUs e aceleradores de computação.

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
}

Enumerar adaptadores com/sem drivers de modo de usuário DirectX

O DXCore suporta a enumeração de dispositivos MCDM/WDDM que não fornecem um driver de modo de usuário Direct 3D (mas dependem de interfaces privadas ou outras bibliotecas para interação). Esses dispositivos não são enumeráveis por meio IDXCoreAdapterFactory1::CreateAdapterListByWorkload porque esse método foi projetado para oferecer suporte a casos de uso envolvendo a pilha DirectX. No entanto, essa classe estreita de adaptadores será enumerável por meio do método IDXCoreAdapterFactory::CreateAdapterList usando os novos atributos de tipo de hardware . Este exemplo enumera cada adaptador no sistema, independentemente do suporte ao tempo de execução do Direct 3D, e adiciona-o a um mapa usando o GUID do atributo do tipo de hardware como chave.

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

Ver também