Pourquoi les pixel shaders ne nous permettent-ils pas de lire directement à partir du framebuffer ou du buffer de profondeur?

18

Me laisser échantillonner le tampon d'image ou le tampon de profondeur dans le pixel shader serait une fonctionnalité extrêmement utile. Même le simple fait de connaître la profondeur ou la couleur de tout ce qui se trouve derrière le pixel actuel serait utile.

Pourquoi OpenGL et DirectX ne me laissent-ils pas faire cela? Je m'attendais à ce qu'il y ait une sorte de limitation matérielle, mais le mélange alpha utilise la couleur dans le tampon de cadre pour les calculs de mélange, et le test Z échantillonne le tampon de profondeur à l'emplacement actuel. Pourquoi ne pas simplement nous exposer ces valeurs directement? Puis-je espérer voir cela à l'avenir?

Hannesh
la source

Réponses:

20

Il s'agit d' une limitation matérielle. Le fragment shader fait partie du pipeline programmable, mais le mélange de couleurs final avec le (s) tampon (s) cible (s) n'est pas programmable dans le matériel largement disponible / de base à ce stade (il est configurable via des états de mélange, mais vous ne pouvez pas écrire arbitrairement code qui remplace les opérations de mélange intégrées des GPU).

La raison pour laquelle le matériel n'est pas construit pour cela a probablement à voir avec le fait que les GPU sont massivement parallèles; ils traitent plusieurs fragments à la fois. Certains de ces fragments peuvent finalement interagir les uns avec les autres dans les tampons de destination, mais en raison de la nature asynchrone du traitement des fragments, il n'est possible de savoir comment qu'après que le fragment a été traité et que la couleur finale a été émise ... ce qui a gagné ça n'arrive pas toujours de façon déterministe.

Le fait que le pixel A soit derrière le pixel B dans la dernière image ne signifie pas que le pixel A terminera toujours le traitement des fragments et sera écrit sur la destination avant B, en particulier sur plusieurs images de rendu. Ainsi, la valeur lue dans le tampon de destination pendant le traitement du pixel B ne sera pas toujours celle du pixel A - parfois ce seront les valeurs claires.

Je soupçonne donc que l'interdiction des lectures directes du tampon de destination pendant la phase de fragment a beaucoup plus à voir avec le fait d'empêcher le programmeur de shader de se tirer une balle dans le pied en obtenant des résultats potentiellement non déterministes à partir de cette lecture que de toute limitation technique réelle pour rendre la phase de mélange entièrement programmable. En gardant les opérations de lecture étroitement contrôlées (le test de profondeur, par exemple), le GPU garantit que les opérations effectuées avec la valeur de lecture ont un certain sens.

Cela dit, il peut également y avoir un rapport coût / avantage. Rendre programmable cet aspect du pipeline GPU compliquerait quelque peu la conception de la puce, et le besoin / demande de lectures de tampon de destination a été relativement faible par rapport à d'autres fonctionnalités.


la source
Juste pour développer cela, la raison historique pour laquelle l'accès au framebuffer a été lent est parce que les instructions sont très fortement pipelinées. L'accès à un pixel de framebuffer donné impliquerait le blocage du pipeline actuel jusqu'à ce que tous les autres pipelines soient vidés pour terminer tout rendu pertinent pour le pixel interrogé. Même dans le cas étrange d'un GPU complètement non parallèle, vous seriez toujours en train de vider le pipeline entier pour chaque requête, ce qui est juste une mauvaise idée. Il ne fait aucun doute que les choses sont un peu différentes dans le monde du matériel programmable, mais je m'attends à ce qu'un principe similaire s'applique.
Kylotan
4

Bien que gênant, il permet aux fabricants de matériel d’optimiser le processus de rendu de nombreuses manières transparentes.

Par exemple, le matériel PowerVR (certainement utilisé pour sauvegarder la journée, pas utilisé depuis longtemps) attend que la scène entière à rendre soit soumise, puis effectue un tri automatique de la profondeur en utilisant l'algorithme des peintres et n'a pas réellement besoin de générer un tampon de profondeur. Il diviserait l'écran en tuiles et rendrait chacune à son tour.

Roger Perkins
la source
4

Le pixel shader ne peut pas lire les tampons de couleur et de profondeur car:

Les pixels A et B peuvent être ombrés exactement au même moment dans le matériel, bien que B soit rendu au-dessus du pixel ("après") A.

Si vous avez fait en sorte que le matériel soit garanti pour ombrer A avant B, alors des parties du matériel resteraient sans rien faire pendant que A est ombré, puis des parties du matériel resteraient sans rien faire pendant que B est ombré.

Dans le pire des cas imaginables, tous les pixels que vous ombrez s'affichent les uns sur les autres, et les milliers et milliers de threads GPU - tous sauf un - restent inactifs. Ce fil ombrage patiemment le pixel A, puis B, puis C ...

bmcnett
la source