Por que os pixel shaders não nos permitem ler diretamente do buffer de quadros ou do buffer de profundidade?

18

Deixar-me experimentar o buffer de quadros ou o buffer de profundidade no sombreador de pixels seria um recurso extremamente útil. Mesmo apenas saber a profundidade ou a cor do que está por trás do pixel atual seria útil.

Por que o OpenGL e o DirectX não me permitem fazer isso? Eu esperava que houvesse algum tipo de limitação de hardware, mas a mistura alfa usa a cor no buffer de estrutura para cálculos de mistura, e o teste Z mostra o buffer de profundidade no local atual. Por que não apenas expor esses valores diretamente para nós? Posso esperar ver isso no futuro?

Hannesh
fonte

Respostas:

20

Ele é uma limitação de hardware. O shader de fragmento faz parte do pipeline programável, mas a mistura final de cores com o (s) buffer (s) de destino não é programável em hardware de commodity amplamente disponível neste momento (é configurável através dos estados de mistura, mas você não pode escrever arbitrariamente código que substitui as operações de mistura incorporadas das GPUs).

A razão pela qual o hardware não foi construído para isso provavelmente tem a ver com o fato de a GPU ser massivamente paralela; eles processam muitos fragmentos de cada vez. Alguns desses fragmentos podem interagir entre si nos buffers de destino, mas devido à natureza assíncrona do processamento de fragmentos, não é possível saber como até que o fragmento tenha sido processado e a cor final emitida ... sempre acontece deterministicamente.

Só porque o pixel A estará atrás do pixel B no quadro final não significa que o pixel A sempre concluirá o processamento do fragmento e será gravado no destino antes de B, especialmente em vários quadros de renderização. Portanto, o valor lido do buffer de destino durante o processamento do pixel B nem sempre será do pixel A - às vezes serão os valores claros.

Portanto, desconfio que a proibição de leituras diretas do buffer de destino durante o estágio de fragmento tenha muito mais a ver com impedir que o programador de shader se atire no pé, obtendo resultados potencialmente não determinísticos dessa leitura do que com qualquer limitação técnica real para tornar o estágio de mistura totalmente- programável. Ao manter as operações de leitura rigidamente controladas (o teste de profundidade, por exemplo), a GPU garante que as operações realizadas com o valor de leitura façam algum tipo de sentido.

Dito isto, também pode haver uma coisa de custo / benefício acontecendo. Tornar programável esse aspecto do pipeline da GPU complicaria um pouco o design do chip, e a necessidade / demanda de leituras do buffer de destino tem sido relativamente baixa em comparação com outros recursos.


fonte
Apenas para expandir isso, a razão histórica pela qual o acesso ao buffer de quadros foi lento é porque as instruções são muito pesadas. Obter acesso a um determinado pixel do buffer de estrutura envolveria o bloqueio do pipeline atual até que todos os outros pipelines fossem liberados para concluir qualquer renderização relevante para o pixel consultado. Mesmo no caso estranho de uma GPU completamente não paralela, você ainda estaria liberando o pipeline inteiro para cada consulta, o que é apenas uma má ideia. Sem dúvida, as coisas estão um pouco diferentes no mundo do hardware programável agora, mas espero que se aplique um princípio semelhante.
Kylotan
4

Embora irritante, permite aos fabricantes de hardware a flexibilidade de otimizar o processo de renderização de várias maneiras transparentes.

Por exemplo, o hardware do PowerVR (que costumava voltar no dia, não usado há muito tempo) espera até que toda a cena a ser renderizada seja enviada e, em seguida, efetua a classificação automática de profundidade usando o algoritmo do pintor e não precisa realmente gerar um buffer de profundidade. Ele dividiria a tela em blocos e renderizaria cada um deles.

Roger Perkins
fonte
4

O sombreador de pixels não pode ler os buffers de cor e profundidade porque:

Os pixels A e B podem ser sombreados exatamente no mesmo momento no hardware, embora B seja renderizado no topo do pixel A. (depois) do pixel A.

Se você fizesse com que o hardware tivesse a garantia de sombrear A antes de B, as partes do hardware ficariam sem fazer nada enquanto A estiver sombreado e as partes do hardware ficariam sem fazer nada enquanto B estiver sombreado.

Na pior das hipóteses que se pode imaginar, todos os pixels que você sombra renderizam uns sobre os outros e os milhares e milhares de threads da GPU - todos, exceto um - ficam ociosos. Este segmento protege pacientemente os pixels A, B e C ...

bmcnett
fonte