Comment déboguer un shader GLSL?

Je dois déboguer un programme GLSL mais je ne sais pas comment générer un résultat intermédiaire. Est-il possible de faire des traces de débogage (comme avec printf) avec GLSL?

Vous ne pouvez pas facilement communiquer avec le processeur depuis GLSL. Utiliser glslDevil ou d’autres outils est votre meilleur choix.

Un printf nécessiterait d’essayer de revenir au processeur depuis le GPU exécutant le code GLSL. Au lieu de cela, vous pouvez essayer d’avancer à l’écran. Au lieu d’essayer de sortir du texte, affichez quelque chose de distinctif visuellement à l’écran. Par exemple, vous pouvez peindre quelque chose d’une couleur spécifique seulement si vous atteignez le sharepoint votre code où vous voulez append un printf. Si vous devez imprimer une valeur, vous pouvez définir la couleur en fonction de cette valeur.

void main(){ float bug=0.0; vec3 tile=texture2D(colMap, coords.st).xyz; vec4 col=vec4(tile, 1.0); if(something) bug=1.0; col.x+=bug; gl_FragColor=col; } 

J’ai trouvé Transform Feedback comme un outil utile pour déboguer les vertex shaders. Vous pouvez l’utiliser pour capturer les valeurs des sorties VS et les lire du côté du processeur, sans avoir à passer par le rasterizer.

Voici un autre lien vers un tutoriel sur Transform Feedback.

Si vous souhaitez visualiser les variations d’une valeur à travers l’écran, vous pouvez utiliser une fonction heatmap similaire à celle-ci (je l’ai écrite dans hlsl, mais il est facile de l’adapter à glsl):

 float4 HeatMapColor(float value, float minValue, float maxValue) { #define HEATMAP_COLORS_COUNT 6 float4 colors[HEATMAP_COLORS_COUNT] = { float4(0.32, 0.00, 0.32, 1.00), float4(0.00, 0.00, 1.00, 1.00), float4(0.00, 1.00, 0.00, 1.00), float4(1.00, 1.00, 0.00, 1.00), float4(1.00, 0.60, 0.00, 1.00), float4(1.00, 0.00, 0.00, 1.00), }; float ratio=(HEATMAP_COLORS_COUNT-1.0)*saturate((value-minValue)/(maxValue-minValue)); float indexMin=floor(ratio); float indexMax=min(indexMin+1,HEATMAP_COLORS_COUNT-1); return lerp(colors[indexMin], colors[indexMax], ratio-indexMin); } 

Ensuite, dans votre pixel shader, vous sortez simplement quelque chose comme:

 return HeatMapColor(myValue, 0.00, 50.00); 

Et peut avoir une idée de la façon dont il varie à travers vos pixels:

entrer la description de l'image ici

Bien sûr, vous pouvez utiliser n’importe quel jeu de couleurs que vous aimez.

GLSL Sandbox m’a été très utile pour les shaders.

Pas de débogage en soi (qui a été répondu comme incapable), mais pratique pour voir les changements de sortie rapidement.

Effectuez un rendu hors ligne vers une texture et évaluez les données de la texture. Vous pouvez trouver le code associé par googler pour “render to texture” opengl Utilisez ensuite glReadPixels pour lire la sortie dans un tableau et y effectuer des assertions (car parcourir un si grand tableau dans le débogueur n’est généralement pas vraiment utile).

Vous pouvez également désactiver le bridage sur les valeurs de sortie qui ne sont pas comsockets entre 0 et 1, ce qui est uniquement pris en charge pour les textures à virgule flottante .

Personnellement, j’ai été dérangé par le problème du débogage correct des shaders pendant un certain temps. Il ne semble pas y avoir de bon moyen – Si quelqu’un trouve un bon débogueur (et non obsolète / obsolète), faites-le moi savoir.

Je partage un exemple de fragment shader, comment je débogue réellement.

 #version 410 core uniform sampler2D samp; in VS_OUT { vec4 color; vec2 texcoord; } fs_in; out vec4 color; void main(void) { vec4 sampColor; if( texture2D(samp, fs_in.texcoord).x > 0.8f) //Check if Color contains red sampColor = vec4(1.0f, 1.0f, 1.0f, 1.0f); //If yes, set it to white else sampColor = texture2D(samp, fs_in.texcoord); //else sample from original color = sampColor; } 

entrer la description de l'image ici

Les réponses existantes sont toutes bonnes, mais je voulais partager un petit bijou qui a été utile pour déboguer des problèmes de précision délicats dans un shader GLSL. Avec de très grands nombres int représentés sous forme de virgule flottante, il faut veiller à utiliser correctement floor (n) et floor (n + 0.5) pour implémenter round () à un int exact. Il est alors possible de rendre une valeur flottante qui est un int exact par la logique suivante pour compresser les composants en octets en valeurs de sortie R, G et B.

  // Break components out of 24 bit float with rounded int value // scaledWOB = (offset >> 8) & 0xFFFF float scaledWOB = floor(offset / 256.0); // c2 = (scaledWOB >> 8) & 0xFF float c2 = floor(scaledWOB / 256.0); // c0 = offset - (scaledWOB << 8) float c0 = offset - floor(scaledWOB * 256.0); // c1 = scaledWOB - (c2 << 8) float c1 = scaledWOB - floor(c2 * 256.0); // Normalize to byte range vec4 pix; pix.r = c0 / 255.0; pix.g = c1 / 255.0; pix.b = c2 / 255.0; pix.a = 1.0; gl_FragColor = pix; 

Au bas de cette réponse se trouve un exemple de code GLSL qui permet de générer la valeur float complète en couleur, en codant IEEE 754 binary32 . Je l’utilise comme suit (cet extrait donne le composant yy de la masortingce modelview):

 vec4 xAsColor=toColor(gl_ModelViewMasortingx[1][1]); if(bool(1)) // put 0 here to get lowest byte instead of three highest gl_FrontColor=vec4(xAsColor.rgb,1); else gl_FrontColor=vec4(xAsColor.a,0,0,1); 

Une fois que vous obtenez ceci à l’écran, vous pouvez simplement prendre n’importe quel sélecteur de couleur, formater la couleur au format HTML (en ajoutant 00 à la valeur rgb si vous n’avez pas besoin d’une précision plus élevée et faire un deuxième passage pour obtenir l’octet inférieur) , et vous obtenez la représentation hexadécimale du float comme IEEE 754 binary32 .

Voici l’implémentation réelle de toColor() :

 const int emax=127; // Input: x>=0 // Output: base 2 exponent of x if (x!=0 && !isnan(x) && !isinf(x)) // -emax if x==0 // emax+1 otherwise int floorLog2(float x) { if(x==0.) return -emax; // NOTE: there exist values of x, for which floor(log2(x)) will give wrong // (off by one) result as compared to the one calculated with infinite precision. // Thus we do it in a brute-force way. for(int e=emax;e>=1-emax;--e) if(x>=exp2(float(e))) return e; // If we are here, x must be infinity or NaN return emax+1; } // Input: any x // Output: IEEE 754 biased exponent with bias=emax int biasedExp(float x) { return emax+floorLog2(abs(x)); } // Input: any x such that (!isnan(x) && !isinf(x)) // Output: significand AKA mantissa of x if !isnan(x) && !isinf(x) // undefined otherwise float significand(float x) { // converting int to float so that exp2(genType) gets correctly-typed value float expo=float(floorLog2(abs(x))); return abs(x)/exp2(expo); } // Input: x\in[0,1) // N>=0 // Output: Nth byte as counted from the highest byte in the fraction int part(float x,int N) { // All comments about exactness here assume that underflow and overflow don't occur const float byteShift=256.; // Multiplication is exact since it's just an increase of exponent by 8 for(int n=0;n=128) binary32.y-=128; // put lowest bit of exponent into its position, replacing just cleared integer bit binary32.y+=128*int(mod(float(e),2.)); // prepare high bits of exponent for fitting into their positions e/=2; // pack highest byte binary32.x=e+s; return binary32; } vec4 toColor(float x) { ivec4 binary32=packIEEE754binary32(x); // Transform color components to [0,1] range. // Division is inexact, but works reliably for all integers from 0 to 255 if // the transformation to TrueColor by GPU uses rounding to nearest or upwards. // The result will be multiplied by 255 back when transformed // to TrueColor subpixel value by OpenGL. return vec4(binary32)/255.; }