Wichtige Änderungen beim Wechsel von Direct3D 11 zu Direct3D 12
Direct3D 12 stellt eine deutliche Abkehr vom Direct3D 11-Programmiermodell dar. Mit Direct3D 12 können Apps näher an die Hardware herankommen als je zuvor. Da direct3D 12 näher an der Hardware liegt, ist es schneller und effizienter. Der Nachteil, dass Ihre App die Geschwindigkeit und Effizienz mit Direct3D 12 erhöht hat, besteht darin, dass Sie für mehr Aufgaben verantwortlich sind als mit Direct3D 11.
- Explizite Synchronisierung
- Verwaltung der Physischen Speicherresidenz
- Pipelinestatusobjekte
- Befehlslisten und -bundles
- Deskriptorheaps und Tabellen
- Portieren von Direct3D 11
- Zugehörige Themen
Direct3D 12 ist eine Rückkehr zur Low-Level-Programmierung. Durch die Einführung dieser neuen Features erhalten Sie mehr Kontrolle über die grafischen Elemente Ihrer Spiele und Apps: Objekte zur Darstellung des Gesamtzustands der Pipeline, Befehlslisten und Bundles für die Arbeitsübermittlung sowie Deskriptorheaps und Tabellen für den Ressourcenzugriff.
Ihre App hat die Geschwindigkeit und Effizienz mit Direct3D 12 erhöht, aber Sie sind für mehr Aufgaben verantwortlich als mit Direct3D 11.
Explizite Synchronisierung
- In Direct3D 12 liegt die CPU-GPU-Synchronisierung jetzt explizit in der Verantwortung der App und wird nicht mehr implizit von der Runtime ausgeführt, wie in Direct3D 11. Diese Tatsache bedeutet auch, dass keine automatische Überprüfung auf Pipelinerisiken von Direct3D 12 durchgeführt wird, sodass wiederum dies die Verantwortung der Apps ist.
- In Direct3D 12 sind Apps für das Pipelining von Datenupdates verantwortlich. Das heißt, das Muster "Map/Lock-DISCARD" in Direct3D 11 muss manuell in Direct3D 12 ausgeführt werden. Wenn die GPU in Direct3D 11 weiterhin den Puffer verwendet, wenn Sie ID3D11DeviceContext::Map mit D3D11_MAP_WRITE_DISCARD aufrufen, gibt die Laufzeit einen Zeiger auf einen neuen Speicherbereich anstelle der alten Pufferdaten zurück. Dadurch kann die GPU weiterhin die alten Daten verwenden, während die App Daten im neuen Puffer platziert. In der App ist keine zusätzliche Speicherverwaltung erforderlich. Der alte Puffer wird automatisch wiederverwendet oder zerstört, wenn die GPU damit fertig ist.
- In Direct3D 12 werden alle dynamischen Updates (einschließlich Konstantenpuffern, dynamischen Vertexpuffern, dynamischen Texturen usw.) explizit von der App gesteuert. Diese dynamischen Updates umfassen alle erforderlichen GPU-Zäune oder Pufferungen. Die App ist dafür verantwortlich, den Arbeitsspeicher verfügbar zu halten, bis er nicht mehr benötigt wird.
- Direct3D 12 verwendet die Verweiszählung im COM-Stil nur für die Lebensdauer von Schnittstellen (durch Verwendung des schwachen Referenzmodells von Direct3D, das an die Lebensdauer des Geräts gebunden ist). Alle Ressourcen- und Beschreibungsspeicherlebensdauern sind die alleinige Verantwortung der App, die für die richtige Dauer verwaltet werden soll, und werden nicht als Verweis gezählt. Direct3D 11 verwendet die Verweiszählung, um auch die Lebensdauer von Schnittstellenabhängigkeiten zu verwalten.
Verwaltung der Physischen Speicherresidenz
Eine Direct3D 12-Anwendung muss Racebedingungen zwischen mehreren Warteschlangen, mehreren Adaptern und den CPU-Threads verhindern. D3D12 synchronisiert cpu und GPU nicht mehr und unterstützt keine praktischen Mechanismen für die Ressourcenumbenennung oder mehrstufige Pufferung. Zäune müssen verwendet werden, um zu verhindern, dass mehrere Verarbeitungseinheiten Arbeitsspeicher überschreiben, bevor eine andere Verarbeitungseinheit die Verwendung beendet.
Die Direct3D 12-Anwendung muss sicherstellen, dass daten im Arbeitsspeicher gespeichert sind, während die GPU sie liest. Der von jedem Objekt verwendete Arbeitsspeicher wird während der Erstellung des Objekts als resident festgelegt. Anwendungen, die diese Methoden aufrufen, müssen Zäune verwenden, um sicherzustellen, dass die GPU nicht auf entfernte Objekte zugreift.
Ressourcenbarrieren sind eine weitere Art der Synchronisierung, die zum Synchronisieren von Ressourcen- und Unterressourcenübergängen auf einer sehr präzisen Ebene verwendet wird.
Weitere Informationen finden Sie unter Arbeitsspeicherverwaltung in Direct3D 12.
Pipelinestatusobjekte
Direct3D 11 ermöglicht die Bearbeitung des Pipelinezustands durch einen großen Satz unabhängiger Objekte. Beispielsweise können der Eingabeasserzustand, der Pixelshaderzustand, der Rasterizerzustand und der Ausgabezusammenführungszustand unabhängig geändert werden. Dieser Entwurf bietet eine bequeme und relativ allgemeine Darstellung der Grafikpipeline, nutzt aber nicht die Funktionen moderner Hardware, vor allem weil die verschiedenen Zustände häufig voneinander abhängig sind. Beispielsweise kombinieren viele GPUs den Pixelshader und den Ausgabezusammenführungszustand in einer einzelnen Hardwaredarstellung. Da die Direct3D 11-API es jedoch ermöglicht, diese Pipelinephasen separat festzulegen, kann der Anzeigetreiber Probleme mit dem Pipelinestatus erst beheben, wenn der Zustand abgeschlossen ist, d. h. erst nach dem Zeichnen. Dieses Schema verzögert die Einrichtung des Hardwarezustands, was zusätzlichen Mehraufwand und weniger maximale Draw-Aufrufe pro Frame bedeutet.
Direct3D 12 adressiert dieses Schema, indem ein Großteil des Pipelinezustands in unveränderliche Pipelinezustandsobjekte (PSOs) vereinheitlicht wird, die bei der Erstellung abgeschlossen werden. Hardware und Treiber können den PSO dann sofort in alle hardwarenativen Anweisungen und Denkzustände konvertieren, die zum Ausführen der GPU-Arbeit erforderlich sind. Sie können immer noch dynamisch ändern, welcher PSO verwendet wird, aber dazu muss die Hardware nur die minimale Menge des vorab berechneten Zustands direkt in die Hardwareregister kopieren, anstatt den Hardwarezustand direkt zu berechnen. Durch die Verwendung von PSOs wird der Mehraufwand für Zeichnungsaufrufe erheblich reduziert, und es können viele weitere Zeichenaufrufe pro Frame erfolgen. Weitere Informationen zu PSOs finden Sie unter Verwalten des Grafikpipelinestatus in Direct3D 12.
Befehlslisten und -bundles
In Direct3D 11 erfolgt die gesamte Arbeitsübermittlung über den unmittelbaren Kontext, der einen einzelnen Stream von Befehlen darstellt, der an die GPU geht. Um eine Multithreadskalierung zu erreichen, verfügen Spiele auch über verzögerte Kontexte , die ihnen zur Verfügung stehen. Verzögerte Kontexte in Direct3D 11 sind nicht perfekt der Hardware zugeordnet, sodass relativ wenig Arbeit in ihnen ausgeführt werden kann.
Direct3D 12 führt ein neues Modell für die Arbeitsübermittlung ein, das auf Befehlslisten basiert, die die gesamten Informationen enthalten, die zum Ausführen einer bestimmten Workload auf der GPU erforderlich sind. Jede neue Befehlsliste enthält Informationen wie z. B. den zu verwendenden PSO, welche Textur- und Pufferressourcen benötigt werden, und die Argumente für alle Draw-Aufrufe. Da jede Befehlsliste eigenständig ist und keinen Zustand erbt, kann der Treiber alle erforderlichen GPU-Befehle vorab und im Freethread berechnen. Der einzige serielle Prozess, der erforderlich ist, ist die endgültige Übermittlung von Befehlslisten an die GPU über die Befehlswarteschlange.
Zusätzlich zu Befehlslisten führt Direct3D 12 auch eine zweite Ebene der Arbeitsvorbereitung ein: Bundles. Im Gegensatz zu Befehlslisten, die vollständig eigenständig sind und in der Regel erstellt, einmal übermittelt und verworfen werden, bieten Bundles eine Form der Zustandsvererbung, die die Wiederverwendung ermöglicht. Wenn ein Spiel beispielsweise zwei Zeichenmodelle mit unterschiedlichen Texturen zeichnen möchte, besteht ein Ansatz darin, eine Befehlsliste mit zwei Sätzen identischer Zeichenaufrufe aufzuzeichnen. Ein anderer Ansatz besteht jedoch darin, ein Bündel aufzuzeichnen, das ein einzelnes Zeichenmodell zeichnet, und dann das Bündel zweimal in der Befehlsliste mithilfe verschiedener Ressourcen wiederzugeben. Im letzteren Fall muss der Anzeigetreiber die entsprechenden Anweisungen nur einmal berechnen, und das Erstellen der Befehlsliste bedeutet im Wesentlichen zwei kostengünstige Funktionsaufrufe.
Weitere Informationen zu Befehlslisten und Paketen finden Sie unter Arbeitsübermittlung in Direct3D 12.
Deskriptorheaps und Tabellen
Die Ressourcenbindung in Direct3D 11 ist stark abstrahiert und praktisch, aber viele moderne Hardwarefunktionen werden nicht ausgelastet. In Direct3D 11 erstellen Spiele Ansichtsobjekte von Ressourcen und binden diese Ansichten dann an mehrere Slots in verschiedenen Shaderphasen in der Pipeline. Shader lesen wiederum Daten aus diesen expliziten Bindungsslots, die zur Zeichnungszeit festgelegt werden. Dieses Modell bedeutet, dass jedes Mal, wenn ein Spiel mit unterschiedlichen Ressourcen gezeichnet wird, unterschiedliche Ansichten an verschiedene Slots neu binden und das Zeichnen erneut aufrufen muss. Dieser Fall stellt auch den Mehraufwand dar, der durch die vollständige Nutzung moderner Hardwarefunktionen vermieden werden kann.
Direct3D 12 ändert das Bindungsmodell an moderne Hardware und verbessert die Leistung erheblich. Anstatt eigenständige Ressourcenansichten und explizite Zuordnungen zu Slots zu erfordern, stellt Direct3D 12 einen Deskriptorheap bereit, in dem Spiele ihre verschiedenen Ressourcenansichten erstellen. Dieses Schema bietet einen Mechanismus, mit dem die GPU die hardwarenative Ressourcenbeschreibung (Deskriptor) direkt im Voraus in den Arbeitsspeicher schreibt. Um zu deklarieren, welche Ressourcen von der Pipeline für einen bestimmten Draw-Aufruf verwendet werden sollen, geben Spiele eine oder mehrere Deskriptortabellen an, die Teilbereiche des vollständigen Deskriptorheaps darstellen. Da der Deskriptorheap bereits mit den entsprechenden hardwarespezifischen Deskriptordaten aufgefüllt wurde, ist das Ändern von Deskriptortabellen ein äußerst kostengünstiger Vorgang.
Zusätzlich zur verbesserten Leistung von Deskriptorheaps und Tabellen ermöglicht Direct3D 12 auch die dynamische Indizierung von Ressourcen in Shadern, was eine beispiellose Flexibilität bietet und neue Renderingtechniken freischaltet. Beispielsweise codieren moderne verzögerte Rendering-Engines in der Regel einen Material- oder Objektbezeichner irgendeiner Art in den g-Zwischenpuffer. In Direct3D 11 müssen diese Engines darauf achten, zu viele Materialien zu verwenden, da das Einschließen von zu vielen in einem g-Puffer den endgültigen Renderdurchlauf erheblich verlangsamen kann. Mit dynamisch indizierbaren Ressourcen kann eine Szene mit tausend Materialien genauso schnell fertig werden wie eine mit nur zehn.
Weitere Informationen zu Deskriptorheaps und Tabellen finden Sie unter Ressourcenbindung und Unterschiede im Bindungsmodell von Direct3D 11.
Portieren von Direct3D 11
Die Portierung von Direct3D 11 ist ein beteiligter Prozess, der unter Portieren von Direct3D 11 zu Direct3D 12 beschrieben wird. Weitere Informationen finden Sie unter Arbeiten mit Direct3D 11, Direct3D 10 und Direct2D.
Zugehörige Themen