GLSL - Declarando variáveis ​​globais fora do escopo da função principal

12

Ajuda a declarar variáveis ​​fora do seu escopo de função principal no GLSL? Essas variáveis ​​são realmente reutilizadas e são mais eficientes?

Aqui está o código em questão:

varying vec2 vposition;
uniform float seed;
uniform float top;
uniform float bottom;
uniform float phi;
uniform float theta;
uniform float scaledPI;
uniform float yn;
uniform float ym;
uniform float rx;
uniform float ry;
uniform float radius;

const float PI = 3.141592653589793238462643383;

float left;
float right;
float mscaled;
float xn;
float xm;
void main() {
    float t = vposition.y * yn + ym;

    if(t <= 0.0 || t >= PI){
        left = phi - PI;
        right = phi + PI;
    }else{
        mscaled = scaledPI / (1 - abs(Math.cos(theta)));
        mscaled = mscaled < PI ? mscaled : PI;
        left = phi - mscaled;
        right = phi + mscaled;
    }
    xn = (left - right) / ((-rx / 2.0) - (rx / 2.0));
    xm = left - ((-rx/2.0) * xn);
    float p = vposition.x * xn + xm;

    vec3 coords = vec3( sin(p) * sin(t), cos(t), cos(p) * sin(t) );
    float nv = surface( vec4( coords, seed ) );
    gl_FragColor = vec4( vec3( nv, nv, nv ), 1.0 );
}
RodgerDodger
fonte
3
Esta pergunta é confusa. GLSL não tem um loop principal. Você quer dizer a main()função? Seus valores são realmente variáveis globais (uniformes ou atributos na linguagem GLSL) ou valores constantes?
quer
Você pode postar algum código como um exemplo do que está falando?
Nathan Reed
Eu atualizei a pergunta com código.
precisa saber é o seguinte
@ user1286792: Isso não altera o fato de que o GLSL não possui um loop principal . Não está claro do que você está falando. O que exatamente você acha que será salvo ao fazer isso?
Nicol Bolas
@ NicolBolas Atualizei a pergunta para ficar mais clara. Espero que seja útil agora para alguém no futuro.
RodgerDodger

Respostas:

33

Acho que entendi o que você está tentando perguntar. Presumo que sua principal preocupação sejam as variáveis ​​não uniformes definidas fora de main():

float left;
float right;
float mscaled;
float xn;
float xm;

Vamos dar uma olhada em como a GPU e o GLSL funcionam. A GPU não possui uma pilha ou registros de ativação de chamada. Não há como simular escopo ou variáveis ​​locais no GLSL, como um compilador C pode fazer na maioria das CPUs. Tudo o que existe são os registros, que são registros uniformes, entradas do estágio de sombreador, saídas e o arquivo de registro local exclusivo para essa chamada de sombreador.

Em outras palavras, como não existe uma função, a pilha ou a pilha, todas as variáveis ​​declaradas em qualquer lugar ficam em um registro. Seja local para algum escopo no GLSL ou global para o arquivo inteiro, não faz diferença. Eles são apenas registros.

No entanto, o alocador de registro não faz parte do padrão GLSL. Diferentes implementações de OpenGL podem ter níveis variados de qualidade quando se trata de converter código GLSL de alto nível em código de máquina de baixo nível que a GPU entende. Uma das partes mais complicadas de um compilador (GLSL ou não) é a alocação de registros . Essa é a parte do compilador que determina quais registros uma determinada variável ocupa. C tem um pouco mais de dificuldade, pois geralmente tem que lidar com arquivos de registro muito pequenos (especialmente no x86) e tem que lidar com derramamento de registro (mover variáveis ​​para a pilha) e alias (salvar variáveis ​​de volta na RAM antes de chamar funções) e instruções ímpares que exigem a saída em um registro específico (x86idivpor exemplo). As GPUs têm um arquivo de registro grande por não terem pilha ou pilha, portanto, o alocador pode ser mais simples.

No entanto, o arquivo de registro não é infinito. Se você tiver mais variáveis ​​do que registros suportados pelo seu hardware, o compilador precisará ajustar todas as suas variáveis ​​nos registros. Isso geralmente requer alguma forma de verificação do alcance da animação . Ou seja, se você usar uma variável xnpara um cálculo e nunca mais usá-la novamente, o compilador poderá determinar isso e, em seguida, saber que o registro ocupado por xnpoderia ser usado por outra variável posteriormente, permitindo mais variáveis ​​do que há registros (por muito tempo porque não há muitas variáveis ​​dinâmicas ao mesmo tempo).

O compilador pode não fazer isso, no entanto. Não tem. Ou pode fazê-lo apenas em alguns casos. Os escopos deram aos compiladores mais simples um problema muito mais fácil de resolver. Todos os registros alocados às variáveis ​​de função local podem ser reutilizados após a saída dessa função, porque ela sabe que as variáveis ​​estão mortas. Variáveis ​​globais não têm essa garantia fácil. Portanto, alguns compiladores menos capazes podem não otimizar sua vida útil também, e as variáveis ​​globais sempre consomem um registro. Isso não tornará nada mais lento, mas em alguns drivers poderá limitar o tamanho do sombreador que você pode escrever.

Em geral, eu recomendaria manter todas as variáveis ​​localizadas. Mantenha a definição o mais próximo possível do uso da variável. Isso se aplica a todas as linguagens de programação, não apenas ao GLSL. Eu também recomendaria criar todas as constantes "variáveis" em todos os casos possíveis. Mais uma vez, pode ser uma dica para certos compiladores menos capazes de que certas otimizações são possíveis e, mais importante, torna seu código mais auto-documentado e fácil de manter.

E, claro, aqui está o seu obrigatório "apenas perfil para testar e descobrir com certeza" conselhos. Escreva seu shader com e sem os globais e faça o perfil. Todo e qualquer aconselhamento on-line sobre desempenho deve ser desconfiado e presumido estar imerso em suposição ou desatualizado.

Sean Middleditch
fonte
Foi exatamente isso que eu quis dizer. Você respondeu minha pergunta perfeitamente e também explicou melhor o que eu estava perguntando.
precisa saber é o seguinte
11
Às vezes, declarar matrizes como const, em vez de não-const, torna todo o shader mais lento (MUITO MAIS LENTO). Notei que problema no meu GTX 460.
Tara
Acabei de me livrar de um erro estranho e suspeito fortemente que a GPU Adreno (OpenGL ES 3.1) não conseguiu compilar um sombreador porque as variáveis ​​foram declaradas fora do main.
Comodoro
Uma das respostas mais completas do SO que eu já vi - muito bem!
Duhaime
Hoje eu aprendi algo novo. Hoje, eu aprendo, eu realmente não conheço ou entendo glsl. Só porque eu posso usá-lo para criar um espaço cilíndrico transformado em geometria gif não significa que eu entenda como funciona.
cmarangu