Verzweigung durch Rechnung ersetzen
-
Hi,
Ich möchte/muss Verzweigungen durch eine Rechnung ersetzen (Hintergrund sind Shader).
Das Prinzip ist folgendes:if (testwert == 0) wert = wert0 if (testwert == 1) wert = wert1
wird ersetzt durch
wert = testwert * wert1 + (1-testwert) * wert0
Wie man hoffentlich sieht, kommt bei beidem das Gleiche raus.
Ich möchte das nun auf mehr Variablen erweitern, auf 5 zum Beispiel.
if (testwert == 0) wert = wert0 if (testwert == 1) wert = wert1 if (testwert == 2) wert = wert2 if (testwert == 3) wert = wert3 ...
Wie lautet die Rechnungsvariante des obigen Codes? Switch und Goto kann ein Shader nicht soweit ich weiß.
Es gibt dafür bestimmt einen Namen, für Hinweise bin ich dankbar.MFG.
-
Hat sich vielleicht erledigt.
wert = !test * wert0 + !(test - 1) * wert1 + !(test - 2) * wert2 + !(test - 3) * wert3 ...
Sieht recht vielversprechend aus.
Hoffentlich schluckt das der Shader und hoffentlich ist !3==0 und !0==1 wie in C.
-
Keine Ahnung, wie so ein Shader funktioniert, aber logische Operatoren (!, &&, ||, ?: ) sind auch nur Verzweigungen. Würde mich echt wundern, wenn das eine prinziell (dh unter der Annahme halbwegs ausgereifter Compiler) dem anderen überlegen wäre.
Wenn du sowas rein mit Grundrechenarten machen willst, würde ich mir mal Polynominterpolation reinziehen. Im Grunde machst du das bei der Formeltestwert * wert1 + (1-testwert) * wert0
, das ist ein Interpolationspolynom 1. Grades durch deine zwei Stützpunkte. Für mehr Punkte könnte es aber leicht in Overkill ausarten ...
-
wert = wert0 * ( testwert && 1) + wert1 * (testwert && 2) + ....
Geht sowas nicht? wenn der Testwert nicht 1 ist dann ist der Ausdruck 0 und somit der wert0 auch 0. Ist der Testwert gleich der 1 dann ist der Ausdruck 1 und 1 * wert0 ist das was du zuweisen willst.
-
Im Prinzip ist ein Shader ein sehr abgespeckter parallelisierter Prozessor in der Grafikkarte.
Leider wurden Arrayzugriffe abgespeckt, mein eigentliches Ziel.
Ich wollte Array[testwert] durch entsprechende if-Anweisungen ersetzen, was er aber auch nicht so mochte wie ich wollte, deswegen die Rechnung. Es soll nicht effizienter werden, es soll überhaupt mal funktionieren. Zeigerarithmetik würde gehen, *(Array + testwert), Pointer gibts aber natürlich auch nicht.testwert * wert1 + (1-testwert) * wert0
sieht irgendwie schon nach Interpolation aus, allerdings ist testwert eine ganze Zahl. Wahrscheinlich kann man eine Interpolationsformel nehmen und sehr viel rauskürzen wegen des Integer Spezialfalls. Interpolieren können Shader aber wiederum ganz gut, zumindest linear, und deutlich schneller als richtige Prozessoren.Shader 4.0 kann Arrayzugriffe, Shader 3.0 nicht. Wahrscheinlich werde ich einfach auf einen 4.0er bestehen müssen.
Ich bin mir auch relativ sicher, dass ! ein direkter Maschinenbefehl ist, den die ALU direkt ausführt, ohne mit Program Counter / Branch Prediction oder ähnlichem zu spielen und ohne die Pipeline zu ruinieren, daher sollte das schon schneller sein als eine if-else-Kette. Einfach einen Arrayzugriff machen wär natürlich noch besser.
-
@blue-tec:
In C-Syntax müsste das & statt && sein und man dürfte nur 2er Potenzen nehmen, weil 3 & 1 auch 1 ist. Ansonsten klappt das sicherlich auch.Danke an alle.
-
nwp3 schrieb:
Das Prinzip ist folgendes:
if (testwert == 0) wert = wert0 if (testwert == 1) wert = wert1
das sollte kein problem fuer einen shadercompiler sein.
wird ersetzt durch
wert = testwert * wert1 + (1-testwert) * wert0
Wie man hoffentlich sieht, kommt bei beidem das Gleiche raus.
Ich möchte das nun auf mehr Variablen erweitern, auf 5 zum Beispiel.
if (testwert == 0) wert = wert0 if (testwert == 1) wert = wert1 if (testwert == 2) wert = wert2 if (testwert == 3) wert = wert3 ...
Wie lautet die Rechnungsvariante des obigen Codes? Switch und Goto kann ein Shader nicht soweit ich weiß.
Es gibt dafür bestimmt einen Namen, für Hinweise bin ich dankbar.das sollte zwar auch problemlos gehen, aber normalerweise gibt man dem compiler einen hint dafuer indem man es umformuliert in
wert = testwert==0?wert0:wert; wert = testwert==1?wert1:wert; wert = testwert==2?wert2:wert; wert = testwert==3?wert3:wert; ...
das geht natuerlich nur bedingt, da shader model 3 nur mit float rechnet und integer eigentlich nur zur compile time richtig evaluiert werden.
Im Prinzip ist ein Shader ein sehr abgespeckter parallelisierter Prozessor in der Grafikkarte.
Im Prinzip ist es eine pure (riesige) SIMD einheit und jeder vertex bzw pixel benutzt eine "lane" von diesem. Deswegen klappt branching auch nicht (bzw nicht effizient), denn wie SIMD schon sogat SINGLE INSTRUCTION multiple data, also muessen alle "daten", in dem speziellen fall "pixel" dem gleichen programmfluss folgen.
simple if abfragen bzw ? operationen werden mittels eines "fused compare select" befehls gemacht und koennen bei geschickter nutzung in nur einem takt pro zeile (von meinem beispiel) abgearbeitet werden. Es sollte auch keine probleme mit latency der isntructions geben.
Leider wurden Arrayzugriffe abgespeckt, mein eigentliches Ziel.
das wurde nicht abgespeckt sondern heisst "texture lookup" und ist eher "aufgespeckt". du kannst darauf natuerlich nur lesend zugreifen da es eine trennung zwischen write und read resourcen gibt. vielleicht hilft das.