Freigeben über


Portieren von Direct3D 11 zu Direct3D 12

Dieser Abschnitt enthält einige Anleitungen zum Portieren von einem benutzerdefinierten Direct3D 11-Grafikmodul zu Direct3D 12.

Geräteerstellung

Sowohl Direct3D 11 als auch Direct3D 12 teilen ein ähnliches Geräteerstellungsmuster. Vorhandene Direct3D 12-Treiber sind alle D3D_FEATURE_LEVEL_11_0 oder besser, sodass Sie die älteren Featureebenen und die zugehörigen Einschränkungen ignorieren können.

Denken Sie auch daran, dass Sie mit Direct3D 12 Geräteinformationen explizit mithilfe von DXGI-Schnittstellen auflisten sollten. In Direct3D 11 können Sie vom Direct3D-Gerät mit dem DXGI-Gerät verkettet werden, und dies wird für Direct3D 12 nicht unterstützt.

Das Erstellen eines WARP-Softwaregeräts auf Direct3D 12 erfolgt durch Bereitstellen eines expliziten Adapters, der von IDXGIFactory4::EnumWarpAdapter abgerufen wurde. Das WARP-Gerät für Direct3D 12 ist nur auf Systemen verfügbar, auf denen das optionale Feature "Grafiktools " aktiviert ist.

Hinweis

Es gibt kein Äquivalent zu D3D11CreateDeviceAndSwapChain. Auch bei Direct3D 11 wird davon abgeraten, diese Funktion zu verwenden, da es häufig besser ist, das Gerät und die Swapchain in unterschiedlichen Schritten zu erstellen.

Zugesicherte Ressourcen

Objekte, die mit den folgenden Schnittstellen in Direct3D 11 erstellt wurden, werden in Direct3D 12 als "zugesicherte Ressourcen" bezeichnet. Eine zugesicherte Ressource ist eine Ressource, die sowohl virtuellen Adressraum als auch physische Seiten zugeordnet ist. Dies ist ein Konzept des Microsoft Windows Device Driver 2 (WDD2)-Speichermodells, auf dem Direct3D 12 basiert.

Direct3D 11-Ressourcen:

In Direct3D 12 werden alle durch ID3D12Resource und ID3D12Device::CreateCommittedResource dargestellt.

Reservierte Ressourcen

Reservierte Ressourcen sind Ressourcen, bei denen nur virtueller Adressraum zugewiesen wurde, physischer Speicher wird erst zugewiesen, wenn ein Aufruf von ID3D12Device::CreateHeap erfolgt. Dies ist im Wesentlichen dasselbe Konzept wie nebeneinander angeordnete Ressourcen in Direct3D 11.

Die flags (D3D11_RESOURCE_MISC_FLAG), die in Direct3D 11 zum Einrichten von nebeneinander angeordneten Ressourcen verwendet werden, ordnen sie dann dem physischen Speicher zu.

  • D3D11_RESOURCE_MISC_TILED
  • D3D11_RESOURCE_MISC_TILE_POOL

Hochladen von Daten

In Direct3D 11 gibt es das Erscheinungsbild einer einzelnen Zeitachse (aufruft nach einer Sequenz, z. B. Daten, die mit D3D11_SUBRESOURCE_DATA initialisiert wurden, und dann wird ein Aufruf an ID3D11DeviceContext::UpdateSubresource und dann ein Aufruf an ID3D11DeviceContext::Map ausgeführt). Die Anzahl der Kopien, die mit den Daten erstellt wurden, ist für einen Direct3D 11-Entwickler nicht offensichtlich.

In Direct3D 12 gibt es zwei Zeitachsen, die GPU-Zeitachse (eingerichtet durch Aufrufe von CopyTextureRegion und CopyBufferRegion aus zugeordnetem Arbeitsspeicher) und die CPU-Zeitachse (bestimmt durch Aufrufe von Map). Hilfsfunktionen werden (in der Datei d3dx12.h) mit dem Namen Updatesubresources bereitgestellt, die eine freigegebene Zeitachse verwenden. Es gibt mehrere Varianten dieser Hilfsfunktion, eine, die ID3D12Device::GetCopyableFootprints verwendet, eine andere, die einen Heap-Allocating-Mechanismus verwendet, und eine andere, die einen Stack-Allocating-Mechanismus verwendet. Diese Hilfsfunktionen kopieren Ressourcen sowohl in die GPU als auch in die CPU über einen zwischengeschalteten Stagingbereich des Arbeitsspeichers.

In der Regel verfügen gpu und CPU jeweils über eine eigene Kopie einer Ressource, die an ihre eigene Zeitachse gebunden ist. Der Ansatz für die gemeinsame Zeitachse verwaltet auf ähnliche Weise zwei Kopien.

Shader und Shaderobjekte

In Direct3D 11 gibt es eine Vielzahl von Shader- und Zustandsobjekten und festlegen den Status dieser Objekte mithilfe der ID3D11Device-Erstellungsmethoden und der ID3D11DeviceContext-Setmethoden. In der Regel erfolgt eine große Anzahl von Aufrufen an diese Methoden, die dann zum Zeichnen vom Treiber kombiniert werden, um den richtigen Pipelinezustand festzulegen.

In Direct3D 12 wurde diese Einstellung des Pipelinestatus in ein einzelnes Objekt (CreateComputePipelineState für ein Computemodul und CreateGraphicsPipelineState für ein Grafikmodul) kombiniert, das dann an eine Befehlsliste angefügt wird, bevor der Draw-Aufruf mit einem Aufruf von SetPipelineState aufgerufen wird.

Diese Aufrufe ersetzen alle einzelnen Aufrufe zum Festlegen von Shadern, Eingabelayout, Blend-Zustand, Rasterizerzustand, Tiefenschablonenzustand usw. in Direct3D 11

  • Device 11-Methoden: CreateInputLayout, , CreateXShader, CreateDepthStencilStateund CreateRasterizerState.
  • Device Context 11-Methoden: IASetInputLayout, , xxSetShader, OMSetBlendState, , OMSetDepthStencilStateund RSSetState.

Während Direct3D 12 ältere kompilierte Shader-Blobs unterstützen kann, sollten Shader entweder mithilfe des Shadermodells 5.1 mit den FXC/D3DCompile-APIs oder mithilfe des DXIL DXC-Compilers erstellt werden. Sie sollten die Shadermodell 6-Unterstützung mit CheckFeatureSupport und D3D12_FEATURE_SHADER_MODEL überprüfen.

Übermitteln von Arbeit an die GPU

in Direct3D 11 gibt es wenig Kontrolle darüber, wie Arbeit übermittelt wird, es wird weitgehend vom Treiber behandelt, obwohl einige Steuerelemente über die AUFRUFe ID3D11DeviceContext::Flush und IDXGISwapChain1::P resent1 aktiviert sind.

In der Direct3D 12-Arbeitsübermittlung ist die App sehr explizit und gesteuert. Das primäre Konstrukt zum Übermitteln von Arbeiten ist die ID3D12GraphicsCommandList, die verwendet wird, um alle Apps-Befehle aufzuzeichnen (und ähnelt dem verzögerten ID3D11-Kontext). Der Sicherungsspeicher für eine Befehlsliste wird vom ID3D12CommandAllocator bereitgestellt, mit dem die App die Speicherauslastung der Befehlsliste verwalten kann, indem tatsächlich der Speicher verfügbar gemacht wird, den der Direct3D 12-Treiber zum Speichern der Befehlsliste verwendet.

Schließlich ist die ID3D12CommandQueue eine First-In-First-Out-Warteschlange, in der die richtige Reihenfolge der Befehlslisten für die Übermittlung an die GPU gespeichert wird. Nur wenn eine Befehlsliste die Ausführung auf der GPU abgeschlossen hat, wird die nächste Befehlsliste aus der Warteschlange vom Treiber übermittelt.

In Direct3D 11 gibt es kein explizites Konzept einer Befehlswarteschlange. Im allgemeinen Setup für Direct3D 12 kann die derzeit geöffnete D3D12_COMMAND_LIST_TYPE_DIRECT Befehlsliste für den aktuellen Frame analog zum Direkten Kontext von Direct3D 11 betrachtet werden. Dies bietet viele der gleichen Funktionen.

D3D11DeviceContext ID3D12GraphicsCommand List
ClearDepthStencilView ClearDepthStencilView
ClearRenderTargetView ClearRenderTargetView
ClearUnorderedAccess* ClearUnorderedAccess*
Draw, DrawInstanced DrawInstanced
DrawIndexed, DrawIndexedInstanced DrawIndexedInstanced
Disponieren Disponieren
IASetInputLayout, xxSetShader usw. SetPipelineState
OMSetBlendState OMSetBlendFactor
OMSetDepthStencilState OMSetStencilRef
OMSetRenderTargets OMSetRenderTargets
RSSetViewports RSSetViewports
RSSetScissorRects RSSetScissorRects
IASetPrimitiveTopology IASetPrimitiveTopology
IASetVertexBuffers IASetVertexBuffers
IASetIndexBuffer IASetIndexBuffer
ResolveSubresource ResolveSubresource
CopySubresourceRegion CopyBufferRegion
UpdateSubresource CopyTextureRegion
CopyResource CopyResource

Hinweis

Eine mit D3D12_COMMAND_LIST_TYPE_BUNDLE erstellte Befehlsliste ist simliar für einen verzögerten Kontext. Direct3D 12 unterstützt auch die Möglichkeit, auf einige Features eines unmittelbaren Kontexts gleichzeitig auf das Rendern über D3D12_COMMAND_LIST_TYPE_COPY und D3D12_COMMAND_LIST_TYPE_COMPUTE Befehlslistentypen zuzugreifen.

CPU-/GPU-Synchronisierung

In direct3D 11 cpu/GPU-Synchronisierung war weitgehend automatisch, und die App musste den Status des physischen Arbeitsspeichers nicht beibehalten.

in Direct3D 12 muss die App die beiden Zeitachsen (CPU und GPU) explizit verwalten. Dies erfordert, dass Informationen von der App verwaltet werden müssen, welche Ressourcen von der GPU benötigt werden und wie lange. Dies bedeutet auch, dass die App dafür verantwortlich ist, sicherzustellen, dass der Inhalt von Ressourcen (zugesicherte Ressourcen, Heaps, Befehlszuordnungen, z. B. Befehlszuweisungen) erst geändert wird, wenn die GPU sie verwendet hat.

Das Hauptobjekt zum Synchronisieren der Zeitachsen ist das ID3D12Fence-Objekt. Der Betrieb von Zaunen ist ziemlich einfach, sie ermöglichen es der GPU, zu signalisieren, wenn sie eine Aufgabe abgeschlossen hat. Die GPU und CPU können beide Signale signalisieren und beide auf Zäune warten.

In der Regel ist der Ansatz, dass beim Übermitteln einer Befehlsliste für die Ausführung ein Zaunsignal von der GPU nach Abschluss übertragen wird (wenn sie das Lesen der Daten abgeschlossen hat), sodass die CPU die Ressourcen wiederverwenden oder zerstören kann.

In Direct3D 11 wurde die ID3D11DeviceContext::Map-Kennzeichnung D3D11_MAP_WRITE_DISCARD jede Ressource im Wesentlichen als endlose Speichermenge behandelt, in die die App schreiben könnte (ein Prozess, der als "Umbenennen" bezeichnet wird). In Direct3D 12 ist der Prozess erneut explizit: Zusätzlicher Speicher muss zugewiesen werden, und Zäune sollten zum Synchronisieren der Vorgänge verwendet werden. Ringpuffer (bestehend aus großen Puffern) können hierfür eine gute Technik sein, siehe das Ringpufferszenario in der Zaunbasierten Ressourcenverwaltung.

Verwenden eines Ringpuffers

Ressourcenbindung

Ansichten in Direct3D 11 (Shaderressourcenansichten, Renderzielansichten usw.) wurden in Direct3D 12 weitgehend durch das Konzept eines Deskriptors ersetzt. Die Erstellungsmethoden sind weiterhin in Direct3D 12 (z. B. CreateShaderResourceView und CreateRenderTargetView) vorhanden, die aufgerufen werden, nachdem der Deskriptor-Heap erstellt wurde, um die Daten in den Heap zu schreiben. Die Bindung in Direct3D 12 wird jetzt von Deskriptorhandles behandelt, die in einer Stammsignatur beschrieben sind und mithilfe der Methoden SetGraphicsRootDescriptorTable oder SetComputeRootDescriptorTable übermittelt werden.

Die Stammsignaturen enthalten Zuordnungen zwischen der Stammsignaturplatznummer und den Deskriptortabellen, in denen die Deskriptortabelle Verweise auf Ressourcen enthalten kann, die für Vertex-Shader, Pixelshader und die anderen Shader verfügbar sind, z. B. Konstantenpuffer, Shaderressourcenansichten und Sampler. Diese Flexibilität trennt den HLSL-Registrierungsspeicherplatz vom API-Bindungsbereich in Direct3D 12, im Gegensatz zu Direct3D 11, bei dem es eine zu einer Zuordnung zwischen diesen gibt.

Eine der Auswirkungen dieses Systems besteht darin, dass die App für die Umbenennung von Deskriptortabellen verantwortlich ist, wodurch Entwickler die Leistungskosten für die Änderung sogar eines einzelnen Deskriptors pro Draw-Aufruf verstehen können.

Ein neues Feature von Direct3D 12 besteht darin, dass eine App steuern kann, welche Deskriptoren zwischen welchen Shaderphasen gemeinsam verwendet werden. In Direct3D 11-Ressourcen wie UAVs werden zwischen allen Shaderphasen gemeinsam genutzt. Indem Deskriptoren für bestimmte Shaderphasen deaktiviert werden können, stehen die register, die von deaktivierten Deskriptoren verwendet werden, für die deskriptoren zur Verfügung stehen, die für eine bestimmte Shaderstufe aktiviert sind.

Die folgende Tabelle zeigt eine Beispielstammsignatur.

Stammparameterplatz Beschreibungstabelleneintrag
0 VS-Beschreibungsbereich b0-b13
1 VS-Beschreibungsbereich t0-t127
2 VS-Beschreibungsbereich s0-s16
3 PS-Beschreibungsbereich b0-b13
...
14 DS-Beschreibungsbereich s0-16
15 Shared Descriptor Range u0-u63

 

Ressourcenzustand

In Direct3D 11 wird der Ressourcenstatus nicht von der App verwaltet, sondern vom Treiber.

In Direct3D 12 wird die Verwaltung des Ressourcenzustands zur Verantwortung der App, um die vollständige Parallelität in der Aufzeichnung von Befehlslisten zu ermöglichen: Die App muss die Aufzeichnungszeitachsen für Befehlslisten verarbeiten (die parallel ausgeführt werden können) und die Ausführungszeitachsen, die sequenziell sein müssen.

Ein Ressourcenstatusübergang wird von der ResourceBarrier-Methode behandelt. In erster Linie muss die App den Treiber informieren, wenn sich die Ressourcennutzung ändert. Wenn z. B. eine Ressource als Renderziel verwendet wird und dann als Eingabe für einen Vertex-Shader im nächsten Draw-Aufruf verwendet werden soll, ist dies möglicherweise ein kurzer Stände im GPU-Vorgang erforderlich, um den Renderzielvorgang abzuschließen, bevor der Vertex-Shader verarbeitet wird.

Dieses System ermöglicht eine feinkörnige Synchronisierung (die GPU-Stände) der Grafikpipeline sowie Cache-Leerungen und möglicherweise einige Speicherlayoutänderungen (z. B. Renderzielansicht zur Dekomprimierung der Tiefenschablonenansicht).

Dies wird als Übergangsbarriere bezeichnet. Es gibt andere Arten von Barrieren, in Direct3D 11 hat der ID3D11DeviceContext2::TiledResourceBarrier denselben physischen Speicher aktiviert, der von zwei verschiedenen nebeneinander angeordneten Ressourcen verwendet werden kann. In Direct3D 12 wird dies als "Aliasbarriere" bezeichnet. Aliasingbarrieren können sowohl für nebeneinander angeordnete als auch für platzierte Ressourcen in Direct3D 12 verwendet werden. Darüber hinaus gibt es die UAV-Barriere. In Direct3D 11 müssen alle UAV-Dispatch- und Draw-Vorgänge serialisiert werden, auch wenn diese Vorgänge parallel weitergeleitet oder bearbeitet werden können. Bei Direct3D 12 wird diese Einschränkung durch das Hinzufügen einer UAV-Barriere entfernt. Eine UAV-Barriere stellt sicher, dass UAV-Vorgänge sequenziell sind. Wenn also ein zweiter Vorgang erfordert, dass der erste Abschluss erforderlich ist, wird die zweite zum Warten durch die Hinzufügung der Barriere gezwungen. Der Standardvorgang für UAVs ist einfach, dass die Vorgänge so schnell wie möglich fortgesetzt werden.

Es gibt eindeutig Leistungsgewinne, wenn eine Workload parallelisiert werden kann.

Swapchains

Die DXGI-Swapchain ist die Basis für Swapchains in Direct3D 11 und 12. In Direct3D 11 gibt es einige geringfügige Unterschiede, die drei Arten von Swapchain sind SEQUENZIELL, VERWERFEN und FLIP_SEQUENTIAL. Für Direct3D 12 gibt es nur zwei Typen: FLIP_SEQUENTIAL und FLIP_DISCARD. Wie oben erwähnt, sollten Sie ihre Swapchain explizit über IDXGIFactory4 oder höher erstellen und dieselbe Schnittstelle für jede Adapterenumeration verwenden.

In Direct3D 11 gibt es eine automatische Backbufferdrehung: Für den Hintergrundpuffer 0 ist nur eine Renderzielansicht erforderlich. In Direct3D 12 ist die Pufferdrehung explizit, es muss eine Renderzielansicht für jeden Hintergrundpuffer vorhanden sein. Verwenden Sie die IDXGISwapChain3::GetCurrentBackBufferIndex-Methode , um auszuwählen, auf welche Methode gerendert werden soll. Auch diese zusätzliche Flexibilität ermöglicht eine größere Parallelisierung.

Hinweis

Während es zahlreiche Möglichkeiten zum Einrichten Ihrer Anwendung gibt, verfügen Anwendungen im Allgemeinen über einen ID3D12CommandAllocator pro Swapchainpuffer. Auf diese Weise kann die Anwendung fortfahren, eine Reihe von Befehlen für den nächsten Frame zu erstellen, während die GPU die vorherige rendert.

Festes Funktionsrendering

In Direct3D 11 gab es einige Methoden, mit denen verschiedene Vorgänge auf höherer Ebene vereinfacht wurden, z. B. GenerateMips (Erstellen vollständiger Mip-Ketten) und DrawAuto (verwendung der Streamausgabe als Shadereingabe ohne weitere Eingabe aus der App). Diese Methoden sind in Direct3D 12 nicht verfügbar, die App muss diese Vorgänge behandeln, indem Shader erstellt werden, um sie auszuführen.

Quoten und Enden

Die folgende Tabelle zeigt eine Reihe von Features, die zwischen Direct3D 11 und 12 ähnlich sind, aber nicht identisch sind.

Direct3D 11 Direct3D 12
ID3D11Query ID3D12QueryHeap ermöglicht das Gruppieren von Abfragen, wodurch die Kosten reduziert werden.
ID3D11Predicate Die Prädierung ist jetzt aktiviert, indem Daten in einem vollständig transparenten Puffer vorhanden sind. Das Direct3D 11 ID3D11Predicate-Objekt wird durch ID3D12Resource::Map ersetzt, das einem Aufruf von ResolveQueryData und einem GPU-Synchronisierungsvorgang unter Verwendung eines Zauns folgen muss, damit die Daten bereit sind. Verweisen Sie auf die Prädication.
Ausgeblendeter UAV/SO-Zähler Die App ist für die Zuweisung und Verwaltung von SO/UAV-Leistungsindikatoren verantwortlich. Verweisen Sie auf Datenstromausgabezähler und UAV-Leistungsindikatoren.
Ressourcen dynamic MinLOD (Minium level of detail) Dies wurde in die SRV-Deskriptor statische MinLOD verschoben.This has been moved to the SRV descriptor static MinLOD.
Draw*Indirect/DispatchIndirect Zeichnung indirekter Methoden werden alle mit der einzigen ExecuteIndirect-Methode zusammengeführt.
Tiefenschablonenformate werden interleaviert Tiefenschablonenformate sind planar. Beispielsweise würde ein Format von 24 Bit Tiefe, 8 Bit der Schablone im Format 24/8/24/8 gespeichert... usw. in Direct3D 11, aber als 24.24.24... gefolgt von 8/8/8... in Direct3D 12. Beachten Sie, dass jede Ebene eine eigene Unterressource in D3D12 ist (siehe Unterressourcen).
ResizeTilePool Reservierte Ressourcen können mehreren Heaps zugeordnet werden. Wenn ein Kachelpool in D3D11 gewachsen wäre, kann stattdessen ein zusätzlicher Heap in D3D12 zugewiesen werden.

 

Lernprogramme zum erweiterten Lernen von DirectX: DirectX 11 zu DirectX 12–Portierungshandbuch

Grundlegendes zu Direct3D 12

Arbeiten mit Direct3D 11, Direct3D 10 und Direct2D