Era uma vez, quando> era mais rápido que <... Espere, o que?

280

Estou lendo um tutorial incrível sobre o OpenGL . É realmente ótimo, confie em mim. O tópico em que estou atualmente é Z-buffer. Além de explicar o que é, o autor menciona que podemos realizar testes de profundidade personalizados, como GL_LESS, GL_ALWAYS etc. Ele também explica que o significado real dos valores de profundidade (que é superior e que não é) também pode ser personalizado. Eu entendo até agora. E então o autor diz algo inacreditável:

O intervalo zNear pode ser maior que o intervalo zFar; se for, os valores do espaço da janela serão revertidos, em termos do que constitui o mais próximo ou o mais distante do visualizador.

Anteriormente, foi dito que o valor de Z no espaço da janela de 0 é o mais próximo e 1 é o mais distante. No entanto, se nossos valores Z do espaço do clipe forem negados, a profundidade de 1 estará mais próxima da vista e a profundidade de 0 será a mais distante. No entanto, se mudarmos a direção do teste de profundidade (GL_LESS para GL_GREATER, etc), obteremos exatamente o mesmo resultado. Portanto, é realmente apenas uma convenção. De fato, inverter o sinal de Z e o teste de profundidade já foi uma otimização de desempenho vital para muitos jogos.

Se eu entendi corretamente, em termos de desempenho, inverter o sinal de Z e o teste de profundidade não passa de uma <comparação para outra >. Então, se eu entendi direito e o autor não está mentindo ou inventando as coisas, mudar <para >costumava ser uma otimização vital para muitos jogos.

O autor está inventando as coisas, estou entendendo mal alguma coisa, ou é realmente o caso que já <foi mais lento ( vitalmente , como o autor diz) do que >?

Obrigado por esclarecer este assunto bastante curioso!

Isenção de responsabilidade: Estou ciente de que a complexidade do algoritmo é a principal fonte de otimizações. Além disso, suspeito que hoje em dia definitivamente não faria diferença e não estou pedindo para otimizar nada. Sou extremamente, dolorosamente, talvez proibitivamente curioso.

Armen Tsirunyan
fonte
6
O link para este tutorial parece ter acabado (recentemente). :(
TZHX
@TZHX: Como a resposta aceita é de autoria do autor do tutorial, esperamos encontrá-la novamente. Ver o meu último comentário à sua resposta :)
Armen Tsirunyan
3
O tutorial OpenGL referenciado está disponível aqui .
Fons 30/05
(a <b) é idêntico a (b> a), portanto, não há absolutamente nenhuma necessidade de implementar as duas operações de comparação no hardware. A diferença no desempenho é resultado do que acontece como resultado da operação de comparação. Esta é uma estrada longa e sinuosa a ser tomada para explicar todos os efeitos colaterais, mas aqui estão algumas dicas. Os jogos costumavam preencher o buffer de profundidade para evitar o processamento de fragmentos mais caro para fragmentos que falharam no teste de profundidade. O Quake costumava dividir o alcance da profundidade em duas metades para evitar a limpeza do buffer de quadros, porque o jogo sempre preenchia todos os pixels na tela e assim por diante.
t0rakka
2
@Fons parece que o link está morto, novamente :(
nalzok

Respostas:

350

Se eu entendi corretamente, em termos de desempenho, inverter o sinal de Z e o teste de profundidade não passa de uma comparação <comparada a uma>. Então, se eu entendi direito e o autor não está mentindo ou inventando as coisas, mudar <para> costumava ser uma otimização vital para muitos jogos.

Não expliquei isso muito bem, porque não era importante. Eu apenas senti que era um pouco interessante de acrescentar. Eu não pretendia revisar o algoritmo especificamente.

No entanto, o contexto é fundamental. Eu nunca disse que uma comparação <era mais rápida que uma>. Lembre-se: estamos falando de testes de profundidade de hardware gráfico, não de sua CPU. Não operator<.

O que eu estava me referindo era uma otimização antiga específica em que um quadro você usaria GL_LESScom um intervalo de [0, 0,5]. No próximo quadro, você renderiza com GL_GREATERum intervalo de [1.0, 0.5]. Você vai e volta, literalmente "lançando o sinal de Z e o teste de profundidade" a cada quadro.

Isso perde um pouco de precisão de profundidade, mas você não precisava limpar o buffer de profundidade, que era uma vez uma operação bastante lenta. Como a limpeza em profundidade não é apenas gratuita atualmente, mas na verdade é mais rápida que essa técnica, as pessoas não fazem mais isso.

Nicol Bolas
fonte
1
A razão pela qual a limpeza do buffer de profundidade é mais rápida hoje em dia tem dois motivos, ambos baseados no fato de que a GPU usa um buffer de profundidade hierárquico. Portanto, basta definir os estados do bloco para limpar (o que é rápido); alterar o sinal de comparação de profundidade, no entanto, significa que todo o buffer HiZ precisa ser liberado, porque ele armazena apenas um valor mínimo ou máximo, dependendo do sinal de comparação.
Jasper Bekkers
3
@NicolBolas: comentário do PerTZHX, o link para o seu tutorial na minha pergunta está morto. Poderia nos informar onde os tutoriais se moveram e, opcionalmente, editar a pergunta, por favor?
Armen Tsirunyan
2
Os tutoriais estão disponíveis no arquivo da web. Se o @NicolBolas permitir, seria útil para a comunidade se pudéssemos movê-los para um local mais acessível. Talvez GitHub ou algo assim. Você está aqui
Página Inicial
3

A resposta é quase certamente que, para qualquer encarnação de chip + driver usada, o Hierarchical Z só funcionava na mesma direção - esse era um problema bastante comum na época. Montagem / ramificação de baixo nível não tem nada a ver com isso - o buffer Z é feito em hardware de função fixa e é canalizado - não há especulações e, portanto, nenhuma previsão de ramificação.

Crowley9
fonte
0

Uma otimização como essa prejudicará o desempenho de muitas soluções gráficas incorporadas, pois tornará a resolução do buffer de quadros menos eficiente. A limpeza de um buffer é um sinal claro para o driver de que ele não precisa armazenar e restaurar o buffer ao fazer o bin.

Pouca informação de fundo: um rasterizador de ladrilhos / ladrilhos processa a tela em número de ladrilhos muito pequenos que cabem na memória do chip. Isso reduz gravações e leituras na memória externa, o que reduz o tráfego no barramento de memória. Quando um quadro é concluído (a troca é chamada ou os FIFOs são liberados porque estão cheios, as ligações do buffer de quadros são alteradas etc.), o buffer de quadros deve ser resolvido; isso significa que cada compartimento é processado por sua vez.

O driver deve assumir que o conteúdo anterior deve ser preservado. A preservação significa que a bandeja deve ser gravada na memória externa e posteriormente restaurada da memória externa quando a bandeja for processada novamente. A operação de limpeza informa ao motorista que o conteúdo da bandeja está bem definido: a cor limpa. Esta é uma situação que é trivial para otimizar. Também existem extensões para "descartar" o conteúdo do buffer.

t0rakka
fonte
-8

Tem a ver com bits de flag em montagem altamente ajustada.

O x86 possui instruções jl e jg, mas a maioria dos processadores RISC possui apenas jl e jz (sem jg).

Joshua
fonte
2
Se essa é a resposta, isso levanta novas questões. A "ramificação realizada" foi mais lenta que a "ramificação ignorada" nos primeiros processadores RISC? Certamente não é assim agora, de qualquer maneira mensurável, tanto quanto eu sei. Você deveria escrever forloops com uma ramificação incondicional para trás e uma ramificação condicional raramente levada adiante para sair do loop? Parece estranho.
Pascal Cuoq 07/09/11
54
-1: Esta questão não tem nada a ver com CPUs . GL_LESS e GL_GREATER são operações de comparação de profundidade, executadas em GPUs.
Nicol Bolas
8
Engraçado quanto rep você pode obter por uma resposta correta ao título, mas que tem muito pouco a ver com a pergunta real.
Joshua
7
+1 Não, esta resposta está correta para pelo menos parte da pergunta. A pergunta é: "O autor está inventando as coisas, estou entendendo mal alguma coisa, ou é verdade que uma vez <foi mais lento (vitalmente, como diz o autor) do que>?". Existem três opções dadas. Esta resposta está respondendo à possibilidade da opção 3. Em nenhum lugar do artigo é fornecida a tecnologia da CPU / GPU, nem que ela deva ser uma GPU (primeiros jogos 3D em que se encontra na CPU). Ok ... eu não acho que houve muitos jogos 3D em RISC :-)
Xanatos
3
(e a etiqueta GPU foi adicionado a 20:34 A primeira revisão teve apenas o tag do CPU Esta resposta foi escrita em 18:44..)
Xanatos