Welcher dieser DirectX11-Aufrufe sendet tatsächlich Daten an die GPU?

7

Ich versuche, Grafikprogrammierung und DirectX11 zu lernen.

Ich versuche zu lernen, wie man die Übertragung von CPU-GPU und die Grafikprogrammierung im Allgemeinen minimiert.
Ich habe eine Frage, die ich aus Online-Ressourcen nicht beantworten konnte:

Welche der D3D-Methoden sendet die Daten tatsächlich an die GPU (und bei einem statischen Netz werden ALLE Scheitelpunktdaten bei jedem Frame oder nur einmal an die GPU übergeben)?

Code folgt:
(vereinfacht für Stapelaustausch)

In meiner "Mesh" -Klasse habe ich einen Scheitelpunktpuffer:

ID3D11Buffer *m_pVBuffer;

Im Konstruktor meines Netzes habe ich einige Scheitelpunkte für den Scheitelpunktpuffer festgelegt:

D3D11_MAPPED_SUBRESOURCE ms;
devcon->Map(m_pVBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms);
memcpy(ms.pData, &vertices[0], sizeof(VERTEX) * vertices.size());
devcon->Unmap(m_pVBuffer, NULL);

Dann mache ich in der "Render" -Methode meines Netzes Folgendes:

UINT stride = sizeof(VERTEX);
UINT offset = 0;
devcon->IASetVertexBuffers(0, 1, &m_pVBuffer, &stride, &offset);
devcon->IASetIndexBuffer(m_pIBuffer, DXGI_FORMAT_R32_UINT, 0);
devcon->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
devcon->DrawIndexed(m_num_indices, 0, 0);

Um es zu wiederholen: Werden die Daten auf die GPU hochgeladen, wenn ich den Vertex-Puffer zuordne, speichere und die Zuordnung aufhebe, oder werden sie bei jedem Aufruf von IASetVertexBuffers in jedem Frame hochgeladen?

x10
quelle

Antworten:

7

Dies ist eine schwierige Frage, da Sie nicht die vollständige Kontrolle darüber haben, ob ein Vertex-Puffer im VRAM oder im Haupt-RAM gespeichert ist. Der Treiber trifft diese Entscheidung für Sie basierend auf den Nutzungs- und CPU-Zugriffsflags, die beim Erstellen des Vertex-Puffers angegeben wurden.

Im Allgemeinen werden Puffer mit Standard- und unveränderlicher Verwendung im VRAM gespeichert. diejenigen mit Staging-Nutzung werden im Hauptspeicher gespeichert. und diejenigen mit dynamischer Nutzung könnten sich an beiden Orten befinden. Wenn jedoch nicht genügend VRAM verfügbar ist, speichert der Treiber Ressourcen als Ersatz im Hauptspeicher.

Wenn ein Puffer im VRAM landet, werden Daten über den Systembus (der die CPU und die GPU verbindet) übertragen, wenn die CPU den Puffer aktualisiert (dh wenn Sie ein Map / Unmap-Paar erstellen). Wenn es sich im Hauptspeicher befindet, liest die GPU die Daten jedes Mal über den Systembus, wenn Sie diesen Puffer zum Rendern verwenden.

Normalerweise verwenden Sie für statische Netze eine unveränderliche Verwendung, und der Puffer wird im VRAM gespeichert, sodass nach der Ersteinrichtung keine zusätzliche Systembusübertragung erfolgt. Für einen dynamischen Scheitelpunktpuffer (für Partikel oder ähnliches) würden Sie die dynamische Verwendung verwenden, und die Daten würden einmal pro Frame über den Bus übertragen. Wenn sie sich im VRAM befinden, wird der Bus von der CPU zum Schreiben verwendet, und wenn Es befindet sich im Hauptspeicher, der Bus wird von der GPU zum Lesen verwendet.

Nathan Reed
quelle
Die von mir durchgeführten Tests bestätigen diese Antwort. Wenn ich viele Objekte rendere, kommt es in den ersten Sekunden zu einer anfänglichen Verlangsamung, aber dann steigt die Framerate. Da ich in jedem Frame das Gleiche mache, muss dies daran liegen, dass zumindest ein Teil der Puffer im VRAM "zwischengespeichert" ist. Die Antwort lautet also "Es wird nur einmal hochgeladen. Wahrscheinlich. Sie sollten sich jedoch nicht darauf verlassen."
10.
0

Die Antwort hängt davon ab, wie sich eine bestimmte Generation hochoptimierter Hardwaretreiber anfühlt, dh, es gibt keine allgemeine Antwort für Sie.

Fügen Sie dieser Komplikation die Tatsache hinzu, dass Treiber 1-N-Frames hinter dem rendern, was Sie ihnen derzeit zum Rendern sagen, da 3D-Karten sowohl hoch serialisiert als auch parallel und zwischengespeichert sind und asynchron arbeiten, um die Dinge zu erledigen.

Wenn Sie gerade erst lernen, sind die Sequenzpunkte für die Vorbereitung eines Renderings die wichtigsten Informationen: Beschreiben Sie die Daten, kopieren Sie die Daten, teilen Sie dem Treiber mit, welche Daten verwendet werden sollen, und starten Sie das Rendering. Und nicht was passiert, wenn das tatsächlich ein sehr tiefes Kaninchenloch ist.

Patrick Hughes
quelle
0

Mein Verständnis, meist basierend auf Lesen dieser ist , dass der Fahrer in der Regel nicht alle Ressourcen über Videospeicher senden, bis die Ressource in einem Zeichenaufruf verwendet wird.

Das würde bedeuten, dass der Konstruktor die GPU-Hardware wahrscheinlich überhaupt nicht berührt, und die Rendermethode auch. Selbst der Aufruf von DrawIndexed () schafft es wahrscheinlich nicht sofort zur Hardware, da es CPU-effizienter ist, große Listen von GPU-Befehlen zu puffern.

Der Treiber kann auch Daten aus dem GPU-Speicher entladen, wenn dieser leer ist (vorausgesetzt, er hat eine Kopie davon im Hauptspeicher). In extremen Fällen kann dies mehr als einmal pro Frame passieren.

Natürlich ist all dies vom Treiber vor dem Programmierer verborgen, sodass Sie sich nicht darauf verlassen können, dass es so ist - die Treiber ändern sich ständig.

Adam
quelle
Es ist sehr wahrscheinlich, dass es nicht einmal zu einem Draw-Aufruf kommt - der Draw-Aufruf wird nur an einen vom Treiber verwalteten Befehlspuffer gesendet, und dieser wird in der eigenen Sweet Time des Fahrers gelöscht, die danach beliebig lange dauern kann.
Maximus Minimus