Freigeben über


Erweiterte D3D12-Barrieren

Die DDI-Schnittstelle für erweiterte Barrieren ist in Windows 11, Version 22H2 WDK (WDDM 3.0) verfügbar. Um erweiterte Barrieren auf 22H2 (oder früheren Betriebssystemversionen) zu verwenden, müssen Sie das 1.706.4-preview Agility SDK installieren.

Erweiterte D3D12-Barrieren bieten Entwicklern unabhängige Kontrolle über die GPU-Arbeitssynchronisierung, Texturlayoutübergänge und Cache-Leeren (Ressourcenspeicherzugriff). Dieses Feature bietet eine Reihe von Direct3D-APIs und DDIs, die Entwicklern unabhängige Kontrolle über die GPU-Arbeitssynchronisierung, Texturlayoutübergänge und Cache-Leeren (Ressourcenspeicherzugriff) ermöglichen.

Erweiterte Barrieren ersetzen herkömmliche Ressourcenbarrieren durch ausdrucksvollere Barrierentypen. Sie bieten die folgenden Features:

  • Weniger Synchronisierungslatenz.
  • Eine Reduzierung übermäßiger Cachelöschvorgänge.
  • Keine mysteriösen Werbe- und Verfallsregeln.
  • Schnelles, flexibles Ressourcenaliasing (vielfältige Aliasingtopologien).
  • Verwerfen während des Barriereübergangs.
  • Unterstützung für gleichzeitiges Lesen/Schreiben, einschließlich der Kopie der gleichen Ressource (Selbstkopie).
  • Unterstützung für asynchrone Befehle "Verwerfen", "Kopieren", "Auflösen" und "Löschen".

Erweiterte Barrieren sind nicht einfacher als Legacy-Ressourcenbarrieren, aber sie sind weniger mehrdeutig und daher für Entwickler einfacher zu verwenden.

Melden erweiterter Barriereunterstützung

Das Feature für erweiterte Barrieren ist derzeit keine Hardware- oder Treiberanforderung. Ein Treiber gibt die Unterstützung an, indem das EnhancedBarriersSupported-Mitglied von D3D12DDI_D3D12_OPTIONS_DATA_0089 auf TRUE festgelegt wird.

  • D3D12DDI_FEATURE_VERSION_VIDEO_0088_0 ist die Versionsnummer, die die vorläufige Implementierung der in Windows 11 eingeführten Meilensteine ​​der erweiterten Barriere von D3D12 definiert.

Erweiterte Barriererückruffunktionen D3D12

Treiber, die die Unterstützung für erweiterte Barrieren angeben, implementieren die folgenden Rückruffunktionen:

Designdetails

Treiber behandeln in der Regel Legacy-Ressourcenbarrieren mit drei separaten Vorgängen:

  1. GPU-Arbeit synchronisieren.
  2. Führen Sie alle erforderlichen Cache-Leervorgänge aus.
  3. Führen Sie alle erforderlichen Layoutänderungen aus.

Erweiterte Barrieren bieten Entwicklern die Möglichkeit, jeden dieser Vorgänge separat zu steuern.

Arten erweiterter Barrieren

Es gibt drei Arten erweiterter Barrieren:

Bereichsbarrieren ersetzen Legacy-Ressourcenbarrieren. Bereichsbarrieren werden bereitgestellt, sodass Legacy-Ressourcenbarrieren ohne spürbaren Leistungsverlust vollständig implementiert werden können.

  • Alle Barrierentypen steuern die GPU-Synchronisierung und Lese- oder Schreibzugriffstypen vor und nach der Barriere.

  • Texturbarrieren verwalten zusätzlich das Layout von Textur-Unterressourcen. Die Auswahl Unterressourcen kann als Bereich von MIP-, Array- und Plane-Slices ausgedrückt werden, zusätzlich zu der bekannten „Eins-oder-Alle“-Option, die von älteren Ressourcenbarrieren verwendet wird.

  • Pufferbarrieren und globale Barrieren steuern nur die Synchronisierung und den Ressourcenzugriff und wirken sich nicht auf das Ressourcenlayout aus (Puffer haben kein Layout). Globale Barrieren wirken sich auf den gesamten zwischengespeicherten Speicher aus, sodass sie teuer sein können und nur verwendet werden sollten, wenn eine stärker bereichsbezogene Barriere unzureichend ist.

Texturbarrieren

  • Steuern Sie die Cache-Leerung, das Speicherlayout und die Synchronisierung für Textur-Unterressourcen.
  • Darf nur mit Texturressourcen verwendet werden.
  • Zulassen der Auswahl einer einzelnen Unterressource, aller Unterressourcen oder eines zusammenhängenden Bereichs von Unterressourcen (d. h. Mip-Bereich und Arraybereich).
  • Muss einen gültigen, nicht NULL-Ressourcenzeiger angeben.

Pufferbarrieren

  • Steuern des Leerens des Caches und der Synchronisierung für Pufferressourcen.
  • Darf nur mit Pufferressourcen verwendet werden.
  • Im Gegensatz zu Texturen verfügen Puffer nur über eine einzige Unterressource und verfügen nicht über ein Layout, das übergestellt werden kann.
  • Muss einen gültigen, nicht NULL-Ressourcenzeiger angeben.

Globale Barrieren

  • Steuern Sie die Cache-Leerung und -Synchronisierung für alle angegebenen Ressourcenzugriffstypen in einer einzigen Befehlswarteschlange.
  • Sie haben keine Auswirkungen auf das Texturlayout.
  • Sind erforderlich, um Funktionen wie ältere NULL-UAV-Barrieren und NULL/NULL-Aliasing-Barrieren bereitzustellen.

Da globale Barrieren kein Texturlayout übergehen, können globale Barrieren nicht in Übergängen verwendet werden, die andernfalls eine Layoutänderung erfordern. Beispielsweise kann eine globale Barriere nicht verwendet werden, um eine Textur ohne gleichzeitigen Zugriff von D3D12DDI_BARRIER_ACCESS_RENDER_TARGET auf D3D12DDI_BARRIER_ACCESS_SHADER_RESOURCE zu übertragen, da dies auch eine Änderung von D3D12DDI_BARRIER_LAYOUT_RENDER_TARGET zu D3D12DDI_BARRIER_LAYOUT_SHADER_RESOURCE erfordern würde.

Synchronization

Grafikprozessoren sind darauf ausgelegt, möglichst viele Aufgaben parallel auszuführen. Jede GPU-Arbeit, die von früherer GPU-Arbeit abhängt, muss synchronisiert werden, bevor auf abhängige Daten zugegriffen wird.

Die erweiterte Barriereschnittstelle verwendet explizite SyncBefore - und SyncAfter-Werte als logische Bitfeldmasken. Eine Barriere muss warten, bis alle vorherigen Befehle SyncBefore-Bereiche abgeschlossen sind, bevor die Barriere ausgeführt wird. Ebenso muss eine Barriere alle nachfolgenden SyncAfter-Bereiche blockieren, bis die Barriere abgeschlossen ist. D3D12DDI_BARRIER_SYNC gibt den Synchronisierungsbereich der GPU-Arbeit in Bezug auf die Barriere an.

Weitere Informationen finden Sie in der Erweiterte Barrieren-Spezifikation.

Layoutübergänge

Textur-Unterressourcen können verschiedene Layouts für verschiedene Zugriffsmethoden verwenden. Beispielsweise werden Texturen häufig komprimiert, wenn sie als Renderziel oder Tiefenschablone verwendet werden und häufig für Shader-Lese- oder Kopierbefehle nicht komprimiert werden. Texturbarrieren verwenden LayoutBefore und LayoutAfter D3D12DDI_BARRIER_LAYOUT Werte, um Layoutübergänge zu beschreiben.

Layoutübergänge werden nur für Texturen benötigt, sodass sie nur in der D3D12DDI_TEXTURE_BARRIER-Datenstruktur ausgedrückt werden.

Sowohl LayoutBefore als auch LayoutAfter müssen mit dem Typ der Warteschlange kompatibel sein, die die Barriere ausführt. Beispielsweise kann eine Compute-Warteschlange keine Unterressource in oder aus D3D12DDI_BARRIER_LAYOUT_RENDER_TARGET übertragen.

Um eine klar definierte Barrierereihenfolge bereitzustellen, ist das Layout einer Unterressource nach Abschluss einer Abfolge von Barrieren das endgültige LayoutAfter in der Sequenz.

Zugriffsübergänge

Da viele GPU-Schreibvorgänge zwischengespeichert werden, kann jede Barriere zwischen einem Schreibzugriff und einem anderen Schreibzugriff oder einem schreibgeschützten Zugriff eine Cache-Leerung erfordern. Die APIs für erweiterte Barrieren verwenden Zugriffsübergänge, um anzugeben, dass der Speicher einer Unterressource für einen bestimmten neuen Zugriffstyp sichtbar gemacht werden muss. Wie bei den Layoutübergängen sind einige Zugriffsübergänge möglicherweise nicht erforderlich, wenn bekannt ist, dass der Speicher der zugeordneten Unterressource bereits für die gewünschte Verwendung zugänglich ist.

Zugriffsübergänge werden wie folgt ausgedrückt:

  • Für Texturen als Teil der D3D12DDI_TEXTURE_BARRIER-Struktur.
  • Für Puffer, als Teil der D3D12DDI_BUFFER_BARRIER-Struktur.

Zugriffsübergänge führen keine Synchronisierung durch. Es wird erwartet, dass die Synchronisierung zwischen abhängigen Zugriffen mithilfe der entsprechenden SyncBefore - und SyncAfter-Werte in der Barriere behandelt wird.

Eine AccessBefore, die für einen angegebenen AccessAfter sichtbar gemacht wurde, garantiert nicht, dass der Ressourcenspeicher auch für einen anderen Zugriffstyp sichtbar ist. Zum Beispiel:

MyTexBarrier.AccessBefore=D3D12DDI_BARRIER_ACCESS_UNORDERED_ACCESS;
MyTexBarrier.AccessAfter=D3D12DDI_BARRIER_ACCESS_SHADER_RESOURCE;

Dieser Zugriffsübergang zeigt an, dass ein nachfolgender Shader-Lesezugriff von einem vorhergehenden ungeordneten Schreibzugriff abhängt. Wenn die Hardware jedoch Shaderressourcen direkt aus dem UAV-Cache lesen kann, wird der Treiber möglicherweise nicht tatsächlich den UAV-Cache leeren.

D3D12DDI_BARRIER_ACCESS_COMMON

D3D12DDI_BARRIER_ACCESS_COMMON ist ein spezieller Zugriffstyp, der einen layoutkompatiblen Zugriff angibt. Der Übergang zu D3D12DDI_BARRIER_ACCESS_COMMON bedeutet, dass Unterressourcendaten nach einer Barriere für alle layoutkompatiblen Zugriffe verfügbar sein müssen. Da Puffer kein Layout haben, bedeutet D3D12DDI_BARRIER_ACCESS_COMMON einfach einen pufferkompatiblen Zugriff.

Die Angabe D3D12DDI_BARRIER_ACCESS_COMMON als AccessBefore in einer Barriere impliziert den Satz aller Schreibzugriffstypen. Die Verwendung von D3D12DDI_BARRIER_ACCESS_COMMON als AccessBefore wird abgeraten, da dies zu kostspieligen, unbeabsichtigten Cachelöschungen führen könnte. Stattdessen werden Entwickler ermutigt, nur die schmalsten erforderlichen Schreibzugriffsbits zu verwenden, um den Barriereaufwand ordnungsgemäß einzuschränken. Eine Debug-Ebenenwarnung wird ausgegeben, wenn AccessBefore auf D3D12DDI_BARRIER_ACCESS_COMMON festgelegt ist.

Gleichzeitiger Zugriff in einer Warteschlange

Erweiterte Barrieren ermöglichen gleichzeitige Lese-/Schreibvorgänge für denselben Puffer oder die Textur für den gleichzeitigen Zugriff in derselben Befehlswarteschlange.

Puffer und Ressourcen für den gleichzeitigen Zugriff unterstützen immer Schreibzugriff aus einer Warteschlange mit gleichzeitigen, nicht unabhängigen, Lesezugriffen aus einer oder mehreren anderen Warteschlangen. Der Grund für diese Unterstützung besteht darin, dass solche Ressourcen immer das COMMON-Layout verwenden und keine Lese-/Schreibrisiken aufweisen, da Lesevorgänge nicht von gleichzeitigen Schreibvorgängen abhängen dürfen. (Legacy-Regeln für Ressourcenbarrieren verbieten die Kombination von Schreibzustandsbits mit anderen Zustandsbits. Ressourcen können daher nicht gleichzeitig mit älteren Ressourcenbarrieren gelesen und in dieselbe Warteschlange geschrieben werden.)

Die Regel, dass immer nur ein Schreiber gleichzeitig verwendet werden kann, gilt weiterhin, da zwei scheinbar nicht überlappende Schreibbereiche dennoch überlappende Cache-Zeilen aufweisen können.

Unterressourcenbereiche

Es ist üblich, dass Entwickler einen Bereich von Unterressourcen übertragen möchten. Ein Beispiel ist das Übergang einer vollständigen Mip-Kette für ein bestimmtes Texturarray oder eine einzelne Mip-Ebene für alle Arraysegmente. Mit verbesserten Barrieren können Entwickler logisch angrenzende Bereiche von Unterressourcen mithilfe der D3D12DDI_BARRIER_SUBRESOURCE_RANGE-Struktur übertragen. (Legacy-Ressourcenzustandsübergangsbarrieren bieten Entwicklern nur die Möglichkeit, alle Unterressourcenzustände oder einen einzelnen Unterressourcenzustand atomisch zu übertragen.)

Compute und Direkte Warteschlangenlayouts

Die folgenden erweiterten Barrierelayouts sind garantiert für direkte und Computewarteschlangen identisch:

  • D3D12DDI_BARRIER_LAYOUT_GENERIC_READ
  • D3D12DDI_BARRIER_LAYOUT_UNORDERED_ACCESS
  • D3D12DDI_BARRIER_LAYOUT_SHADER_RESOURCE
  • D3D12DDI_BARRIER_LAYOUT_COPY_SOURCE
  • D3D12DDI_BARRIER_LAYOUT_COPY_DEST

Eine Unterressource in einem dieser Layouts kann entweder in direkten Warteschlangen oder Computewarteschlangen ohne Layoutübergang verwendet werden.

Bei mancher Hardware können Layoutübergangsbarrieren für direkte Warteschlangen erheblich schneller sein, wenn sich beide vorhergehenden oder nachfolgenden Zugriffe auch auf direkte Warteschlangen befinden. Es wird dringend empfohlen, auf Ressourcen in direkten Warteschlangen zuzugreifen, indem Sie die folgenden Layouts verwenden:

  • D3D12DDI_BARRIER_LAYOUT_DIRECT_QUEUE_GENERIC_READ
  • D3D12DDI_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS
  • D3D12DDI_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE
  • D3D12DDI_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_SOURCE
  • D3D12DDI_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_DEST

Die DIRECT_QUEUE-Layoutvarianten sind nicht mit Computewarteschlangen kompatibel und können nicht in Computebefehlslistenbarrieren verwendet werden. Sie sind jedoch mit Computevorgängen in direkten Warteschlangen kompatibel.

Barrierefreier Zugang

Da zwischen ExecuteCommandLists-Begrenzungen keine ausstehenden Befehle oder Zwischenspeicherungsvorgänge vorhanden sein müssen, kann zunächst auf Puffer in einem ExecuteCommandLists-Bereich ohne Barriere zugegriffen werden. Ebenso kann unter den folgenden Bedingungen zunächst ohne Barriere auf Textur-Unterressourcen zugegriffen werden:

  • Das Unterressourcenlayout ist mit dem Zugriffstyp kompatibel.
  • Alle erforderlichen Komprimierungsmetadaten werden initialisiert.

Auf Texturunterressourcen im Layout D3D12DDI_BARRIER_LAYOUT_COMMON (oder einem warteschlangenspezifischen allgemeinen Layout wie D3D12DDI_BARRIER_LAYOUT_DIRECT_QUEUE_COMMON), die keine potenziell ausstehenden Lese- oder Schreibvorgänge aufweisen, kann in einem ExecuteCommandLists-Befehlsstrom ohne Barriere mit einem der folgenden Zugriffstypen zugegriffen werden:

  • D3D12DDI_BARRIER_ACCESS_SHADER_RESOURCE
  • D3D12DDI_BARRIER_ACCESS_COPY_SOURCE
  • D3D12DDI_BARRIER_ACCESS_COPY_DEST

Darüber hinaus kann ein Puffer oder eine Textur mit einem warteschlangenspezifischen allgemeinen Layout D3D12DDI_BARRIER_ACCESS_UNORDERED_ACCESS ohne Barriere verwenden.

Auf Puffer und Texturen mit gleichzeitigem Zugriff (Texturen, die mit dem Flag D3D12DDI_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS erstellt wurden) kann zunächst in einem ExecuteCommandLists-Befehlsstrom ohne Barriere mit einem der folgenden Zugriffstypen zugegriffen werden:

  • D3D12DDI_BARRIER_ACCESS_VERTEX_BUFFER
  • D3D12DDI_BARRIER_ACCESS_CONSTANT_BUFFER
  • D3D12DDI_BARRIER_ACCESS_INDEX_BUFFER
  • D3D12DDI_BARRIER_ACCESS_RENDER_TARGET
  • D3D12DDI_BARRIER_ACCESS_UNORDERED_ACCESS
  • D3D12DDI_BARRIER_ACCESS_SHADER_RESOURCE
  • D3D12DDI_BARRIER_ACCESS_STREAM_OUTPUT
  • D3D12DDI_BARRIER_ACCESS_INDIRECT_ARGUMENT
  • D3D12DDI_BARRIER_ACCESS_COPY_DEST
  • D3D12DDI_BARRIER_ACCESS_COPY_SOURCE
  • D3D12DDI_BARRIER_ACCESS_RESOLVE_DEST
  • D3D12DDI_BARRIER_ACCESS_RESOLVE_SOURCE
  • D3D12DDI_BARRIER_ACCESS_PREDICATION

Auch nachfolgende Zugriffe können ohne Barriere mit maximal einer Schreibzugriffsart erfolgen. Mit Ausnahme von D3D12DDI_BARRIER_ACCESS_RENDER_TARGET müssen Jedoch Barrieren verwendet werden, um sequenzielle Schreibvorgänge in dieselbe Ressource zu leeren.

Selbst erstellte Ressourcenkopie

Obwohl diese Funktion nicht ausschließlich auf die verbesserten Barrieren zurückzuführen ist, ist sie häufig nachgefragt. Die Möglichkeit, Kopien von einem Bereich einer Teilressource in einen anderen, nicht überschneidenden Bereich zuzulassen, ist zwar nicht unbedingt auf die verbesserten Barrieren zurückzuführen, aber sie ist eine häufig nachgefragte Funktion. Mit erweiterten Barrieren kann eine Unterressource mit einem gemeinsamen Layout sowohl als Quelle als auch als Ziel im gleichen CopyBufferRegion- oder CopyTextureRegion-Aufruf verwendet werden. Kopien zwischen überschneidende Quell- und Zielspeicherbereiche erzeugen nicht definierte Ergebnisse. Die Debugschicht MUSS anhand dieser Ergebnisse überprüft werden. (Der Entwurf einer Legacyressource für Ressourcenbarrieren lässt nicht zu, dass sich eine Unterressource gleichzeitig im D3D12DDI_RESOURCE_STATE_COPY_SOURCE- und D3D12DDI_RESOURCE_STATE_COPY_DEST-Zustand befindet und somit nicht in sich selbst kopiert werden kann.)

Initialisierung von Ressourcenmetadaten

Für das Design der Legacyressourcenbarrieren ist "Löschen", "Kopieren" oder "Verwerfen" erforderlich, um neu platzierte und aktivierte aliasierte Texturressourcen zu initialisieren, bevor sie als Renderziel- oder Tiefenschablonenressource verwendet werden. Diese Anforderung liegt daran, dass Renderziel- und Tiefenschablonenressourcen in der Regel Komprimierungsmetadaten verwenden, die initialisiert werden müssen, damit die Daten gültig sind. Das gleiche gilt für reservierte Texturen mit neu aktualisierter Kachelzuordnung.

Erweiterte Barrieren unterstützen eine Option zum Verwerfen als Teil einer Barriere. Barrierelayoutübergänge von D3D12DDI_BARRIER_LAYOUT_UNDEFINED zu einem potenziell komprimierten Layout (z. B. D3D12DDI_BARRIER_LAYOUT_RENDER_TARGET, D3D12DDI_BARRIER_LAYOUT_DEPTH_STENCIL, D3D12DDI_BARRIER_LAYOUT_UNORDERED_ACCESS) MÜSSEN Komprimierungsmetadaten initialisieren, wenn D3D12DDI_TEXTURE_BARRIER_FLAG_DISCARD im Member D3D12DDI_TEXTURE_BARRIER::Flags vorhanden ist.

Zusätzlich zu Renderziel- und Tiefen-/Schablonenressourcen gibt es ähnliche Optimierungen der UAV-Texturkomprimierung, die das Legacy-Barrieremodell nicht unterstützt hat.

Barriere-Sortierung

Barrieren werden in der Vorwärtsreihenfolge in die Warteschlange gestellt (API-Aufrufreihenfolge, Barrier-Group-Index, Barrier-Array-Index). Mehrere Barrieren auf derselben Unterressource müssen so funktionieren, als ob die Barrieren in der Warteschlange abgeschlossen sind.

In die Warteschlange eingereihte Barrieren mit übereinstimmenden SyncAfter-Bereichen, die potenziell in denselben Speicher schreiben, müssen alle Schreibvorgänge in der Warteschlange abgeschlossen werden. Diese Anforderung vermeidet Datenrennen bei Barrieren, die Ressourcenaliasing unterstützen. Beispielsweise muss eine Barriere, die eine Ressource deaktiviert, alle Caches vor einer anderen Barriere leeren, die eine andere Ressource auf demselben Speicher aktiviert, mögliche Löschmetadaten.