Derzeit gibt es 4 Möglichkeiten, dies zu tun: Standard-1D-Texturen, Puffertexturen, einheitliche Puffer und Shader-Speicherpuffer.
1D Texturen
Mit dieser Methode glTex(Sub)Image1D
füllen Sie eine 1D-Textur mit Ihren Daten. Da Ihre Daten nur ein Array von Floats sind, sollte Ihr Bildformat sein GL_R32F
. Sie können dann mit einem einfachen texelFetch
Aufruf im Shader darauf zugreifen . texelFetch
Nimmt Texelkoordinaten (daher der Name) und schaltet alle Filter aus. Sie erhalten also genau ein Texel.
Hinweis: texelFetch
ist 3.0+. Wenn Sie frühere GL-Versionen verwenden möchten, müssen Sie die Größe an den Shader übergeben und die Texturkoordinate manuell normalisieren.
Die Hauptvorteile sind hier Kompatibilität und Kompaktheit. Dies funktioniert auf GL 2.1-Hardware (unter Verwendung der Notation). Und Sie nicht haben zu verwenden GL_R32F
Formate; Sie könnten GL_R16F
halbe Schwimmer verwenden. Oder GL_R8
wenn Ihre Daten für ein normalisiertes Byte angemessen sind. Größe kann viel für die Gesamtleistung bedeuten.
Der Hauptnachteil ist die Größenbeschränkung. Sie können nur eine 1D-Textur mit der maximalen Texturgröße verwenden. Auf Hardware der GL 3.x-Klasse sind dies rund 8.192, aber garantiert nicht weniger als 4.096.
Einheitliche Pufferobjekte
Dies funktioniert so, dass Sie in Ihrem Shader einen einheitlichen Block deklarieren:
layout(std140) uniform MyBlock
{
float myDataArray[size];
};
Sie greifen dann wie ein Array im Shader auf diese Daten zu.
Zurück im C / C ++ / etc-Code erstellen Sie ein Pufferobjekt und füllen es mit Gleitkommadaten. Anschließend können Sie dieses Pufferobjekt dem MyBlock
einheitlichen Block zuordnen. Weitere Details finden Sie hier.
Die Hauptvorteile dieser Technik sind Geschwindigkeit und Semantik. Die Geschwindigkeit hängt davon ab, wie Implementierungen einheitliche Puffer im Vergleich zu Texturen behandeln. Texturabrufe sind globale Speicherzugriffe. Einheitliche Pufferzugriffe sind in der Regel nicht; Die einheitlichen Pufferdaten werden normalerweise in den Shader geladen, wenn der Shader bei seiner Verwendung beim Rendern initialisiert wird. Von dort ist es ein lokaler Zugang, der viel schneller ist.
Semantisch ist dies besser, da es sich nicht nur um ein flaches Array handelt. Für Ihre spezifischen Bedürfnisse float[]
spielt es keine Rolle , ob Sie nur eine benötigen . Wenn Sie jedoch eine komplexere Datenstruktur haben, kann die Semantik wichtig sein. Betrachten Sie beispielsweise eine Reihe von Lichtern. Lichter haben eine Position und eine Farbe. Wenn Sie eine Textur verwenden, sieht Ihr Code zum Abrufen der Position und Farbe für ein bestimmtes Licht folgendermaßen aus:
vec4 position = texelFetch(myDataArray, 2*index);
vec4 color = texelFetch(myDataArray, 2*index + 1);
Mit einheitlichen Puffern sieht es genauso aus wie jeder andere einheitliche Zugriff. Sie haben Mitglieder benannt, die aufgerufen werden können position
und color
. Alle semantischen Informationen sind also da; Es ist einfacher zu verstehen, was los ist.
Auch hierfür gibt es Größenbeschränkungen. OpenGL erfordert, dass Implementierungen mindestens 16.384 Bytes für die maximale Größe einheitlicher Blöcke bereitstellen. Das heißt, für Float-Arrays erhalten Sie nur 4.096 Elemente. Beachten Sie erneut, dass dies das Minimum ist, das für Implementierungen erforderlich ist. Einige Hardware bietet viel größere Puffer. AMD bietet beispielsweise 65.536 Geräte für die Hardware der DX10-Klasse an.
Puffertexturen
Dies ist eine Art "Super 1D Textur". Sie ermöglichen Ihnen effektiv den Zugriff auf ein Pufferobjekt von einer Textureinheit aus . Obwohl sie eindimensional sind, handelt es sich nicht um 1D-Texturen.
Sie können sie nur ab GL 3.0 oder höher verwenden. Und Sie können nur über die texelFetch
Funktion darauf zugreifen .
Der Hauptvorteil ist hier die Größe. Puffertexturen können im Allgemeinen ziemlich gigantisch sein. Während die Spezifikation im Allgemeinen konservativ ist und mindestens 65.536 Bytes für Puffertexturen vorschreibt, erlauben die meisten GL-Implementierungen, dass sie in der Größe der Mega- Bytes liegen. In der Tat wird die maximale Größe normalerweise durch den verfügbaren GPU-Speicher und nicht durch Hardwarebeschränkungen begrenzt.
Außerdem werden Puffertexturen in Pufferobjekten gespeichert, nicht in undurchsichtigeren Texturobjekten wie 1D-Texturen. Dies bedeutet, dass Sie einige Pufferobjekt-Streaming-Techniken verwenden können , um sie zu aktualisieren.
Der Hauptnachteil ist hier die Leistung, genau wie bei 1D-Texturen. Puffertexturen sind wahrscheinlich nicht langsamer als 1D-Texturen, aber sie sind auch nicht so schnell wie UBOs. Wenn Sie nur einen Schwimmer von ihnen ziehen, sollte dies kein Problem sein. Wenn Sie jedoch viele Daten daraus abrufen, sollten Sie stattdessen ein UBO verwenden.
Shader-Speicherpufferobjekte
OpenGL 4.3 bietet eine andere Möglichkeit, dies zu handhaben: Shader-Speicherpuffer . Sie ähneln einheitlichen Puffern. Sie geben sie mit einer Syntax an, die fast identisch mit der von einheitlichen Blöcken ist. Der Hauptunterschied besteht darin, dass Sie ihnen schreiben können. Natürlich ist das für Ihre Bedürfnisse nicht nützlich, aber es gibt andere Unterschiede.
Shader-Speicherpuffer sind konzeptionell eine alternative Form der Puffertextur. Daher sind die Größenbeschränkungen für Shader-Speicherpuffer viel größer als für einheitliche Puffer. Das OpenGL-Minimum für die maximale UBO-Größe beträgt 16 KB. Das OpenGL-Minimum für die maximale SSBO-Größe beträgt 16 MB . Wenn Sie also über die Hardware verfügen, sind diese eine interessante Alternative zu UBOs.
Stellen Sie nur sicher, dass Sie sie als deklarieren readonly
, da Sie ihnen nicht schreiben.
Der potenzielle Nachteil ist hier wiederum die Leistung im Vergleich zu UBOs. SSBOs funktionieren wie eine Bildlade- / Speicheroperation über Puffertexturen. Im Grunde ist es (sehr schöner) syntaktischer Zucker um einen imageBuffer
Bildtyp. Daher werden Lesevorgänge von diesen wahrscheinlich mit der Geschwindigkeit von Lesevorgängen von a ausgeführt readonly imageBuffer
.
Ob das Lesen über das Laden / Speichern von Bildern durch Pufferbilder schneller oder langsamer als Puffertexturen ist, ist derzeit unklar.
Ein weiteres potenzielles Problem besteht darin, dass Sie die Regeln für den nicht synchronen Speicherzugriff einhalten müssen . Diese sind komplex und können Sie sehr leicht stolpern.