Auswirkungen von Schleifen variabler Länge auf GPU-Shader


9

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:

Geben Sie hier die Bildbeschreibung ein

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?


Leider ist diese Frage hier zu schwer zu beantworten. Obwohl eine bereits gegebene Antwort auf eine solche lesenswerte Quelle hinweist (beinhaltet dynamische Verzweigung). +1 für das "Thema" ..
Teodron

1
@teodron sei nicht defätistisch! Ich hatte gehofft, jemand würde sagen, dass auf NVidia-Karten Bildschirmpixel in 8x8-Blöcken alle so tief iterieren, wie es die tiefsten Bedürfnisse erfordern, und dass Blöcke mit 8x8-Pixeln in beliebiger Reihenfolge oder ähnlichem ausgeführt werden können; Das ist nicht wahr, das ist nur die Art von Weisheit, von der ich hoffe, dass die Leute sie teilen können. Links auf Larrabee, hmm, sind ziemlich indirekt.
Will

Scheint nicht so, als würde er über Larrabee sprechen, aber der Stanford-Typ hielt zwei Jahre später, im Jahr 2010, den gleichen Vortrag ( Sie können ihn hier sehen ). Ausgehend von seinen Zahlen habe ich unter Berücksichtigung einer while-Schleife nicht verstanden, ob die Pixel, die ihre Berechnungen früher "beenden", eine Leistung ausgleichen. In CUDA warten Threads an einer Barriere. Was passiert analog mit Shader-Threads?
Teodron

@teodron Ja, ich habe mein Verständnis von CUDA übernommen und mich auf GPUs beworben. Ich bin mir sicher, dass sie im Gleichschritt sind, aber ich möchte, dass sich jemand auskennt, der sich einschaltet. Wie auch immer
Will

Antworten:


8

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.



0

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). .


-4

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.


1
Möglicherweise werden Sie häufig herabgestimmt, weil niemand genau weiß, was Sie hier vermitteln möchten oder was dies mit der Frage zu tun hat.
Doppelgreener
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.