Por que esse sombreador de geometria diminui tanto o meu programa?

27

Eu tenho um programa OpenGL e estou processando uma malha de terreno. Desloco os vértices no buffer de vértice e ainda não os colo no shader de fragmento. Estou adicionando um shader de geometria, uma parte de cada vez.

Antes de adicionar o sombreador de geometria, quando eu estava apenas programando as etapas de fragmento e sombreamento de vértice do pipeline, estava obtendo taxas de quadros de cerca de 30+. O suficiente para que eu não pudesse notar nenhuma pontada. Depois de adicionar o sombreador de geometria, recebo cerca de 5 quadros por segundo. Por quê? Esta é a totalidade do sombreador de geometria:

#version 420

layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;

void main()
{
    for (int i = 0; i < gl_in.length(); i++)
    {
        gl_Position = gl_in[i].gl_Position;
        EmitVertex();
    }
    EndPrimitive();
}

Não é exatamente isso que o OpenGL estava fazendo sem o sombreador de geometria?

Avi
fonte

Respostas:

40

Não é exatamente isso que o OpenGL estava fazendo sem o sombreador de geometria?

Não é não. O GS é uma etapa opcional , não uma etapa que possui um padrão.

Para que o OpenGL execute um sombreador de geometria , ele deve executar o que é conhecido como " montagem primitiva ". Quando você renderiza uma série de triângulos GL_TRIANGLE_STRIP, o OpenGL faz coisas internas para converter a cada 3 vértices adjacentes em um triângulo individual, modificando a ordem do enrolamento de maneira apropriada.

Normalmente, quando não se usa um GS, esse processo é realizado uma vez. No entanto, quando você usa um GS, ele deve ser executado antes da execução do GS. Mas também deve ser realizado após o GS, porque um GS pode gerar um tipo primitivo totalmente diferente (por exemplo, quads).

Então agora você está fazendo o sistema basicamente fazer um monte de trabalho extra por nada. Afinal, o OpenGL não pode assumir que seu GS não está fazendo nada (esse é um problema indecidível).

Além disso, várias otimizações não funcionam mais na presença de um GS. Considere a renderização indexada.

Cada índice de um buffer de matriz de elementos produzirá as mesmas saídas de um sombreador de vértice. Portanto, a GPU geralmente armazena essas saídas em cache em um cache pós-T&L . Se ele vir um índice que já está no cache, o VS não será executado novamente; apenas busca dados do cache.

O que é isso"? "It" é ... a unidade de montagem primitiva . Sim, aquela coisa que é executada duas vezes quando você usa um GS. O material de armazenamento em cache do índice? Funciona apenas para as entradas do GS.

Então, o que acontece com as saídas do GS? Bem, isso depende do hardware. Mas tem que entrar em algum tipo de buffer de memória. E aí está o problema: esse buffer não está indexado. É como uma situação glDrawArrays.

Portanto, se você enviar um buffer de índice de 0, 1, 2, 0, 2, 3, isso se traduziria em 4 vértices no cache pós-T&L. Mas o buffer de vértices pós-GS agora possui 6 vértices. O buffer pós-GS usa mais espaço. Portanto, se você enfrentar o problema de criar listas ou tiras de triângulo otimizados pós-T&L adequadamente e usar um GS de passagem como o seu, basicamente matará cerca de metade dos seus ganhos de desempenho com essa otimização.

Não foi inútil, mas dói.

Além disso, muitas GPUs da classe GL 3.x (aka: DX10) tinham buffers pós-GS bastante pequenos. Quanto menor o buffer, menos invocações de GS você pode ter ativo simultaneamente. Portanto, seu hardware efetivamente afunila a GS. Como o mosaico é um grande recurso do hardware da classe 4.x, a maioria desses hardwares possui buffers suficientes para viabilizar o uso mais pesado de GS.

Portanto, é mais provável que o uso de um GS faça com que seu processamento de vértice de código seja afunilado. Obviamente, você sempre pode usar isso a seu favor, tornando seus shaders de vértice e fragmento mais complexos, já que é apenas um desempenho gratuito nesse ponto.

Para obter mais informações sobre lentidão induzida por GS, leia este artigo .

Aqui está uma regra básica sobre os GS: nunca use um GS porque você acha que isso tornará a renderização mais rápida . Você deve usá-lo quando isso possibilitar o que você está tentando fazer . Se o que você está tentando fazer é uma otimização, use outra coisa.

As exceções gerais a isso são:

Nicol Bolas
fonte
Estou tentando calcular a inclinação de cada polígono, tomando sua altura mais alta e subtraindo sua altura mais baixa. No entanto, se um sombreador de geometria necessariamente me desacelerar nessa quantidade, acho que posso fazê-lo de forma criativa no sombreador de vértice.
Avi
11
@Avi observe que os pontos mais alto e mais baixo de um triângulo não lhe dão inclinação; você precisa dos três pontos.
sam hocevar
2
Pessoalmente, sempre achei o instanciamento mais útil para sprites pontuais do que um GS.
Maximus Minimus
11
A exceção para sprites de ponto generaliza para shaders de layout(points) in;? Ou é o tamanho de saída fixo? Ou talvez ambos?
Philip