J'ai besoin de déboguer un programme GLSL mais je ne sais pas comment produire 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 CPU depuis GLSL. L'utilisation de glslDevil ou d'autres outils est votre meilleur choix.
Un printf nécessiterait d'essayer de revenir au CPU à partir du GPU exécutant le code GLSL. Au lieu de cela, vous pouvez essayer d'aller de l'avant à l'écran. Au lieu d'essayer de produire du texte, affichez quelque chose de visuellement distinctif à l'écran. Par exemple, vous ne pouvez peindre quelque chose d'une couleur spécifique que si vous atteignez le point de votre code où vous souhaitez ajouter un printf. Si vous devez imprimer une valeur, vous pouvez définir la couleur en fonction de cette valeur.
C'est un périphérique de débogage. Si vous voulez savoir où se trouve la position de la lumière dans la scène, par exemple, allez: if (lpos.x> 100) bug = 1.0. Si la position de la lumière est supérieure à 100, la scène deviendra rouge.
ste3e
13
J'ai trouvé que Transform Feedback était un outil utile pour le débogage des vertex shaders. Vous pouvez l'utiliser pour capturer les valeurs des sorties VS et les relire côté CPU, sans avoir à passer par le rastériseur.
Voici un autre lien vers un didacticiel sur Transform Feedback.
Si vous souhaitez visualiser les variations d'une valeur sur l'écran, vous pouvez utiliser une fonction de heatmap similaire à celle-ci (je l'ai écrite en hlsl, mais il est facile de l'adapter à glsl):
Vous pouvez essayer ceci: https://github.com/msqrt/shader-printf qui est une implémentation appelée à juste titre «Fonctionnalité printf simple pour GLSL».
Vous pouvez également essayer ShaderToy, et peut-être regarder une vidéo comme celle-ci ( https://youtu.be/EBrAdahFtuo ) de la chaîne YouTube "The Art of Code" où vous pouvez voir certaines des techniques qui fonctionnent bien pour le débogage et visualisation. Je peux fortement recommander sa chaîne car il écrit de très bonnes choses et il a également le don de présenter des idées complexes dans des formats novateurs, très attrayants et faciles à digérer (sa vidéo de Mandelbrot en est un superbe exemple: https: // youtu.be/6IWXkV82oyY )
J'espère que personne ne se soucie de cette réponse tardive, mais la question occupe une place importante dans les recherches de Google pour le débogage GLSL et beaucoup de choses ont bien sûr changé en 9 ans :-)
PS: D'autres alternatives pourraient également être NVIDIA nSight et AMD ShaderAnalyzer qui offrent un débogueur complet pour les shaders.
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 whiteelse
sampColor = texture2D(samp, fs_in.texcoord);//else sample from original
color = sampColor;}
Au bas de cette réponse se trouve un exemple de code GLSL qui permet de sortir la floatvaleur complète en couleur, en codant IEEE 754 binary32. Je l'utilise comme suit (cet extrait donne un yycomposant de la matrice modelview):
vec4 xAsColor=toColor(gl_ModelViewMatrix[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 l'avez affiché à l'écran, vous pouvez simplement prendre n'importe quel sélecteur de couleur, formater la couleur au format HTML (en ajoutant 00à la rgbvaleur si vous n'avez pas besoin d'une précision plus élevée, et en effectuant une deuxième passe pour obtenir l'octet inférieur si vous le faites), et vous obtenez la représentation hexadécimale du floatcomme IEEE 754 binary32.
Voici la mise en œuvre réelle de toColor():
constint emax=127;// Input: x>=0// Output: base 2 exponent of x if (x!=0 && !isnan(x) && !isinf(x))// -emax if x==0// emax+1 otherwiseint 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 NaNreturn emax+1;}// Input: any x// Output: IEEE 754 biased exponent with bias=emaxint 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 otherwisefloat significand(float x){// converting int to float so that exp2(genType) gets correctly-typed valuefloat 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 fractionint part(float x,int N){// All comments about exactness here assume that underflow and overflow don't occurconstfloat byteShift=256.;// Multiplication is exact since it's just an increase of exponent by 8for(int n=0;n<N;++n)
x*=byteShift;// Cut higher bits away.// $q \in [0,1) \cap \mathbb Q'.$float q=fract(x);// Shift and cut lower bits away. Cutting lower bits prevents potentially unexpected// results of rounding by the GPU later in the pipeline when transforming to TrueColor// the resulting subpixel value.// $c \in [0,255] \cap \mathbb Z.$// Multiplication is exact since it's just and increase of exponent by 8float c=floor(byteShift*q);returnint(c);}// Input: any x acceptable to significand()// Output: significand of x split to (8,8,8)-bit data vector
ivec3 significandAsIVec3(float x){
ivec3 result;float sig=significand(x)/2.;// shift all bits to fractional part
result.x=part(sig,0);
result.y=part(sig,1);
result.z=part(sig,2);return result;}// Input: any x such that !isnan(x)// Output: IEEE 754 defined binary32 number, packed as ivec4(byte3,byte2,byte1,byte0)
ivec4 packIEEE754binary32(float x){int e = biasedExp(x);// sign to bit 7int s = x<0.?128:0;
ivec4 binary32;
binary32.yzw=significandAsIVec3(x);// clear the implicit integer bit of significandif(binary32.y>=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.;}
Effectuez un rendu hors ligne sur une texture et évaluez les données de la texture. Vous pouvez trouver le code associé en recherchant sur Google "render to texture" opengl Ensuite, utilisez glReadPixels pour lire la sortie dans un tableau et effectuer des assertions dessus (car regarder à travers un si grand tableau dans le débogueur n'est généralement pas vraiment utile).
Vous pouvez également désactiver le verrouillage pour afficher des valeurs qui ne sont pas comprises entre 0 et 1, ce qui n'est pris en charge que pour les textures à virgule flottante .
J'ai personnellement été gêné 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), veuillez me le faire savoir.
Toute réponse ou tout commentaire indiquant "google xyz" doit être banni ou rejeté de Stackoverflow.
gregoiregentil
1
Les réponses existantes sont toutes bonnes, mais je voulais partager un autre petit bijou qui a été précieux dans le débogage de 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 prendre soin d'utiliser correctement floor (n) et floor (n + 0.5) pour implémenter round () à un int exact. Il est alors possible de restituer une valeur flottante qui est un entier exact par la logique suivante pour regrouper les composants d'octets en valeurs de sortie R, V et B.
Réponses:
Vous ne pouvez pas facilement communiquer avec le CPU depuis GLSL. L'utilisation de glslDevil ou d'autres outils est votre meilleur choix.
Un printf nécessiterait d'essayer de revenir au CPU à partir du GPU exécutant le code GLSL. Au lieu de cela, vous pouvez essayer d'aller de l'avant à l'écran. Au lieu d'essayer de produire du texte, affichez quelque chose de visuellement distinctif à l'écran. Par exemple, vous ne pouvez peindre quelque chose d'une couleur spécifique que si vous atteignez le point de votre code où vous souhaitez ajouter un printf. Si vous devez imprimer une valeur, vous pouvez définir la couleur en fonction de cette valeur.
la source
la source
J'ai trouvé que Transform Feedback était un outil utile pour le débogage des vertex shaders. Vous pouvez l'utiliser pour capturer les valeurs des sorties VS et les relire côté CPU, sans avoir à passer par le rastériseur.
Voici un autre lien vers un didacticiel sur Transform Feedback.
la source
Si vous souhaitez visualiser les variations d'une valeur sur l'écran, vous pouvez utiliser une fonction de heatmap similaire à celle-ci (je l'ai écrite en hlsl, mais il est facile de l'adapter à glsl):
Ensuite, dans votre pixel shader, vous sortez simplement quelque chose comme:
Et pouvez avoir une idée de la façon dont cela varie à travers vos pixels:
Bien sûr, vous pouvez utiliser n'importe quel jeu de couleurs que vous aimez.
la source
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 rapidement les changements de sortie.
la source
Vous pouvez essayer ceci: https://github.com/msqrt/shader-printf qui est une implémentation appelée à juste titre «Fonctionnalité printf simple pour GLSL».
Vous pouvez également essayer ShaderToy, et peut-être regarder une vidéo comme celle-ci ( https://youtu.be/EBrAdahFtuo ) de la chaîne YouTube "The Art of Code" où vous pouvez voir certaines des techniques qui fonctionnent bien pour le débogage et visualisation. Je peux fortement recommander sa chaîne car il écrit de très bonnes choses et il a également le don de présenter des idées complexes dans des formats novateurs, très attrayants et faciles à digérer (sa vidéo de Mandelbrot en est un superbe exemple: https: // youtu.be/6IWXkV82oyY )
J'espère que personne ne se soucie de cette réponse tardive, mais la question occupe une place importante dans les recherches de Google pour le débogage GLSL et beaucoup de choses ont bien sûr changé en 9 ans :-)
PS: D'autres alternatives pourraient également être NVIDIA nSight et AMD ShaderAnalyzer qui offrent un débogueur complet pour les shaders.
la source
Je partage un exemple de fragment shader, comment je débogue réellement.
la source
Au bas de cette réponse se trouve un exemple de code GLSL qui permet de sortir la
float
valeur complète en couleur, en codant IEEE 754binary32
. Je l'utilise comme suit (cet extrait donne unyy
composant de la matrice modelview):Une fois que vous l'avez affiché à l'écran, vous pouvez simplement prendre n'importe quel sélecteur de couleur, formater la couleur au format HTML (en ajoutant
00
à largb
valeur si vous n'avez pas besoin d'une précision plus élevée, et en effectuant une deuxième passe pour obtenir l'octet inférieur si vous le faites), et vous obtenez la représentation hexadécimale dufloat
comme IEEE 754binary32
.Voici la mise en œuvre réelle de
toColor()
:la source
Effectuez un rendu hors ligne sur une texture et évaluez les données de la texture. Vous pouvez trouver le code associé en recherchant sur Google "render to texture" opengl Ensuite, utilisez glReadPixels pour lire la sortie dans un tableau et effectuer des assertions dessus (car regarder à travers un si grand tableau dans le débogueur n'est généralement pas vraiment utile).
Vous pouvez également désactiver le verrouillage pour afficher des valeurs qui ne sont pas comprises entre 0 et 1, ce qui n'est pris en charge que pour les textures à virgule flottante .
J'ai personnellement été gêné 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), veuillez me le faire savoir.
la source
Les réponses existantes sont toutes bonnes, mais je voulais partager un autre petit bijou qui a été précieux dans le débogage de 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 prendre soin d'utiliser correctement floor (n) et floor (n + 0.5) pour implémenter round () à un int exact. Il est alors possible de restituer une valeur flottante qui est un entier exact par la logique suivante pour regrouper les composants d'octets en valeurs de sortie R, V et B.
la source