Scheitelpunktpuffer - verschachtelt oder getrennt? [geschlossen]

7

Interleaved - Alle Scheitelpunktdaten (Position, Normal, Texkoord ...) werden in 1 Scheitelpunktpuffer getrennt gespeichert. Jedes Scheitelpunktattribut wird in einem separaten Scheitelpunktpuffer gespeichert (1 für Positionen, 1 für Normalen ...).

Ich weiß, dass diese Frage oft gestellt wurde und ich weiß auch, dass es (leider) keine richtige Antwort gibt. Aber ich möchte versuchen, die wichtigsten Vor- und Nachteile von beiden aufzulisten. Oder vielleicht haben Sie einige allgemeine Faustregeln, wann Sie sie verwenden sollen.

  1. Vorteile von Interleaved:

    • schneller? (Alle Daten für 1 Scheitelpunkt werden auf einmal abgerufen? etw über den Cache, der besser funktioniert)?
    • weniger API-Aufrufe (zum Erstellen und Festlegen von Puffern, aber das ist wahrscheinlich ein sehr kleiner Unterschied)
  2. Vorteile der getrennten:

    • Wenn verschiedene Shader unterschiedliche Scheitelpunktattribute benötigen (z. B. ein Shader benötigt nur Position und ein anderer Position, Normal und Texcoord), kann jedem Shader nur die Daten bereitgestellt werden, die er benötigt, und es gibt keine Datenverdoppelung
    • Wenn nur die Position von Scheitelpunkten aktualisiert wird, müssen die anderen Attributdaten (z. B. Normalen und Texkoordinaten) nicht erneut gesendet werden.

Wenn Sie weitere Unterschiede feststellen, schreiben Sie bitte. Von oben sieht es im Allgemeinen wie ein Kampf zwischen Speicher und Leistungsoptimierung aus. Aber vielleicht irre ich mich? Vielleicht ist man in den meisten Fällen besser / schlechter?

Bearbeiten: Noch ein Problem - mit verschachtelten Puffern könnte ich unnötige Daten an die GPU senden, und die Datenbandbreite ist ein großer Engpass bei den heutigen Karten. Sollte ich mir darüber Sorgen machen?

NPS
quelle
Ich lese jetzt. Cache-Zeilen sind mindestens 32 Byte lang und verschachtelt. Dies gilt sowohl für Lesevorgänge als auch für Uploads.
MickLH
Wenn Sie sich so sicher sind, müssen Sie einige sehr starke Argumente für diesen Ansatz haben - können Sie uns dies mitteilen?
NPS
Aktualisiert. Gute Nacht xo
MickLH
Mögliches Duplikat von Interleaved-Formaten für Netzverwirrung
Sean Middleditch
1
@ SeanMiddleditch Ich glaube, der Thread, mit dem Sie verlinkt haben (sowohl Frage als auch Antwort), stellt ein anderes Problem dar als meiner. Ich frage nach Unterschieden zwischen verschachtelten und getrennten Ansätzen. Steve fragte, ob er etwas Speicherplatz sparen könne, indem er nicht die normalen Daten für jeden Scheitelpunkt dupliziere.
NPS

Antworten:

8

Ich habe kürzlich beide Versionen in OpenGL (4.3) implementiert und unter Verwendung der (Crytek) Sponza-Szene als Test-Rendering-Szene Shader verwendet, die entweder nur eine Teilmenge oder die vollständige Menge aller definierten Scheitelpunktattribute verwendeten.

Es gab einen Unterschied zu Ihrem Setup: Im nicht verschachtelten Fall befanden sich die Attribute auch im selben Scheitelpunktpuffer. Mit OpenGL ist dies ganz einfach. Sie können Byte-Offsets einfach mit glVertexAttribPointer (...) mit dem letzten Parameter an ein bestimmtes Attribut binden. Eine entsprechende Option gibt es wahrscheinlich für DirectX.

Insbesondere beim Rendern einer Schattenkarte, für die nur Scheitelpunktpositionen erforderlich sind (in meinem Fall), wurden bei Verwendung nicht verschachtelter Puffer ~ 210 bis ~ 220 FPS verwendet, was einem Unterschied von etwa 0,2 ms entspricht. Mit anderen Worten, Sie könnten mit dieser Beschleunigung nicht einmal von 60 FPS auf 61 FPS wechseln.

Beim Rendern der Szene aus der Perspektive des Schattenlichts, jedoch unter Verwendung aller Attribute (in meinem Fall eines verzögerten Durchlaufs der Schattengeometrie) hat sich die Leistung zwischen den beiden Versionen überhaupt nicht geändert.

Ich kann nur raten, aber ich denke, der Grund, warum sich das Rendern der Schattenkarte verbessert hat, ist, dass GPUs (wie CPUs) wahrscheinlich nicht nur einzelne Bytes, Wörter oder Wörter mit einem Speicherzugriff aus dem Speicher ziehen, sondern stattdessen mehr Bytes (auf den meisten modernen CPUs) Dies wären 64 Bytes pro Zugriff) und würde es irgendwo zwischenspeichern. Wenn Daten verschachtelt sind, zieht die GPU möglicherweise einen Satz Position / Normal / Texcoord / was auch immer pro Speicherzugriff auf einmal, von denen alle außer der Position Speicherbandbreite verschwenden, wenn Sie nur Position verwenden.

Eine Einschränkung: In meinem Testfall war die Speicherbandbreite nicht gebunden. Wenn also der Speicherdurchsatz Ihr Engpass ist, werden die Messungen möglicherweise anders ausgeführt.

Insgesamt würde ich vorschlagen, dass Sie es so belassen, wie Sie es jetzt haben, und es später ändern, sobald Sie feststellen, dass eine Optimierung erforderlich ist. Das Ändern dauert nicht lange. Sie müssen lediglich ändern, wie die Daten an den GPU-Speicher übergeben werden, und ändern, wie Attribute mithilfe Ihrer Grafik-API gebunden werden.

TravisG
quelle
+1, insbesondere für die Angabe einiger harter Daten. Ich gehe davon aus, dass ein möglicher Grund, warum Sie bei dem nicht verschachtelten Fall nicht so viel Perfektion gesehen haben, darin besteht, dass zusätzliche Statusänderungen erforderlich sind, die der verschachtelte Fall möglicherweise vermeiden kann. Es ist alles ein Balanceakt ...
Maximus Minimus
+1 für die Betrachtung der Schattenzuordnung - das ist ein guter Test für diese Frage, da Schatten häufig vertexgebunden sind und nur ein oder zwei der vielen Vertexattribute benötigen. Die Vorteile variieren je nach Szene und Hardware - eine dichtere Geometrie würde zu einer stärkeren Beschleunigung führen, und Plattformen mit weniger Speicher-BW würden dies ebenfalls tun. Diese Optimierung war auf der PS3 sehr nützlich - wahrscheinlich nicht so sehr auf modernen High-End-PCs oder den neuen Konsolen, aber wahrscheinlich immer noch nützlich auf mobilen Plattformen.
Nathan Reed
0

verschachtelt : Wenn es einfacher ist, Speicher und Code zu verstehen und zu verwalten. Anstatt 4 Puffer zu haben, haben Sie nur einen und das wars.

trennen : Es gibt keinen praktischen Vorteil beim Teilen von Ressourcen. Das Verwalten von 3D-Inhalten ist schwierig, und wenn die separaten Streams gemeinsam genutzt werden, entsteht nur ein Albtraum. Sie könnten dadurch etwas Gedächtnis gewinnen, aber es lohnt sich nicht.

Bei der Leistung kann es einen Unterschied geben, zumindest bei einigen Android-GPUs weiß ich, dass Sie unterschiedliche Ergebnisse erzielen werden.

Raxvan
quelle
Nur schwer für einen Menschen
MickLH
Sie sagten "könnte etwas Speicher gewinnen" - wenn ich sehr große Modelle habe (idk, 100k Eckpunkte? Mehr?) Und 3 verschiedene Shader-Typen sagen, die dieses Modell rendern, ist das nicht so viel Speicher?
NPS
1
@NPS Die API bietet Problemumgehungen, mit denen Sie Scheitelpunkte mit Positionen / Normalen usw. verschachteln und in den Shadern genau das verwenden können, was Sie möchten.
Raxvan
@Raxvan Ok, welcher ist dann besser - 2 Vertex-Puffer (1 mit [position, normal]und der andere mit [position, normal, texcoord]) und jeder für seinen jeweiligen Shader oder nur 1 Vertex-Puffer (letzterer) und für beide Shader?
NPS
@NPS der letzte für beide. Wenn der Shader beispielsweise die Normalen nicht möchte, können Sie diesen Puffer problemlos verwenden. In einem Setup-Schritt geben Sie die Streams an und können die Normalen einfach ignorieren.
Raxvan