Warum macht der Zugriff auf einen einheitlichen Float meinen Shader mehr als doppelt so langsam?


7

Mein Fragment-Shader wurde durch eine kürzliche Änderung erheblich verlangsamt, und ich habe versucht zu verstehen, warum.

Ich habe die Hauptverlangsamung auf den Zugriff auf einen einzelnen einheitlichen Schwimmer isoliert. Wenn ich diese Zeile einbinde:

float not_used = my_uniform;

dann läuft der Shader mehr als doppelt so langsam wie ohne diese Zeile. Der not_usedFloat wird nie wieder referenziert.

Warum sollte das passieren? Ich hoffe, es zu verstehen, damit ich versuchen kann, eine schnellere Lösung zu finden.

Ich führe dies auf einem Mac mit Intel HD Graphics 3000 aus. Ich messe die Leistung, indem ich OpenGL-Zeitstempelabfragen vor und nach der Ausführung meiner glDrawAnrufe durchführe und die ms-Intervalle betrachte. Ich kann weitere Spezifikationen / Details angeben, wenn dies bei der Diagnose des Problems hilfreich wäre.


Sie messen die Leistung falsch. Draw-Aufrufe können gepuffert sein, daher müssen Sie glFinish()oder Ihre Pufferaustauschfunktionen aufrufen , damit der Code tatsächlich ausgeführt wird. Auch ein anständiger glsl-Compiler sollte alle nicht verwendeten Uniformen aus Ihrem Code entfernen.
Akaltar

@akaltar, ich messe die Leistung auf der GPU-Seite, indem ich gl{Begin,End}Querymit GL_TIME_ELAPSEDals Metrik verwende. Dieses Setup berücksichtigt die Art und Weise, wie OpenGL-Befehle asynchron mit der CPU ausgeführt werden. Siehe opengl.org/registry/specs/ARB/timer_query.txt
Tyler

2
Können Sie den gesamten Shader zeigen?
Roy T.

in seiner jetzigen Form grundsätzlich unmöglich. Jeder Compiler auf dem Planeten optimiert nicht verwendete Variablen. oder vielleicht auch nicht, wenn Sie Mesa mit einer Art Debug-Flag und in der Software-Implementierung verwenden. Da Sie sich jedoch auf einem Mac befinden, ist der glsl-Compiler eine im Treiber eingebettete Version von llvm. Oder Ihr Shader hat zuvor nichts getan und greift auf eine Uniform zu, die jetzt optimiert ist. Der Unterschied ist also ein Maß für das Rauschen. Sie können den FPS-Unterschied nur überprüfen, wenn Sie die GPU-Renderleistung messen.
v.oddou

2
@ Tyler Zweimal so langsam im Vergleich zu was? 16/32 ms oder 0,001 / 0,002 ms? Ist der einheitliche Wert auch eine schöne runde Zahl (0,1,2, -1 usw.)? Es besteht die Möglichkeit, dass die GPU versucht, den Shader neu zu kompilieren, wenn die Uniform einen bequem optimierbaren Wert hat (wenn beispielsweise 0 in Berechnungen vorhanden ist, werden einige von ihnen vollständig deaktiviert, und wenn 1 einheitliche Lesevorgänge und Multiplikationen entfernt).
Schlange5

Antworten:


2

Verwenden Sie glGetUniformLocation, um den Standort der Uniform zu ermitteln? Wenn die Uniform optimiert wurde, gibt diese Funktion -1 zurück. Wenn Sie -1 als Standortargument angeben, glUniform1fwird nichts an den Shader gesendet, was wahrscheinlich einige Zeit spart.


-2

Klingt nach einem Problem mit der Ausrichtung oder der Speichergröße. Vielleicht wird mit diesem einen erhöhten Float Ihr Speicherbedarf auf eine magische Zahl erhöht, die den MAC verlangsamt (ich verwende selbst keine MACs), aber höchstwahrscheinlich verursacht dies ein Ausrichtungsproblem.

Betrachten Sie eine C ++ - Typstruktur im Pseudocode:

struct myStruct {
    char x;
    int y;
}

Wenn diese Struktur normal mit einer int-Größe von 4 Bytes und einer Zeichengröße von 1 Byte erstellt werden darf, beträgt die Struktur 8 Bytes, nicht die erwarteten 5 Bytes. Dies liegt daran, dass, wenn ein Wort (4 Bytes in 32-Bit-Systemen) nicht an einer 4-Byte-Grenze ausgerichtet ist, die CPU mehr Arbeit leisten muss, um dieses Wort zu verschieben. Es ist eine einzelne Assembly-Anweisung, ein Wort (in diesem Fall int) zu verschieben, wenn es richtig ausgerichtet ist. Wenn es nicht richtig ausgerichtet ist, wird die Hälfte des Wortes verschoben, ein Zeiger wird geändert und dann die andere Hälfte, was die Dinge verlangsamt. Daher versucht eine Struktur normalerweise, sich beim Kompilieren richtig auszurichten.

Wenn Sie so etwas wie #pragma packen würden, das die nicht verwendeten Füllbytes entfernen würde, wäre die Größe die erwarteten 5 Bytes und die Dinge wären langsamer.

Ich denke, Sie müssen sich ansehen, wo Sie diesen Float deklarieren und was unmittelbar davor und danach deklariert wird, um herauszufinden, woher Ihre möglichen Speicherausrichtungsprobleme stammen.


3
Es gibt keine solchen Ausrichtungsprobleme auf der GPU. Sie sind grundlegende RISC-DSPs und erlauben keine falsch ausgerichteten Lesevorgänge. Darüber hinaus werden einheitliche Variablen in konstanten Puffern gespeichert, die während einer Thread-Ausführung in Register passen.
v.oddou
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.