Was ist ein guter Ansatz für den Umgang mit Uniformen in modernen OpenGL?


8

Ich erstelle einen Renderer mit modernem OpenGL (3.1 und höher) und versuche jetzt, eine effiziente, aber flexible Methode für den Umgang mit Uniformen zu erstellen. Ich habe mich über einheitliche Pufferobjekte informiert und darüber, wie diese häufig verwendet werden (letzteres hat mir leider nicht so viele Ergebnisse gebracht, wie ich gehofft hatte).

Um OpenGL-API-Aufrufe zu reduzieren und Daten im zusammenhängenden Speicher zu speichern, erwäge ich, für jede Datenstruktur, die auf die GPU hochgeladen werden soll, mehrere große Puffer zu erstellen. Jeder Puffer hat eine maximale Größe von 16 KB (soweit ich weiß, ist so viel für einen UBO garantiert verfügbar). Wenn ein Objekt Uniformen auf die GPU hochladen möchte, ruft es den ersten Puffer des hochzuladenden Typs ab, der noch nicht voll ist, und erhält den nächsten verfügbaren Index in diesem Puffer. Wenn das Objekt gezeichnet wird, bindet es das UBO (falls noch nicht gebunden) und lädt den Elementindex des UBO hoch.

Dies führt zu ungefähr so:

layout(std140) uniform ModelData { 
    mat4 model_matrix[kNumInstancesPerModelUbo]; 
}
uniform int u_ModelDataIndex;

layout(std140) uniform SkeletonData { 
    mat4 bone_transforms[kNumInstancesPerSkeletonUbo][kMaxBones]; 
}
uniform int u_SkeletonDataIndex;

Ich denke jedoch auch über Folgendes nach:

layout(std140) uniform MeshData {
    mat4 model_matrix[kNumInstancesPerMeshUbo];
    mat4 bone_transforms[kNumInstancesPerMeshUbo][kMaxBones];
}
uniform int u_MeshDataIndex;

In mancher Hinsicht fühlt sich dies viel sauberer an, da ein einziger Index erforderlich ist, um auf alle Daten zuzugreifen, die sich auf das hochzuladende Netz beziehen. Auf der anderen Seite kann dies außer Kontrolle geraten (Puffergröße größer als 16 KB, Verarbeitung irrelevanter Daten (z. B. ein Netz ohne Skelett) oder sogar Synchronisierungsprobleme, da Sie beim Hochladen der Modellmatrizen keinen Zugriff auf die Knochen haben). und ich bin mir auch nicht sicher, wie sich dies auf das Speicherlayout auf der GPU auswirken würde.

Ehrlich gesagt fühlt es sich so an, als ob ich hier festsitze und ich kann kein gutes konkretes Beispiel dafür finden, wie Sie schnell und flexibel mit UBOs umgehen würden.

Haben Sie Ratschläge oder Ressourcen für mich, die mir hier helfen könnten?

Antworten:


2

Die Unterzuordnung aus einem größeren Puffer ist mit Einschränkungen absolut der richtige Weg. Ich komme eher von einer DirectX / Vulkan-Seite, aber dies sollte auch für OpenGL gelten (ich habe hier in dieser Antwort einfach keine direkten API-Aufrufe). Folgende Punkte sind zu beachten:

  • Müssen Sie in den größeren Puffer indizieren, oder können Sie die Ressource jedes Mal an den Offset binden?
  • Haben Sie sich um alle Ausrichtungsbeschränkungen für Ihre zusammengepackten Uniformen gekümmert (256-Byte-Ausrichtung ist üblich)?

Neuere Grafik-APIs haben einen "dynamischen Versatz", den Sie mit dem Befehl draw angeben können. Dies ist eine ziemlich schnelle Möglichkeit, indirekt auf einen Teilbereich eines Puffers zuzugreifen. Unter der Annahme, dass Sie Daten dreifach puffern, die veränderlich sind, sollte der Treiber jedoch kaum oder gar keine Konflikte um die Bindung der Daten haben (nur ein fester Overhead).

Zusammenfassend lässt sich sagen, dass das Zuweisen größerer Speicherbereiche / Puffer und das Untervermieten dieser Bereiche als bewährte Methode angesehen wird. Dies gilt auch für Objekte mit unterschiedlichen Shadern (sofern Ihr Allokator damit umgehen kann).


0

Fügen Sie Ihrer Anwendung eine Benchmarking-Phase für beide Lösungen hinzu und wählen Sie dann zur Laufzeit die Gewinnerlösung aus. Dies ist einfach, tragbar und zukunftssicher. Ich meine, du hast einen Test dafür, oder? ;-);

Ich weiß, dass dies eine ziemlich allgemeine Antwort auf "Best Practice" für hohe Leistung ist, aber wenn Sie daran denken, gibt es Tausende von möglichen Zielkonfigurationen und viele Anbieter, die berücksichtigt werden müssen. Wenn Sie dieses kleine Extra benötigen, zahlen Sie Ihrem Händler einen für Ihre Anwendung optimierten Treiber.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.