GLSL - Dichiarazione di variabili globali al di fuori dell'ambito della funzione principale


12

Aiuta a dichiarare variabili al di fuori del proprio ambito di funzione principale in GLSL? Queste variabili vengono effettivamente riutilizzate ed è più efficiente?

Ecco il codice in questione:

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 );
}

3
Questa domanda è confusa. GLSL non ha un loop principale. Intendi la main()funzione? I tuoi valori sono in realtà variabili globali (uniformi o attributi nel linguaggio GLSL) o valori costanti?
Sean Middleditch il

Puoi pubblicare del codice come esempio di ciò di cui stai parlando?
Nathan Reed,

Ho aggiornato la domanda con il codice.
RodgerDodger,

@ user1286792: Questo non cambia il fatto che GLSL non ha un loop principale . Non è chiaro di cosa stai parlando. Che cosa stai pensando esattamente sarà salvato facendo questo?
Nicol Bolas,

@NicolBolas Ho aggiornato la domanda per essere più chiari. Spero che sia utile ora per qualcuno in futuro.
RodgerDodger,

Risposte:


33

Penso di avere quello che stai cercando di chiedere. Presumo che la tua preoccupazione principale siano le variabili non uniformi definite al di fuori di main():

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

Diamo un'occhiata a come funzionano GPU e GLSL. La GPU non ha uno stack o record di attivazione delle chiamate. Non esiste un modo per simulare l'ambito o le variabili locali in GLSL come un compilatore C può fare sulla maggior parte delle CPU. Tutto ciò che esiste sono i registri, che sono registri uniformi, input dello stadio shader, output e il file di registro locale univoco per quella chiamata shader.

In altre parole, poiché non esiste una funzione, uno stack o un heap, tutte le variabili dichiarate ovunque vivono in un registro. Che siano locali in un certo ambito in GLSL o globali nell'intero file non fa alcuna differenza. Sono solo registri.

Tuttavia, l'allocatore di registro non fa parte dello standard GLSL. Diverse implementazioni OpenGL possono avere diversi livelli di qualità quando si tratta di convertire il codice GLSL di alto livello nel codice macchina di basso livello che la GPU comprende. Una delle parti più complicate di un compilatore (GLSL o altro) è l' allocazione dei registri . Questa è la parte del compilatore che determina quali registri occupa una determinata variabile. C ha un po 'più difficile in quanto di solito ha a che fare con file di registro molto piccoli (specialmente su x86) e deve occuparsi dello spargimento del registro (spostare le variabili nello stack) e dell'aliasing (salvare le variabili nella RAM prima di chiamare le funzioni) e istruzioni dispari che richiedono che l'output sia in un registro particolare (x86idivper esempio). Le GPU hanno un file di registro di grandi dimensioni a causa della mancanza di stack o heap, quindi l'allocatore può essere più semplice.

Tuttavia, il file di registro non è infinito. Se hai più variabili dei registri supportati dal tuo hardware, il compilatore dovrà provare ad adattare tutte le tue variabili ai registri. Questo di solito richiede una qualche forma di controllo dell'intervallo di liveness . Cioè, se usi una variabile xnper un calcolo e non la usi mai più, il compilatore può determinarlo e quindi sapere che il registro occupato xnpotrebbe essere usato in seguito da un'altra variabile, permettendo così più variabili di quante ce ne siano dei registri (così a lungo poiché non ci sono troppe variabili attive contemporaneamente).

Il compilatore potrebbe non farlo, tuttavia. Non ha. O potrebbe farlo solo in alcuni casi. Gli ambiti forniti ai compilatori più semplici rappresentano un problema molto più semplice da risolvere. Tutti i registri assegnati alle variabili di funzione locali possono essere riutilizzati dopo che quella funzione è uscita perché sa che le variabili sono morte. Le variabili globali non hanno una garanzia così facile. Quindi, alcuni compilatori meno capaci potrebbero non ottimizzare anche la loro vita e le variabili globali mangeranno sempre un registro. Ciò non rallenta nulla, ma in alcuni driver può limitare la dimensione dello shader che è possibile scrivere.

In generale, consiglio vivamente di mantenere localizzate tutte le variabili. Mantieni la definizione il più vicino possibile all'utilizzo della variabile. Questo vale per tutti i linguaggi di programmazione, non solo per GLSL. Vorrei anche raccomandare di rendere ogni const "variabile" in ogni caso possibile. Ancora una volta può essere un suggerimento per alcuni compilatori meno capaci che alcune ottimizzazioni siano possibili e, cosa ancora più importante, rende il codice più autocompattante e facile da mantenere.

E, naturalmente, ecco il tuo consiglio "solo profilo da testare e scoprire con certezza". Scrivi il tuo shader con e senza i tuoi globi e profilalo. Tutti i consigli sulle prestazioni online devono essere diffidati e devono essere impregnati di supposizione o non aggiornati.


Questo è esattamente ciò che intendevo. Hai risposto perfettamente alla mia domanda e hai anche spiegato meglio cosa stavo chiedendo.
RodgerDodger,

1
In realtà a volte dichiarare le matrici come const anziché non const rende l'intero shader più lento (MOLTO più lento). Ho notato questo problema sulla mia GTX 460.
Tara,

Mi sono appena sbarazzato di uno strano errore e sospetto fortemente che non sia stata una GPU Adreno (OpenGL ES 3.1) a non compilare uno shader perché le variabili sono state dichiarate al di fuori di main.
comodoro

Una delle risposte SO più complete che abbia mai visto - ben fatto!
duhaime,

Oggi ho imparato qualcosa di nuovo. Oggi, imparo, non conosco o capisco veramente glsl. Solo perché posso usarlo per rendere la geometria trasformata nello spazio cilindrico gif non significa che capisco come funziona.
cmarangu,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.