Welche Ursachen eine Verzweigung in GLSL verursachen, hängt vom GPU-Modell und der OpenGL-Treiberversion ab.
Die meisten GPUs haben anscheinend die Form einer Operation "Wählen Sie einen von zwei Werten", die keine Verzweigungskosten verursacht:
n = (a==b) ? x : y;
und manchmal sogar Dinge wie:
if(a==b) {
n = x;
m = y;
} else {
n = y;
m = x;
}
wird ohne Verzweigungsstrafe auf wenige Auswahlwertoperationen reduziert.
Einige GPU / Treiber haben (hatten?) Eine gewisse Strafe für den Vergleichsoperator zwischen zwei Werten, aber eine schnellere Operation beim Vergleich gegen Null.
Wo es schneller gehen könnte:
gl_FragColor.xyz = ((tmp1 - tmp2) != vec3(0.0)) ? E : tmp1;
Anstatt (tmp1 != tmp2)
direkt zu vergleichen , ist dies jedoch sehr abhängig von der GPU und dem Treiber. Daher empfehle ich, die Vergleichsoperation zu verwenden und den Optimierungsjob dem OpenGL-Treiber zu überlassen, da ein anderer Treiber möglicherweise ein Problem mit der längeren Form hat und seien Sie schneller mit der einfacheren, lesbareren Weise.
"Branches" sind auch nicht immer schlecht. Zum Beispiel auf der SGX530-GPU, die in OpenPandora verwendet wird, dieser scale2x-Shader (30 ms):
lowp vec3 E = texture2D(s_texture0, v_texCoord[0]).xyz;
lowp vec3 D = texture2D(s_texture0, v_texCoord[1]).xyz;
lowp vec3 F = texture2D(s_texture0, v_texCoord[2]).xyz;
lowp vec3 H = texture2D(s_texture0, v_texCoord[3]).xyz;
lowp vec3 B = texture2D(s_texture0, v_texCoord[4]).xyz;
if ((D - F) * (H - B) == vec3(0.0)) {
gl_FragColor.xyz = E;
} else {
lowp vec2 p = fract(pos);
lowp vec3 tmp1 = p.x < 0.5 ? D : F;
lowp vec3 tmp2 = p.y < 0.5 ? H : B;
gl_FragColor.xyz = ((tmp1 - tmp2) != vec3(0.0)) ? E : tmp1;
}
Endete dramatisch schneller als dieser äquivalente Shader (80ms):
lowp vec3 E = texture2D(s_texture0, v_texCoord[0]).xyz;
lowp vec3 D = texture2D(s_texture0, v_texCoord[1]).xyz;
lowp vec3 F = texture2D(s_texture0, v_texCoord[2]).xyz;
lowp vec3 H = texture2D(s_texture0, v_texCoord[3]).xyz;
lowp vec3 B = texture2D(s_texture0, v_texCoord[4]).xyz;
lowp vec2 p = fract(pos);
lowp vec3 tmp1 = p.x < 0.5 ? D : F;
lowp vec3 tmp2 = p.y < 0.5 ? H : B;
lowp vec3 tmp3 = D == F || H == B ? E : tmp1;
gl_FragColor.xyz = tmp1 == tmp2 ? tmp3 : E;
Sie wissen nie im Voraus, wie ein bestimmter GLSL-Compiler oder eine bestimmte GPU funktionieren wird, bis Sie einen Benchmark durchführen.
Um den To-Point hinzuzufügen (obwohl ich keine aktuellen Timing-Nummern und Shader-Codes habe, die Ihnen für diesen Teil zur Verfügung stehen), verwende ich derzeit als reguläre Testhardware:
- Intel HD Graphics 3000
- Intel HD 405-Grafik
- nVidia GTX 560M
- nVidia GTX 960
- AMD Radeon R7 260X
- nVidia GTX 1050
Als breite Palette von verschiedenen, gängigen GPU-Modellen zum Testen.
Testen jeweils mit Windows-, Linux-proprietären und Linux-Open-Source-OpenGL- und OpenCL-Treibern.
Und jedes Mal, wenn ich versuche, GLSL-Shader (wie im obigen SGX530-Beispiel) oder OpenCL-Vorgänge für eine bestimmte GPU / Treiber-Kombination zu optimieren , wird die Leistung auf mehr als einer der anderen GPUs / Treiber gleichermaßen beeinträchtigt.
Abgesehen von einer deutlichen Reduzierung der mathematischen Komplexität auf hohem Niveau (z. B. Umwandlung von 5 identischen Divisionen in ein einzelnes Reziprok und 5 Multiplikationen) und einer Reduzierung der Textur-Lookups / Bandbreite ist dies höchstwahrscheinlich eine Zeitverschwendung.
Jede GPU unterscheidet sich zu stark von den anderen.
Wenn Sie speziell an (einer) Spielekonsole (n) mit einer bestimmten GPU arbeiten würden, wäre dies eine andere Geschichte.
Der andere (für kleine Spieleentwickler weniger wichtige, aber immer noch bemerkenswerte) Aspekt ist, dass die GPU-Treiber eines Tages möglicherweise stillschweigend Ihre Shader ersetzen ( wenn Ihr Spiel populär genug wird ), und zwar durch benutzerdefinierte, für diese bestimmte GPU optimierte Shader . Das alles für Sie zu tun.
Sie tun dies für beliebte Spiele, die häufig als Benchmarks verwendet werden.
Wenn Sie Ihren Spielern Zugriff auf die Shader gewähren, damit sie sie leicht selbst bearbeiten können, können einige von ihnen zu ihrem eigenen Vorteil einige zusätzliche FPS einsparen.
Zum Beispiel gibt es fan-made Shader & Textur-Packs für Oblivion, um die Framerate auf sonst kaum spielbarer Hardware dramatisch zu erhöhen.
Und wenn Ihr Shader erst einmal komplex genug ist, Ihr Spiel fast abgeschlossen ist und Sie mit dem Testen auf einer anderen Hardware beginnen, sind Sie beschäftigt genug, um Ihre Shader so zu reparieren, dass sie auf einer Vielzahl von GPUs funktionieren, da dies auf verschiedene Fehler zurückzuführen ist, die Sie nicht kennen Zeit haben, sie zu diesem Grad zu optimieren.