GLSL - Déclaration de variables globales en dehors de l'étendue de la fonction principale

12

Cela aide-t-il à déclarer des variables en dehors de la portée de votre fonction principale dans GLSL? Ces variables sont-elles réellement réutilisées et est-elle plus efficace?

Voici le code en question:

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
la source
3
Cette question prête à confusion. GLSL n'a pas de boucle principale. Voulez-vous dire la main()fonction? Vos valeurs sont-elles réellement des variables globales (uniformes ou attributs dans le langage GLSL) ou des valeurs constantes?
Sean Middleditch
Pouvez-vous publier du code comme exemple de ce dont vous parlez?
Nathan Reed
J'ai mis à jour la question avec le code.
RodgerDodger
@ user1286792: Cela ne change pas le fait que GLSL n'a pas de boucle principale . On ne sait pas de quoi vous parlez. Que pensez-vous exactement qui sera sauvé en faisant cela?
Nicol Bolas
@NicolBolas J'ai mis à jour la question pour être plus claire. J'espère que cela sera utile maintenant pour quelqu'un à l'avenir.
RodgerDodger

Réponses:

33

Je pense que je comprends ce que vous essayez de demander. Je suppose que votre principale préoccupation concerne les variables non uniformes définies en dehors de main():

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

Jetons un coup d'œil au fonctionnement du GPU et du GLSL. Le GPU n'a pas de pile ni d'enregistrements d'activation d'appel. Il n'y a aucun moyen de simuler la portée ou les variablaes locales dans GLSL comme un compilateur C peut le faire sur la plupart des CPU. Tout ce qui existe, ce sont les registres, qui sont soit des registres uniformes, des entrées, des sorties d'étage de shader et le fichier de registre local propre à cette invocation de shader.

En d'autres termes, comme il n'existe pas de fonction, de pile ou de tas, toutes les variables déclarées n'importe où vivent dans un registre. Qu'ils soient locaux à une certaine étendue dans GLSL ou globaux à l'ensemble du fichier ne fait aucune différence. Ce ne sont que des registres.

Cependant, l'allocateur de registre ne fait pas partie de la norme GLSL. Différentes implémentations OpenGL peuvent avoir différents niveaux de qualité lorsqu'il s'agit de convertir du code GLSL de haut niveau en code machine de bas niveau que le GPU comprend. L'une des parties les plus compliquées d'un compilateur (GLSL ou autre) est l' allocation des registres . C'est la partie du compilateur qui détermine quels registres une variable donnée occupe. C a un peu plus de difficulté car il doit généralement gérer de très petits fichiers de registre (en particulier sur x86) et il doit gérer le débordement de registre (déplacement des variables vers la pile) et l'alias (sauvegarde des variables dans la RAM avant d'appeler des fonctions) et des instructions impaires qui demandent que la sortie soit dans un registre particulier (x86idivpar exemple). Les GPU ont un fichier de registre de grande taille en raison de l'absence de pile ou de tas, donc l'allocateur peut être plus simple.

Cependant, le fichier de registre n'est pas infini. Si vous avez plus de variables que de registres pris en charge par votre matériel, le compilateur devra essayer d'ajuster toutes vos variables dans les registres. Cela nécessite généralement une forme de vérification de la plage de vie . Autrement dit, si vous utilisez une variable xnpour un calcul, puis ne l'utilisez plus jamais, le compilateur peut le déterminer et savoir que le registre occupé par xnpourrait être utilisé par une autre variable plus tard, permettant ainsi plus de variables qu'il n'y a de registres (si longtemps car il n'y a pas trop de variables live à la fois).

Cependant, le compilateur peut ne pas le faire. Ce n'est pas le cas. Ou il pourrait ne le faire que dans certains cas. Les étendues données aux compilateurs plus simples sont un problème beaucoup plus facile à résoudre. Tous les registres alloués aux variables de fonction locales peuvent être réutilisés après la fermeture de cette fonction car elle sait que les variables sont mortes. Les variables globales n'ont aucune garantie aussi simple. Par conséquent, certains compilateurs moins capables peuvent ne pas optimiser également leur durée de vie, et les variables globales consomment toujours un registre. Cela ne fera pas quoi que ce soit plus lent , mais il peut sur certains pilotes limiter la taille du shader , vous pouvez écrire.

En général, je recommande fortement de garder toutes les variables localisées. Gardez la définition aussi proche que possible de l'utilisation de la variable. Cela s'applique à tous les langages de programmation, pas seulement à GLSL. Je recommanderais également de faire chaque const "variable" dans tous les cas que vous pouvez. Il peut encore être un indice pour certains compilateurs moins capables que certaines optimisations sont possibles, et plus important encore, cela rend votre code plus auto-documenté et facile à maintenir.

Et bien sûr, voici votre "profil juste obligatoire pour tester et découvrir avec certitude" des conseils. Écrivez votre shader avec et sans vos globales et profilez-le. Tous les conseils de performance en ligne doivent être méfiants et supposés être imprégnés de suppositions ou obsolètes.

Sean Middleditch
la source
C'est exactement ce que je voulais dire. Vous avez parfaitement répondu à ma question et mieux expliqué ce que je demandais.
RodgerDodger
1
En fait, parfois, déclarer des tableaux comme const au lieu de non-const rend l'ensemble du shader plus lent (BEAUCOUP plus lent). J'ai remarqué ce problème sur ma GTX 460.
Tara
Je viens de me débarrasser d'une erreur étrange et je soupçonne fortement qu'il s'agissait d'un GPU Adreno (OpenGL ES 3.1) qui n'a pas pu compiler un shader car les variables ont été déclarées en dehors de main.
comodoro
L'une des réponses SO les plus complètes que j'ai jamais vues - bravo!
duhaime
Aujourd'hui, j’ai appris quelque chose de nouveau. Aujourd'hui, j'apprends, je ne connais ni ne comprends vraiment glsl. Ce n'est pas parce que je peux l'utiliser pour faire de la géométrie gif transformée par l'espace cyllindrique que je comprends comment cela fonctionne.
cmarangu