Warum ist der Zugriff auf Texturen bei der Berechnung der Texturkoordinate im Fragment-Shader viel langsamer?

11

Wenn Sie Texturen in GLSL verwenden, berechnen Sie am besten die endgültigen Texturkoordinaten im Vertex-Shader und übergeben Sie sie mit varyings an den Fragment-Shader . Beispiel mit einem einfachen Umdrehen der y-Koordinate:

// Vertex shader
attribute vec2 texture;
varying highp vec2 texCoord;
// ...
void main() {
    texCoord = vec2(texture.x, 1.0-texture.y);
    // ...
}

// Fragment shader
varying highp vec2 textureCoordinates;
uniform sampler2D tex;
// ...
void main() {
    highp vec4 texColor = texture2D(tex, texCoord);
    // ...
}

Wenn das Umblättern der y-Koordinate oder eine noch einfachere Operation wie das Hinzufügen vec2(0.5)zur Texturkoordinate im Fragment-Shader ausgeführt wird, ist der Texturzugriff viel langsamer. Warum?


Als Hinweis, z. B. das Mischen von zwei Texturen unter Verwendung einer gewichteten Summe davon, ist zeitlich viel billiger und muss auch für jedes Pixel durchgeführt werden, so dass die Berechnung der Texturkoordinate selbst nicht so kostspielig zu sein scheint.

Nero
quelle
1
Meine Vermutung wäre, dass wenn die UV-Koordinaten in VS berechnet werden, die Textureinheit beginnen kann, sie vorab abzurufen, während die PS startet. Wenn sie in der PS berechnet werden, muss die Textureinheit zuerst warten.
RichieSams
2
Fwiw dies wird als "abhängiges Texturlesen" bezeichnet, falls es Ihrer Suche hilft.
Alan Wolfe
Haben Sie einige Messungen, die den Leistungsunterschied zeigen? Ich würde eigentlich nicht erwarten, dass es überhaupt einen großen Unterschied gibt; Die Latenz beim Abrufen von Texturen sollte einige ALU-Operationen überschwemmen. Übrigens gibt es bei abhängigen Texturlesevorgängen zwei (oder mehr) Texturlesevorgänge, wobei die Koordinaten für den zweiten von der Ausgabe des ersten abhängen. Diese sind aufgrund der strengen Reihenfolge zwischen den beiden Texturlesevorgängen langsamer.
Nathan Reed
Nun, jede Operation, die im Fragment-Shader ausgeführt wird, ist teurer als im Vertex-Shader. Jedes Dreieck benötigt 3 Aufrufe eines Vertex-Shaders, aber je nach Bildschirmgröße sind möglicherweise mehr Aufrufe des Fragment-Shaders erforderlich.
Glampert
@NathanReed Ich glaube nicht, dass Sie "abhängige Texturlesevorgänge" auf diejenigen beschränken müssen, die aus einem vorherigen Texturzugriff stammen. Ich würde wahrscheinlich auch alle im Frag-Shader berechneten Koordinaten einschließen, im Gegensatz zu denen, die lediglich aus der linearen (nun ja, hyperbolischen mit Perspektive) Interpolation von Scheitelpunktattributen bestimmt werden können.
Simon F

Antworten:

11

Was Sie sprechen, wird in der Community für mobile Entwickler häufig als "abhängiges Texturlesen" bezeichnet. Es handelt sich um ein Implementierungsdetail bestimmter Hardware, und daher hängt es wirklich von der GPU ab, ob es Auswirkungen auf die Leistung hat oder nicht. In der Regel wird dies für PowerVR-GPUs in Apple-Hardware erwähnt, da dies sowohl in Imagination als auch in Apple ausdrücklich erwähnt wurdeDokumentation. Wenn ich mich richtig erinnere, kam das Problem im Wesentlichen von der Hardware in der GPU, die anfing, Texturen vorab abzurufen, bevor der Fragment-Shader überhaupt ausgeführt wurde, damit die Latenz besser ausgeblendet werden konnte. In den von mir verlinkten Dokumenten wird erwähnt, dass es sich bei Series6-Hardware nicht mehr um ein Problem handelt. Zumindest bei neuerer Apple-Hardware ist dies kein Grund zur Sorge. Bei anderen mobilen GPUs bin ich mir ehrlich gesagt nicht sicher, da dies nicht mein Fachgebiet ist. Sie sollten versuchen, die Dokumentation zu konsultieren, um dies sicher herauszufinden.

Wenn Sie sich zu diesem Thema für eine Google-Suche entscheiden, beachten Sie, dass Sie wahrscheinlich älteres Material finden, das sich mit abhängigen Texturabrufen auf älterer Desktop-Hardware befasst. In den frühen Tagen der Pixel- / Fragment-Shader war der Begriff "abhängiger Texturabruf" grundlegend und bezog sich auf die Verwendung einer UV-Adresse, die auf einem vorherigen Texturabruf beruhte. Das klassische Beispiel war das Bump-Mapping-Umgebungskarten-Rendering, bei dem Sie einen Reflexionsvektor verwenden wollten, der auf der normalen Karte basiert, um die Umgebungskarte abzutasten. Auf dieser älteren Hardware gab es einige wichtige Auswirkungen auf die Leistung, und ich denke, dass sie auf einigen sehr alten GPUs nicht einmal unterstützt wurde. Mit modernen GPUs ist die Hardware und der Shader ISA viel allgemeiner und daher ist die Leistungssituation viel komplizierter.

MJP
quelle
Übrigens: Ich habe das auf einem iPad 3 erlebt. Vielleicht ist das also tatsächlich hardwarespezifisch.
Nero