Warum lassen uns Pixel-Shader nicht direkt aus dem Framebuffer oder dem Tiefenpuffer lesen?

18

Es wäre eine äußerst nützliche Funktion, wenn ich den Framebuffer oder den Tiefenpuffer im Pixel-Shader abtasten könnte. Es wäre schon nützlich, die Tiefe oder Farbe dessen zu kennen, was sich hinter dem aktuellen Pixel befindet.

Warum lassen mich sowohl OpenGL als auch DirectX dies nicht tun? Ich hatte erwartet, dass es eine Art Hardware-Einschränkung gibt, aber Alpha-Blending verwendet die Farbe im Framebuffer für Blending-Berechnungen, und der Z-Test tastet den Tiefenpuffer an der aktuellen Position ab. Warum setzen Sie uns diese Werte nicht einfach direkt aus? Kann ich hoffen, dies in Zukunft zu sehen?

Hannesh
quelle

Antworten:

20

Dies ist eine Hardwarebeschränkung. Der Fragment-Shader ist Teil der programmierbaren Pipeline, aber die endgültige Farbmischung mit den Zielpuffern ist in weit verbreiteter Hardware / Commodity-Hardware derzeit nicht programmierbar (sie kann über Mischzustände konfiguriert werden, Sie können jedoch keine willkürlichen Werte schreiben Code, der die integrierten Mischvorgänge der GPUs ersetzt).

Der Grund, warum die Hardware nicht dafür gebaut wurde, hängt wahrscheinlich damit zusammen, dass die GPUs massiv parallel sind. Sie verarbeiten viele Fragmente gleichzeitig. Einige dieser Fragmente können letztendlich innerhalb der Zielpuffer miteinander interagieren, aber aufgrund der asynchronen Art der Fragmentverarbeitung ist es nicht möglich zu wissen, wie, bis das Fragment verarbeitet und die endgültige Farbe ausgegeben wurde ... was gewonnen hat passiert nicht immer deterministisch.

Nur weil Pixel A im letzten Frame hinter Pixel B liegt, bedeutet dies nicht, dass Pixel A immer die Fragmentverarbeitung abschließt und vor B an das Ziel geschrieben wird, insbesondere über mehrere Rendering-Frames hinweg. Der während der Verarbeitung von Pixel B aus dem Zielpuffer gelesene Wert ist also nicht immer der Wert von Pixel A - manchmal sind es die eindeutigen Werte.

Ich vermute also, dass das Nichtzulassen von direkten Zielpuffer-Lesevorgängen während der Fragmentierungsphase weit mehr damit zu tun hat, den Shader-Programmierer daran zu hindern, sich in den Fuß zu schießen, indem er potenziell nicht deterministische Ergebnisse aus diesen Lesevorgängen erhält, als aus irgendwelchen tatsächlichen technischen Einschränkungen bei der vollständigen Erstellung der Mischphase. programmierbar. Indem die Leseoperationen streng kontrolliert werden (zum Beispiel der Tiefentest), stellt die GPU sicher, dass die Operationen, die mit dem gelesenen Wert ausgeführt werden, einen Sinn ergeben.

Das heißt, es kann auch eine Kosten / Nutzen-Sache geben. Wenn dieser Aspekt der GPU-Pipeline programmierbar wäre, würde dies das Chipdesign etwas komplizieren, und der Bedarf / die Nachfrage nach Lesevorgängen für den Zielpuffer war im Vergleich zu anderen Merkmalen relativ gering.


quelle
Der historische Grund, warum der Zugriff auf den Framebuffer langsam war, ist, dass die Anweisungen sehr stark in die Pipeline eingereiht sind. Um Zugriff auf ein bestimmtes Framebuffer-Pixel zu erhalten, muss die aktuelle Pipeline angehalten werden, bis alle anderen Pipelines geleert wurden, um das für das abgefragte Pixel relevante Rendering abzuschließen. Sogar in dem merkwürdigen Fall einer vollständig nicht parallelen GPU würden Sie immer noch die gesamte Pipeline für jede Abfrage leeren, was nur eine schlechte Idee ist. Zweifellos sieht die Welt der programmierbaren Hardware jetzt etwas anders aus, aber ich gehe davon aus, dass ein ähnliches Prinzip gilt.
Kylotan
4

Es ist zwar ärgerlich, bietet Hardware-Herstellern jedoch die Flexibilität, den Rendering-Prozess auf zahlreiche und transparente Arten zu optimieren.

Beispielsweise wartet die PowerVR-Hardware (früher sicherlich verwendet, lange nicht mehr verwendet), bis die gesamte zu rendernde Szene übermittelt wurde, und führt dann eine automatische Tiefensortierung mithilfe des Maleralgorithmus durch, ohne dass tatsächlich eine generiert werden muss Tiefenpuffer. Es würde den Bildschirm in Kacheln aufteilen und jede nacheinander rendern.

Roger Perkins
quelle
4

Der Pixel-Shader kann aus den Farb- und Tiefenpuffern nicht lesen, weil:

Pixel A und B können in der Hardware genau zum gleichen Zeitpunkt schattiert werden, obwohl B letztendlich über ("nach") Pixel A gerendert wird.

Wenn Sie sicherstellen würden, dass die Hardware A vor B schattiert, würden Teile der Hardware herumstehen und nichts tun, während A schattiert ist, und Teile der Hardware würden herumstehen und nichts tun, während B schattiert ist.

Im schlimmsten Fall werden alle Pixel, die Sie schattieren, übereinander gerendert, und Tausende und Abertausende von GPU-Threads - bis auf einen - bleiben im Leerlauf. Dieser eine Thread schattiert geduldig Pixel A, dann B, dann C ...

bmcnett
quelle