Verwenden von DXCore zum Auflisten von Adaptern
DXCore ist eine Adapter-Enumerations-API für DirectX-Geräte, sodass sich einige ihrer Funktionen mit denen von DXGI überschneiden.
DXCore ermöglicht die Einführung neuer Gerätetypen für den Benutzermodus, z. B. MCDM (Microsoft Compute Driver Model), für die Verwendung mit Direct3D 12, DirectML und Windows Machine Learning. DXCore liefert im Gegensatz zu DXGI keine Informationen zu anzeigebezogenen Technologien oder Eigenschaften.
In den nächsten Abschnitten sehen wir uns die Hauptfeatures von DXCore mit einigen Codebeispielen an (geschrieben in C++/WinRT). Die unten gezeigten Codebeispiele werden aus der vollständigen Quellcodeauflistung extrahiert, die Sie im Thema Minimale DXCore-Anwendung finden können.
Erstellen einer Adapterfactory
Sie beginnen mit der DXCore-Adapterenumeration, indem Sie ein Adapter factory-Objekt erstellen, das durch die IDXCoreAdapterFactory-Schnittstelle dargestellt wird. Um eine Factory zu erstellen, schließen Sie die dxcore.h
Headerdatei ein, und rufen Sie die kostenlose Funktion DXCoreCreateAdapterFactory auf.
#include <dxcore.h>
...
winrt::com_ptr<IDXCoreAdapterFactory> adapterFactory;
winrt::check_hresult(::DXCoreCreateAdapterFactory(adapterFactory.put()));
Abrufen einer Adapterliste
Im Gegensatz zu DXGI erstellt eine neu erstellte DXCore-Adapterfactory nicht automatisch eine Momentaufnahme des Adapterzustands des Systems. Stattdessen erstellt DXCore diese Momentaufnahme, wenn Sie explizit ein Adapterlistenobjekt abrufen, das durch die IDXCoreAdapterList-Schnittstelle dargestellt wird.
winrt::com_ptr<IDXCoreAdapterList> d3D12CoreComputeAdapters;
GUID attributes[]{ DXCORE_ADAPTER_ATTRIBUTE_D3D12_CORE_COMPUTE };
winrt::check_hresult(
adapterFactory->CreateAdapterList(_countof(attributes),
attributes,
d3D12CoreComputeAdapters.put()));
Wählen Sie einen geeigneten Adapter aus der Liste aus
In diesem Abschnitt wird veranschaulicht, wie Sie angesichts eines Adapterlistenobjekts den ersten Hardwareadapter in der Liste finden können.
Die IDXCoreAdapterList::GetAdapterCount-Methode informiert Sie über die Anzahl der Elemente in der Liste, und IDXCoreAdapterList::GetAdapter ruft einen bestimmten Adapter nach Index ab.
Anschließend können Sie die Eigenschaften dieses Adapters abfragen, indem Sie die folgenden Schritte ausführen.
- Um zu bestätigen, dass es gültig ist, den Wert einer bestimmten Eigenschaft für diesen Adapter in dieser Betriebssystemversion abzurufen, rufen Sie IDXCoreAdapter::IsPropertySupported auf. Übergeben Sie einen Wert der DXCoreAdapterProperty-Enumeration, um zu identifizieren, welche Eigenschaft Sie abfragen.
- Bestätigen Sie optional die Größe des Eigenschaftswerts mit einem Aufruf von IDXCoreAdapter::GetPropertySize. Für eine Eigenschaft wie DXCoreAdapterProperty::IsHardware, bei der es sich um einen einfachen booleschen Wert handelt, ist dieser Schritt nicht erforderlich.
- Rufen Sie schließlich den Wert der Eigenschaft ab, indem Sie IDXCoreAdapter::GetProperty aufrufen.
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;
}
}
Wählen Sie den bevorzugten Adapter aus, indem Sie eine Adapterliste sortieren.
Sie können eine DXCore-Adapterliste sortieren, indem Sie die IDXCoreAdapterList::Sort-Methode aufrufen.
Die DXCoreAdapterPreference-Enumeration definiert Werte, die Sortierkriterien darstellen. Übergeben Sie ein Array dieser Werte an Sortieren, und lesen Sie dann den ersten Adapter in der resultierenden sortierten Liste aus.
Um zu bestimmen, ob ein Sortiertyp von Sortieren verstanden werden soll, rufen Sie zuerst IDXCoreAdapterList::IsAdapterPreferenceSupported auf.
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;
}
Abfrage und Festlegen des Adapterstatus (Eigenschaften)
Sie können den Status eines angegebenen Zustandselements eines Adapters abrufen und festlegen, indem Sie die Methoden IDXCoreAdapter::QueryState und IDXCoreAdapter::SetState aufrufen.
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 der Praxis sollten Sie vor dem Aufrufen von QueryState und SetState IsQueryStateSupported aufrufen, um zu bestätigen, dass die Abfrage der Statusart für diesen Adapter und das Betriebssystem (OS) verfügbar ist.
Aktualität der Adapterliste
Sollte eine Adapterliste aufgrund geänderter Systembedingungen veraltet werden, wird sie als solche gekennzeichnet. Sie können die Aktualität einer Adapterliste ermitteln, indem Sie die IDXCoreAdapterList::IsStale-Methode abfragen.
Praktischer ist jedoch, dass Sie Benachrichtigungen über Zustände wie z. B. Veraltung abonnieren können. Übergeben Sie dazu DXCoreNotificationType::AdapterListStale an IDXCoreAdapterFactory::RegisterEventNotification, und speichern Sie das zurückgegebene Cookie sicher zur späteren Verwendung.
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)
{
...
}
Anschließend können Sie ein neues, aktuelles Adapterlistenobjekt aus dem bereits installierten Factoryobjekt generieren. Die Behandlung dieser Bedingungen ist entscheidend für ihre Fähigkeit, nahtlos auf Ereignisse wie die Ankunft und Entfernung des Adapters zu reagieren (unabhängig davon, ob es sich um eine GPU oder einen spezialisierten Computeradapter handelt) und um Workloads entsprechend in Reaktion zu verschieben.
Bevor Sie das Adapterlistenobjekt zerstören, müssen Sie den Cookiewert verwenden, um die Registrierung dieses Objekts von Benachrichtigungen aufzuheben, indem Sie IDXCoreAdapterFactory::UnregisterEventNotification aufrufen. Wenn Sie die Registrierung nicht aufheben, wird eine schwerwiegende Ausnahme ausgelöst, wenn die Situation erkannt wird.
HRESULT hr = factory->UnregisterEventNotification(m_eventCookie);
Anzeigeinformationen
Hinweis
DXCore stellt keine Anzeigeinformationen bereit. Bei Bedarf sollten Sie die Windows-Runtime DisplayMonitor-Klasse verwenden, um diese Informationen abzurufen. Die LUID eines Adapters stellt einen allgemeinen Bezeichner bereit, den Sie zum Zuordnen eines DXCore-Adapters zu DisplayMonitor.DisplayAdapterId-Informationen verwenden können. Um die LUID eines Adapters abzurufen, übergeben Sie DXCoreAdapterProperty::InstanceLuid an die IDXCoreAdapter::GetProperty-Methode.
Aufzählen von Adaptern für Medienworkloads
Während die IDXCoreAdapterFactory1::CreateAdapterListByWorkload-Methode Ihnen ermöglicht, bestimmte Filter für Arbeitsauslastung, Laufzeit und Hardwaretyp bereitzustellen, empfehlen wir, die Filterung auf wesentliche Elemente zu beschränken. Der Hauptgrund dafür ist die Gewährleistung der Kompatibilität über eine Vielzahl von Endbenutzerkonfigurationen hinweg. Sie können sich auf DXCore verlassen, um Ihre App mit dem am besten geeigneten Adapter im ersten Eintrag der Adapterliste bereitzustellen. Zudem können Sie den Rest bei Bedarf ignorieren. In diesem Beispiel erstellen wir eine Adapterliste für eine Medienarbeitsauslastung (d. h. Videoverarbeitung), bei der Medienbeschleuniger von DXCore priorisiert werden.
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
}
Aufzählen von NPUs für ML-Workloads
In einigen Fällen empfiehlt es sich, die Adapterliste für IDXCoreAdapterFactory1::CreateAdapterListByWorkload weiter einzugrenzen, z. B. in dem Fall, in dem Sie nur eine effiziente Verarbeitung von Machine Learning-Workloads auf einer NPU wünschen. In diesem Beispiel wird eine Adapterliste bereitgestellt, die aus NPUs besteht, die ML-Workloads über DirectX-Metabefehle verarbeiten können, GPUs und Computerbeschleuniger weglassen.
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
}
Aufzählen von Adaptern mit/ohne DirectX-Benutzermodustreiber
DXCore unterstützt die Enumeration von MCDM/WDDM-Geräten, die keinen Direct 3D-Benutzermodustreiber bereitstellen (sondern auf private Schnittstellen oder andere Bibliotheken für die Interaktion angewiesen sind). Diese Geräte können nicht über IDXCoreAdapterFactory1::CreateAdapterListByWorkload aufgezählt werden, da diese Methode so konzipiert ist, dass Anwendungsfälle im Zusammenhang mit dem DirectX-Stapel unterstützt werden. Diese schmale Adapterklasse kann jedoch mithilfe der IDXCoreAdapterFactory::CreateAdapterList-Methode mithilfe der neuen Hardwaretypattribute aufgezählt werden. In diesem Beispiel wird jeder Adapter auf dem System aufgelistet, unabhängig von der Direct 3D-Laufzeitunterstützung, und fügt ihn einer Zuordnung mit der GUID des Hardwaretyp-Attributs als Schlüssel hinzu.
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});
}
}
}