Usar DXCore para enumerar adaptadores
DXCore é uma API de enumeração de adaptador para dispositivos DirectX, portanto, algumas de suas instalações se sobrepõem às do 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, DirectML e Windows Machine Learning. O DXCore, ao contrário do DXGI, não fornece nenhuma informação sobre tecnologia ou propriedades relacionadas à exibição
Nas próximas seções, veremos os 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 Aplicativo DXCore mínimo.
Criar uma fábrica de adaptadores
Você inicia a enumeração do adaptador DXCore criando um objeto de fábrica do adaptador, que é representado pela interface IDXCoreAdapterFactory. Para criar uma fábrica, inclua o arquivo de cabeçalho dxcore.h
e chame a função gratuita 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 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 interface IDXCoreAdapterList.
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 se é válido recuperar o valor de uma determinada propriedade para esse adaptador nesta versão do sistema operacional, chame IDXCoreAdapter::IsPropertySupported. Passe um valor da enumeração DXCoreAdapterProperty para identificar sobre qual propriedade você está consultando.
- 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, por fim, 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 método IDXCoreAdapterList::Sort.
A enumeração DXCoreAdapterPreference define valores que representam critérios de classificação. Passe uma matriz desses valores para Sort e, em seguida, leia o primeiro adaptador na lista classificada resultante.
Para determinar se um tipo de classificação será entendido por 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 os métodos IDXCoreAdapter::QueryState e 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));
}
Na prática, antes de chamar QueryState e SetState, você deve chamar IsQueryStateSupported para confirmar se a consulta do tipo de estado está disponível para esse adaptador e sistema operacional (SO).
Atualização da lista de adaptadores
Se uma lista de adaptadores ficar obsoleta devido a mudanças nas condições do sistema, ela será marcada como tal. Você pode determinar a atualização de uma lista de adaptadores sondando seu método IDXCoreAdapterList::IsStale.
Porém, é mais conveniente se inscrever para receber notificações de condições como desatualização. Para fazer isso, passe DXCoreNotificationType::AdapterListStale para IDXCoreAdapterFactory::RegisterEventNotification e 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)
{
...
}
Depois, você pode gerar um objeto de lista de adaptadores novo e atual a partir do objeto de fábrica que você já possui. Lidar com essas condições é fundamental para sua capacidade de responder diretamente a eventos como chegada e remoção do adaptador (seja uma GPU ou um adaptador de computação especializado) e 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á gerada quando a situação for detectada.
HRESULT hr = factory->UnregisterEventNotification(m_eventCookie);
Exibir as informações
Observação
O DXCore não fornece nenhuma informação de exibição. Quando necessário, você deve usar a classe DisplayMonitor de Execução do Windows para recuperar essas informações. O LUID de um adaptador fornece um identificador comum que você pode usar para mapear um adaptador DXCore para informações do DisplayMonitor.DisplayAdapterId. Para obter o LUID de um adaptador, passe DXCoreAdapterProperty::InstanceLuid para o método IDXCoreAdapter::GetProperty.
Enumerar adaptadores para cargas de trabalho de mídia
Embora o método IDXCoreAdapterFactory1::CreateAdapterListByWorkload permita que você forneça filtros específicos para carga de trabalho, tempo de execução e tipo de hardware, recomendamos limitar a filtragem ao essencial. O principal motivo para isso é ajudar a garantir a compatibilidade em uma ampla variedade de configurações do usuário final. Você pode confiar no DXCore fornecendo ao seu aplicativo o adaptador mais adequado na primeira entrada da lista de adaptadores, e 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) em que 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 cargas de trabalho de ML
Em alguns casos, é apropriado restringir ainda mais a lista de adaptadores para IDXCoreAdapterFactory1::CreateAdapterListByWorkload,, como no caso em que você só quiser o processamento eficiente de cargas de trabalho de machine learning em uma NPU. Este exemplo apresenta uma lista de adaptadores que consiste em NPUs capazes de processar cargas de trabalho de ML por meio de metacomandos do 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 dá suporte à enumeração de dispositivos MCDM/WDDM que não fornecem um driver de modo de usuário Direct 3D (mas, em vez disso, dependem de interfaces privadas ou outras bibliotecas para interação). Esses dispositivos não são enumeráveis por meio de IDXCoreAdapterFactory1::CreateAdapterListByWorkload, porque esse método foi elaborado para dar suporte a casos de uso que envolvem a pilha do DirectX. No entanto, essa classe restrita de adaptadores será enumerável por meio do método IDXCoreAdapterFactory::CreateAdapterList usando os novos atributos de tipo de hardware. Este exemplo enumera todos os adaptadores no sistema, independentemente do suporte ao tempo de execução do Direct 3D, e os adiciona a um mapa com o atributo de tipo de hardware GUID como uma 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});
}
}
}