Ich habe gehört, dass if-Anweisungen in Shadern vermieden werden sollten, da beide Teile der Anweisungen ausgeführt werden und dann das falsche gelöscht wird (was die Leistung beeinträchtigt).
Es ist immer noch ein Problem in DirectX 10? Jemand hat mir gesagt, dass darin nur der richtige Zweig ausgeführt wird.
Zur Illustration habe ich den Code:
float y1 = 5; float y2 = 6; float b1 = 2; float b2 = 3;
if(x>0.5){
x = 10 * y1 + b1;
}else{
x = 10 * y2 + b2;
}
Gibt es eine andere Möglichkeit, es schneller zu machen?
Wenn ja, wie geht das?
Beide Zweige sehen ähnlich aus, der einzige Unterschied sind die Werte der "Konstanten" ( y1, y2, b1, b2
sind für alle Pixel in Pixel Shader gleich).
Antworten:
Viele Regeln für die Mikrooptimierung von Shadern sind die gleichen wie für herkömmliche CPUs mit Vektorerweiterungen. Hier einige Hinweise:
test
,lerp
/mix
)Es ist wahr, dass Filialen auf moderner Hardware billiger sind als früher, aber es ist immer noch besser, sie zu vermeiden, wenn dies möglich ist. Mit Swizzling- und Testfunktionen können Sie Ihren Shader ohne Tests neu schreiben:
Die Verwendung von
step
undlerp
ist eine sehr gebräuchliche Ausdrucksweise für die Auswahl zwischen zwei Werten.quelle
Im Allgemeinen ist es in Ordnung. Shader werden in Gruppen von Scheitelpunkten oder Pixeln ausgeführt (verschiedene Anbieter haben unterschiedliche Terminologie, daher halte ich mich davon fern). Wenn alle Scheitelpunkte oder Pixel in einer Gruppe denselben Pfad verwenden, sind die Verzweigungskosten vernachlässigbar.
Sie müssen auch dem Shader-Compiler vertrauen. Der von Ihnen geschriebene HLSL-Code sollte nicht als direkte Repräsentation des Bytecodes oder gar der Assembly angesehen werden, in die er kompiliert, und der Compiler kann ihn problemlos in etwas Äquivalentes konvertieren, vermeidet jedoch den Zweig (z. B. ein Lerp) eine bevorzugte Umwandlung). Wenn der Compiler hingegen feststellt, dass das Durchführen einer Verzweigung tatsächlich der schnellere Weg ist, kompiliert er sie bis zu einer Verzweigung. Das Anzeigen der generierten Assembly in PIX oder einem ähnlichen Tool kann hier sehr hilfreich sein.
Schließlich gilt hier immer noch die alte Weisheit: Profilieren Sie sie, stellen Sie fest, ob es sich tatsächlich um ein Leistungsproblem handelt, und packen Sie es dann an, nicht vorher. Unter der Annahme , dass etwas kann ein Leistungsproblem sein und Handeln nach dieser Annahme wird nur ein großes Risiko von größeren Problemen später entstehen.
quelle
Zitat aus dem Link / Artikel von Robert Rouhani:
Wie von mh01 vorgeschlagen ("Das Anzeigen der generierten Assembly in PIX oder einem ähnlichen Tool kann hier sehr hilfreich sein."), Sollten Sie ein Compiler-Tool verwenden, um die Ausgabe zu untersuchen. Nach meiner Erfahrung lieferte das Cg-Tool von nVidia (das aufgrund seiner plattformübergreifenden Funktionen immer noch weit verbreitet ist) eine perfekte Darstellung des Verhaltens, das im Abschnitt " GPU-Gems- Bedingungscodes (Prädikation)" erwähnt wird . Unabhängig vom Auslösewert wurden daher beide Zweige fragmentweise ausgewertet, und erst am Ende wurde der richtige Zweig in das Ausgaberegister gestellt. Trotzdem wurde die Rechenzeit verschwendet. Damals dachte ich, dass Verzweigung die Leistung verbessern wird, vor allem, weil alleFragmente in diesem Shader beruhten auf einem einheitlichen Wert, um den richtigen Zweig zu bestimmen - das geschah nicht wie beabsichtigt. Also, eine große Einschränkung hier (z. B. Ubershader vermeiden - möglicherweise die größte Quelle der Höllenverzweigung).
quelle
Wenn Sie noch keine Leistungsprobleme haben, ist dies in Ordnung. Die Kosten für den Vergleich mit einer Konstanten sind immer noch extrem günstig. Lesen Sie hier mehr über die GPU-Verzweigung: http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter34.html
Unabhängig davon ist hier ein Codeausschnitt, der viel schlechter abschneidet als die if-Anweisung (und weitaus weniger lesbar / wartbar ist), den er jedoch immer noch entfernt:
Beachten Sie, dass ich davon ausgehe, dass x auf den Bereich beschränkt ist
[0, 1]
. Dies funktioniert nicht, wenn x> = 2 oder x <0 ist.Das Ergebnis ist, x in entweder umzuwandeln
0
oder1
das falsche mit 0 und das andere mit 1 zu multiplizieren.quelle
if(x<0.5)
der Wert fürfx
sein sollround(x)
oder istfloor(x + 0.5)
.Es gibt mehrere Befehle, die Bedingungen ohne Verzweigung ausführen können.
Plus einige logische Operatoren;
Quelle: http://theorangeduck.com/page/avoiding-shader-conditionals
quelle