Freigeben über


Indirektes Zeichnen

Indirektes Zeichnen ermöglicht es, einen Teil des Szenendurchlaufs und des Culling von der CPU auf die GPU zu verlagern, was die Leistung verbessern kann. Der Befehlspuffer kann von der CPU oder der GPU erzeugt werden.

Befehlssignaturen

Das Objekt für die Befehlssignatur (ID3D12CommandSignature) ermöglicht es Anwendungen, das indirekte Zeichnen zu spezifizieren und insbesondere die folgenden Einstellungen vorzunehmen:

Beim Start erstellt eine App eine kleine Gruppe von Befehlssignaturen. Zur Runtime füllt die Anwendung einen Puffer mit Befehlen (mit den Mitteln, die der App-Entwickler wählt). Die Befehle enthalten optional den zu setzenden Status für Vertexpuffer-Ansichten, Indexpuffer-Ansichten, Root-Konstanten und Root-Deskriptoren (rohe oder strukturierte SRV/UAV/CBVs). Diese Argumentlayouts sind nicht hardwarespezifisch, sodass Apps die Puffer direkt generieren können. Die Befehlssignatur erbt den verbleibenden Status von der Befehlsliste. Dann ruft die Anwendung ExecuteIndirect auf, um die GPU anzuweisen, den Inhalt des indirekten Argumentpuffers gemäß dem durch eine bestimmte Befehlssignatur definierten Format zu interpretieren.

Wenn die Befehlssignatur irgendwelche Stammargumente ändert, wird dies in der Befehlssignatur als Teilmenge einer Stammsignatur gespeichert.

Der Status der Befehlssignatur läuft nicht in die Befehlsliste zurück, nachdem die Ausführung abgeschlossen ist. Nach ExecuteIndirect werden jedoch alle Bindungen auf bekannte Werte zurückgesetzt. Dies gilt insbesondere für:

  • Wenn die Befehlssignatur einen Vertexpuffer an einen bestimmten Slot bindet, dann wird nach dem Aufruf von ExecuteIndirect ein NULL-Vertexpunktpuffer an diesen Slot gebunden.
  • Wenn die Befehlssignatur einen Indexpuffer bindet, wird nach ExecuteIndirect ein NULL-Indexpuffer gebunden.
  • Wenn die Befehlssignatur eine Stammkonstante festlegt, wird der Root-Konstantenwert nach dem Aufruf von ExecuteIndirect auf 0 festgelegt.
  • Wenn die Befehlssignatur eine Root-Ansicht (CBV/SRV/UAV) festlegt, wird die Root-Ansicht nach dem Aufruf von ExecuteIndirect auf eine NULL-Ansicht festgelegt.

Beispiel für die Verwendung von Befehlssignaturen: Angenommen, ein Anwendungsentwickler möchte, dass für jeden Zeichnungsaufruf eine eindeutige Root-Konstante im indirekten Argumentpuffer angegeben wird. Die App würde eine Befehlssignatur erstellen, mit der der indirekte Argumentpuffer die folgenden Parameter pro Zeichnungsaufruf angeben kann:

  • Den Wert einer Root-Konstante.
  • Die Zeichnungsargumente (Vertexanzahl, Anzahl der Instanzen usw.).

Der von der Anwendung generierte indirekte Argumentpuffer enthält ein Array von Datensätzen mit fester Größe. Jede Struktur entspricht einem Zeichnungsaufruf. Jede Struktur enthält die Zeichnungsargumente und den Wert der Root-Konstante. Die Anzahl der Zeichnungsaufrufe wird in einem separaten GPU-sichtbaren Puffer angegeben.

Es folgt ein Beispiel für einen von der Anwendung generierten Befehlspuffer:

Befehlspufferformat

Indirekte Argumentpuffer-Strukturen

Die folgenden Strukturen definieren, wie bestimmte Argumente in einem indirekten Argumentpuffer angezeigt werden. Diese Strukturen werden in keiner D3D12-API angezeigt. Anwendungen verwenden diese Definitionen beim Schreiben in einen indirekten Argumentpuffer (mit der CPU oder GPU):

Erstellen von Befehlssignaturen

Verwenden Sie zum Erstellen einer Befehlssignatur die folgenden API-Elemente:

Die Reihenfolge der Argumente innerhalb eines indirekten Argumentpuffers ist so definiert, dass sie genau mit der Reihenfolge der im Parameter pArguments von D3D12_COMMAND_SIGNATURE_DESC angegebenen Argumente übereinstimmt. Alle Argumente für einen Zeichnungsaufruf (Grafik)/Dispatch (Compute) innerhalb eines indirekten Argumentpuffers sind eng gepackt. Anwendungen dürfen jedoch einen beliebigen Byte-Stride zwischen Zeichungs-/Dispatchbefehlen in einem indirekten Argumentpuffer angeben.

Die Root-Signatur muss nur angegeben werden, wenn die Befehlssignatur eines der Root-Argumente ändert.

Für Root-SRV/UAV/CBV ist die von der Anwendung angegebene Größe in Bytes. Die Debugging-Ebene überprüft die folgenden Einschränkungen für die Adresse:

  • CBV – Adresse muss ein Vielfaches von 256 Byte sein.
  • Raw SRV/UAV – Adresse muss ein Vielfaches von 4 Bytes sein.
  • Strukturierte SRV/UAV – Adresse muss ein Vielfaches des (im Shader deklarierten) Strukturbyte-Strides sein.

Eine bestimmte Befehlssignatur ist entweder eine Zeichnungs- oder eine Berechnungsbefehlssignatur. Wenn eine Befehlssignatur einen Zeichnungsvorgang enthält, handelt es sich um eine Grafikbefehlssignatur. Andernfalls muss die Befehlssignatur einen Dispatchvorgang enthalten, und es handelt sich um eine Berechnungsbefehlssignatur.

Die folgenden Abschnitte zeigen einige beispielhafte Befehlssignaturen.

Keine Argumentänderungen

In diesem Beispiel enthält der von der Anwendung generierte indirekte Argumentpuffer ein Array von 36-Byte-Strukturen. Jede Struktur enthält nur die fünf Parameter, die an DrawIndexedInstanced (plus Auffüllung) übergeben werden.

Es folgt der Code zur Erstellung der Befehlssignaturbeschreibung:

D3D12_INDIRECT_ARGUMENT_DESC Args[1];
Args[0].Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED;

D3D12_COMMAND_SIGNATURE_DESC ProgramDesc;
ProgramDesc.ByteStride = 36;
ProgramDesc.NumArgumentDescs = 1;
ProgramDesc.pArguments = Args;

Das Layout einer einzelnen Struktur innerhalb eines indirekten Argumentpuffers lautet:

Bytes Beschreibung
0:3 IndexCountPerInstance
4:7 InstanceCount
8:11 StartIndexLocation
12:15 BaseVertexLocation
16:19 StartInstanceLocation
20:35 Auffüllen

 

Root-Konstanten und Vertexpuffer

In diesem Beispiel ändert jede Struktur in einem indirekten Argumentpuffer zwei Root-Konstanten, ändert eine Vertexpufferbindung und führt einen nicht indizierten Zeichnungsvorgang aus. Es gibt kein Auffüllen zwischen Strukturen.

Der Code zum Erstellen der Befehlssignaturbeschreibung lautet:

D3D12_INDIRECT_ARGUMENT_DESC Args[4];
Args[0].Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT;
Args[0].Constant.RootParameterIndex = 2;
Args[0].Constant.DestOffsetIn32BitValues = 0;
Args[0].Constant.Num32BitValuesToSet = 1;

Args[1].Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT;
Args[1].Constant.RootParameterIndex = 6;
Args[1].Constant.DestOffsetIn32BitValues = 0;
Args[1].Constant.Num32BitValuesToSet = 1;

Args[2].Type = D3D12_INDIRECT_ARGUMENT_TYPE_VERTEX_BUFFER_VIEW;
Args[2].VertexBuffer.Slot = 3;

Args[3].Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW;

D3D12_COMMAND_SIGNATURE_DESC ProgramDesc;
ProgramDesc.ByteStride = 40;
ProgramDesc.NumArgumentDescs = 4;
ProgramDesc.pArguments = Args;

Das Layout einer einzelnen Struktur innerhalb des indirekten Argumentpuffers lautet wie folgt:

Bytes Beschreibung
0:3 Daten für den Root-Parameterindex 2
4:7 Daten für den Root-Parameterindex 6
8:15 Virtuelle VB-Adresse am Slot 3 (64-Bit)
16:19 VB-Größe
20:23 VB-Stride
24:27 VertexCountPerInstance
28:31 InstanceCount
32:35 StartVertexLocation
36:39 StartInstanceLocation

 

DirectX Video-Tutorials für Fortgeschrittene: Indirektes und asynchrones GPU-Culling ausführen

Indirekte Zeichnung und GPU-Culling: exemplarische Codedurchführung

Darstellung