Hilft es, Variablen außerhalb Ihres Hauptfunktionsbereichs in GLSL zu deklarieren? Werden diese Variablen tatsächlich wiederverwendet und sind sie effizienter?
Hier ist der fragliche Code:
varying vec2 vposition;
uniform float seed;
uniform float top;
uniform float bottom;
uniform float phi;
uniform float theta;
uniform float scaledPI;
uniform float yn;
uniform float ym;
uniform float rx;
uniform float ry;
uniform float radius;
const float PI = 3.141592653589793238462643383;
float left;
float right;
float mscaled;
float xn;
float xm;
void main() {
float t = vposition.y * yn + ym;
if(t <= 0.0 || t >= PI){
left = phi - PI;
right = phi + PI;
}else{
mscaled = scaledPI / (1 - abs(Math.cos(theta)));
mscaled = mscaled < PI ? mscaled : PI;
left = phi - mscaled;
right = phi + mscaled;
}
xn = (left - right) / ((-rx / 2.0) - (rx / 2.0));
xm = left - ((-rx/2.0) * xn);
float p = vposition.x * xn + xm;
vec3 coords = vec3( sin(p) * sin(t), cos(t), cos(p) * sin(t) );
float nv = surface( vec4( coords, seed ) );
gl_FragColor = vec4( vec3( nv, nv, nv ), 1.0 );
}
main()
Funktion? Sind Ihre Werte tatsächlich globale Variablen (Uniformen oder Attribute im GLSL-Sprachgebrauch) oder konstante Werte?Antworten:
Ich glaube, ich verstehe, was Sie fragen wollen. Ich gehe davon aus, dass Ihr Hauptanliegen die uneinheitlichen Variablen sind, die außerhalb von definiert sind
main()
:Werfen wir einen Blick darauf, wie GPU und GLSL funktionieren. Die GPU verfügt nicht über einen Stapel oder einen Anrufaktivierungsdatensatz. Es gibt keine Möglichkeit, den Bereich oder lokale Variablen in GLSL zu simulieren, wie dies ein C-Compiler auf den meisten CPUs tun kann. Alles, was existiert, sind die Register, die entweder einheitliche Register, Shader-Stage-Eingänge, Ausgänge und die lokale Registerdatei sind, die für diesen Shader-Aufruf eindeutig ist.
Mit anderen Worten, da es keine Funktion, keinen Stapel oder keinen Heap gibt, leben alle irgendwo deklarierten Variablen in einem Register. Es spielt keine Rolle, ob sie in einem bestimmten Bereich in GLSL lokal oder in der gesamten Datei global sind. Sie sind nur Register.
Der Registerzuweiser ist jedoch nicht Teil des GLSL-Standards. Verschiedene OpenGL-Implementierungen können unterschiedliche Qualitätsstufen aufweisen, wenn es darum geht, GLSL-Code auf hoher Ebene in Maschinencode auf niedriger Ebene zu konvertieren, den die GPU versteht. Einer der komplizierteren Teile eines Compilers (GLSL oder anders) ist Registerzuordnung . Dies ist der Teil des Compilers, der bestimmt, welche Register eine bestimmte Variable belegt. C hat es etwas schwieriger, da es normalerweise mit sehr kleinen Registerdateien (insbesondere unter x86) und mit Registerverschüttungen (Verschieben von Variablen in den Stapel) und Aliasing (Speichern von Variablen zurück in den RAM vor dem Aufrufen von Funktionen) und zu tun hat ungerade Befehle, die verlangen, dass sich die Ausgabe in einem bestimmten Register befindet (x86)
idiv
zum Beispiel). GPUs haben eine große Registerdatei, da sie keinen Stapel oder Heap haben, so dass der Allokator einfacher sein kann.Die Registerdatei ist jedoch nicht unendlich. Wenn Sie mehr Variablen als Register haben, die von Ihrer Hardware unterstützt werden, muss der Compiler versuchen, alle Ihre Variablen in die Register einzupassen. Dies erfordert normalerweise eine Form der Überprüfung des Lebendigkeitsbereichs . Das heißt, wenn Sie eine Variable
xn
für eine Berechnung verwenden und sie dann nie wieder verwenden, kann der Compiler dies feststellen und dann wissen, dass das von belegte belegte Registerxn
später von einer anderen Variablen verwendet werden kann, wodurch mehr Variablen zugelassen werden, als es Register gibt (so lange) da nicht zu viele Live-Variablen gleichzeitig vorhanden sind).Der Compiler tut dies jedoch möglicherweise nicht. Es hat nicht. Oder es könnte es nur in einigen Fällen tun. Bereiche mit einfacheren Compilern sind ein viel einfacher zu lösendes Problem. Alle den lokalen Funktionsvariablen zugewiesenen Register können nach dem Beenden dieser Funktion wiederverwendet werden, da sie wissen, dass die Variablen tot sind. Globale Variablen haben keine so einfache Garantie. Daher optimieren einige weniger fähige Compiler möglicherweise auch ihre Lebensdauer nicht, und die globalen Variablen verschlingen immer ein Register. Dies macht nichts langsamer , kann jedoch bei einigen Treibern die Größe des Shaders einschränken, den Sie schreiben können.
Im Allgemeinen würde ich dringend empfehlen, alle Variablen lokal zu halten. Halten Sie die Definition so nah wie möglich an der Verwendung der Variablen. Dies gilt für alle Programmiersprachen, nicht nur für GLSL. Ich würde auch empfehlen, jede "Variable" const in jedem Fall zu machen, den Sie können. Dies kann wiederum ein Hinweis für bestimmte weniger leistungsfähige Compiler sein, dass bestimmte Optimierungen möglich sind, und vor allem macht es Ihren Code selbstdokumentierender und einfacher zu warten.
Und natürlich ist hier Ihr obligatorischer Ratschlag "Nur Profil, um zu testen und sicher herauszufinden". Schreiben Sie Ihren Shader mit und ohne Globals und profilieren Sie ihn. Alle Online-Leistungsratschläge sollten misstrauisch sein und entweder als mutmaßlich oder veraltet angesehen werden.
quelle