Es ist beliebt, prozeduralen Inhalt innerhalb der GPU zu rendern, z. B. in der Demoszene (Zeichnen eines einzelnen Quadrats, um den Bildschirm auszufüllen, und Ermöglichen, dass die GPU die Pixel berechnet).
Ray Marschieren ist beliebt:
Dies bedeutet, dass die GPU eine unbekannte Anzahl von Schleifeniterationen pro Pixel ausführt (obwohl Sie eine Obergrenze wie haben können maxIterations
).
Wie wirkt sich eine Schleife mit variabler Länge auf die Shader-Leistung aus?
Stellen Sie sich den einfachen Pseudocode vor, der mit dem Marsch marschiert:
t = 0.f;
while(t < maxDist) {
p = rayStart + rayDir * t;
d = DistanceFunc(p);
t += d;
if(d < epsilon) {
... emit p
return;
}
}
Wie sind die verschiedenen gängigen GPU-Familien (Nvidia, ATI, PowerVR, Mali, Intel usw.) betroffen? Vertex-Shader, aber vor allem Fragment-Shader?
Wie kann es optimiert werden?
opengl
glsl
opengl-es2
raytracing
Wille
quelle
quelle
Antworten:
Auf der GDC 2012 gab es einen schönen Vortrag über GPU-Distanzfeld-Marschieren (und andere Themen): http://directtovideo.wordpress.com/2012/03/15/get-my-slides-from-gdc2012/
In Bezug auf die Leistung führen die neuesten Grafikkarten (DX11-Klasse) Shader auf SIMD-Geräten aus, auf denen 32 (NVIDIA) oder 64 (AMD) "Threads" im Gleichschritt ausgeführt werden. Diese Gruppen werden verschiedentlich als Warps oder Wellenfronten bezeichnet. Bei Pixel-Shadern entspricht jeder Thread einem Pixel. Ich würde also erwarten, dass die SIMD-Einheit so etwas wie einen 8x4 (NVIDIA) - oder 8x8 (AMD) -Pixelblock zusammen verarbeitet. Die Verzweigung und Flusssteuerung erfolgt pro Wellenfront, sodass alle Threads in einer Wellenfront so oft wie das tiefste einzelne Pixel innerhalb dieser Wellenfront wiederholt werden müssen. SIMD-Spurmasken deaktivieren die Ausführung für die Pixel, die bereits fertig sind, müssen jedoch weiterhin stillschweigend mit der Flusssteuerung der gesamten Wellenfront einhergehen. Dies bedeutet natürlich, dass das System viel effizienter ist, wenn die Verzweigung kohärent ist.
Nach meiner Erfahrung ist der Overhead für Verzweigungen immer noch ziemlich hoch, selbst wenn alle Threads in der Wellenfront auf dieselbe Weise verzweigen. Ich habe in einigen Fällen Leistungssteigerungen festgestellt, indem ich die Schleife abgewickelt habe, um einen Teil des Verzweigungsaufwands zu amortisieren. Es hängt jedoch natürlich davon ab, wie viel Arbeit Sie in jeder Schleifeniteration erledigen. Wenn der Loop-Body genug "Zeug" enthält, ist das Abrollen kein Gewinn.
quelle
Ich empfehle, Running Code in einem Teraflop zu lesen : Funktionsweise von GPU-Shader-Kernen (pdf) aus SIGGRAPH 2008: Beyond Programmable Shading . Es geht um dynamische Verzweigung.
quelle
In Bezug auf die dynamische Verzweigung eine zusätzliche Anmerkung (mag offensichtlich sein, ist aber für einige Leute immer noch erwähnenswert): Sie kann die Leistung von nicht gerollten Schleifen erheblich beeinträchtigen (Sie können eine Schleife offensichtlich nicht entrollen, wenn es eine nicht konstante Anzahl von Iterationen gibt). .
quelle
int s = 0;
jetzt ist für (int k = 1; k <= n; k ++) {s + = k;} dasselbe wie s = n * (n + 1) / 2
das ist also im Allgemeinen nicht wahr: D.
quelle