Lorsque vous écrivez des shaders non triviaux (comme pour tout autre élément de code non trivial), les gens font des erreurs. [la citation nécessaire] Cependant, je ne peux pas simplement le déboguer comme n'importe quel autre code - vous ne pouvez pas attacher simplement gdb ou le débogueur de Visual Studio après tout. Vous ne pouvez même pas faire de débogage printf, car il n’existe aucune forme de sortie de console. Ce que je fais habituellement, c'est rendre les données que je veux voir en couleur, mais c'est une solution très rudimentaire et amateur. Je suis sûr que les gens ont proposé de meilleures solutions.
Alors, comment puis-je déboguer un shader? Existe-t-il un moyen de parcourir un shader? Puis-je regarder l'exécution du shader sur un sommet / primitif / fragment spécifique?
(Cette question porte spécifiquement sur la façon de déboguer le code shader de la même manière que pour déboguer du code "normal", et non sur le débogage d'éléments tels que les changements d'état.)
Réponses:
Pour autant que je sache, aucun outil ne vous permet de parcourir le code dans un shader (dans ce cas également, vous devrez pouvoir sélectionner uniquement un pixel / sommet que vous souhaitez "déboguer", l'exécution risque fort de varient en fonction de cela).
Ce que je fais personnellement est un "débogage coloré" très fastidieux. Donc, je saupoudre un tas de branches dynamiques avec des
#if DEBUG / #endif
gardes qui disent essentiellementAinsi, vous pouvez "observer" les informations de débogage de cette façon. Je fais habituellement diverses astuces, comme lerping ou mélange entre différents "codes de couleur" pour tester divers événements plus complexes ou des éléments non binaires.
Dans ce "cadre", je trouve également utile d’avoir un ensemble de conventions fixes pour les cas courants afin que, si je n’ai pas à revenir constamment en arrière et vérifier quelle couleur j’ai associée à quoi. L'important est d'avoir un bon support pour le rechargement à chaud du code shader, de sorte que vous puissiez modifier de manière presque interactive vos données / événements suivis et activer / désactiver facilement la visualisation de débogage.
Si vous avez besoin de déboguer quelque chose que vous ne pouvez pas afficher facilement à l'écran, vous pouvez toujours en faire de même et utiliser un analyseur à cadre unique pour inspecter vos résultats. J'ai énuméré quelques-uns d'entre eux comme réponse à cette autre question.
Bien sûr, il va sans dire que si je ne "débogue" pas un pixel shader ou un calcul shader, je transmets cette information "debugColor" à travers le pipeline sans l'interpoler (en GLSL avec
flat
mot clé).Encore une fois, c’est très hacky et loin d’être un bon débogage, mais c’est ce qui m’empêche de ne pas connaître d’alternative appropriée.
la source
Il y a aussi GLSL-Debugger . C'est un débogueur qui s'appelait auparavant "GLSL Devil".
Le débogueur lui-même est très pratique non seulement pour le code GLSL, mais également pour OpenGL. Vous avez la possibilité de passer d'un appel à un autre à un interrupteur Shader. Il affiche également les messages d'erreur communiqués par OpenGL à l'application elle-même.
la source
Il existe plusieurs offres de fournisseurs de GPU, telles que CodeXL d’AMD ou le débogueur nSight / Linux GFX de NVIDIA, qui permettent de passer à travers les shaders mais qui sont liées au matériel du fournisseur respectif.
Permettez-moi de noter que, bien qu’ils soient disponibles sous Linux, j’ai toujours eu très peu de succès à les utiliser là-bas. Je ne peux pas commenter la situation sous Windows.
L’option que j’ai récemment utilisée est de modulariser mon code de shader via
#includes
et de limiter le code inclus à un sous-ensemble commun de GLSL et C ++ & glm .Lorsque je rencontre un problème, j'essaie de le reproduire sur un autre périphérique pour voir si le problème est identique, ce qui laisse supposer une erreur de logique (au lieu d'un problème de pilote / comportement non défini). Il existe également un risque de transmission de données erronées au GPU (par exemple, par des tampons mal liés, etc.) que j’élimine généralement en déboguant la sortie comme dans cifz answer ou en inspectant les données via apitrace .
Lorsqu'il s'agit d'une erreur de logique, j'essaie de reconstruire la situation à partir du GPU sur la CPU en appelant le code inclus sur la CPU avec les mêmes données. Ensuite, je peux le parcourir sur le processeur.
En vous appuyant sur la modularité du code, vous pouvez également essayer d'écrire unittest pour lui et comparer les résultats entre une exécution GPU et une exécution CPU. Cependant, vous devez savoir qu'il existe des cas où C ++ pourrait se comporter différemment du GLSL, vous donnant ainsi de faux positifs lors de ces comparaisons.
Enfin, lorsque vous ne pouvez pas reproduire le problème sur un autre périphérique, vous ne pouvez que commencer à comprendre d'où vient la différence. Unittests peut vous aider à préciser où cela se produit mais à la fin, vous aurez probablement besoin d'écrire des informations de débogage supplémentaires à partir du shader, comme dans cifz answer .
Et pour vous donner un aperçu, voici un organigramme de mon processus de débogage:
Pour terminer, voici une liste des avantages et inconvénients aléatoires:
pro
con
la source
Bien qu'il ne semble pas possible de parcourir un shader OpenGL, il est possible d'obtenir les résultats de la compilation.
Ce qui suit est tiré de l' exemple de carton Android .
Si votre code est compilé correctement, vous n'avez alors pas d'autre choix que d'essayer une autre façon de vous communiquer l'état du programme. Vous pouvez indiquer qu'une partie du code a été atteinte, par exemple en modifiant la couleur d'un sommet ou en utilisant une texture différente. Ce qui est maladroit, mais semble être le seul moyen pour le moment.
EDIT: Pour WebGL, je regarde ce projet , mais je viens juste de le trouver ... je ne peux pas le garantir.
la source
Ceci est un copier-coller de ma réponse à la même question chez StackOverflow .
Au bas de cette réponse se trouve un exemple de code GLSL qui permet de générer la
float
valeur complète en couleur, codant pour IEEE 754binary32
. Je l'utilise comme suit (cet extrait donne leyy
composant de la matrice modelview):Une fois que vous obtenez ceci à l’écran, vous pouvez 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 supérieure, 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 de lafloat
comme IEEE 754binary32
.Voici l'implémentation réelle de
toColor()
:la source
La solution qui a fonctionné pour moi est la compilation du code shader en C ++ - comme mentionné par Nobody. Il s’est avéré très efficace lorsque vous travaillez sur un code complexe même s’il nécessite un peu de configuration.
Je travaille principalement avec HLSL Compute Shaders pour lequel j'ai développé une bibliothèque de démonstration de concept disponible ici:
https://github.com/cezbloch/shaderator
Il explique sur un Compute Shader à partir d’exemples DirectX SDK, comment activer le débogage HLSL en C ++ et comment configurer des tests unitaires.
La compilation du calcul GLSL en C ++ semble plus facile que HLSL. Principalement en raison de constructions de syntaxe en HLSL. J'ai ajouté un exemple trivial de test unitaire exécutable sur un compilateur Shader GLSL que vous pouvez également trouver dans les sources du projet Shaderator sous le lien ci-dessus.
la source