Beim Schreiben nicht-trivialer Shader (genau wie beim Schreiben eines anderen nicht-trivialen Codes) machen die Leute Fehler. [Bearbeiten] Ich kann aber nicht einfach debuggen wie jeder andere Code - Sie können nicht nur gdb anhängen oder das Visual Studio - Debugger , nachdem alle. Sie können nicht einmal printf debuggen, da es keine Form der Konsolenausgabe gibt. Normalerweise rendere ich die Daten, die ich betrachten möchte, als Farbe, aber das ist eine sehr rudimentäre und amateurhafte Lösung. Ich bin sicher, die Leute haben bessere Lösungen gefunden.
Wie kann ich einen Shader tatsächlich debuggen? Gibt es eine Möglichkeit, durch einen Shader zu treten? Kann ich mir die Ausführung des Shaders auf einem bestimmten Vertex / Primitiv / Fragment ansehen?
(Diese Frage bezieht sich speziell auf das Debuggen von Shader-Code, ähnlich wie man "normalen" Code debuggen würde, und nicht auf das Debuggen von Dingen wie Statusänderungen.)
Antworten:
Soweit mir bekannt ist, gibt es keine Tools, mit denen Sie in einem Shader durch den Code navigieren können (auch wenn Sie in diesem Fall nur einen Pixel / Vertex auswählen müssen, den Sie "debuggen" möchten, ist die Ausführung wahrscheinlich variieren je nachdem).
Was ich persönlich mache, ist ein sehr hackiges "buntes Debugging". Also streue ich ein paar dynamische Äste mit
#if DEBUG / #endif
Wachen, die im Grunde genommen sagenAuf diese Weise können Sie Debug-Informationen "beobachten". Normalerweise mache ich verschiedene Tricks wie Lerping oder Mischen zwischen verschiedenen "Farbcodes", um verschiedene komplexere Ereignisse oder nicht-binäre Dinge zu testen.
In diesem "Rahmen" finde ich es auch nützlich, eine Reihe von festen Konventionen für häufig vorkommende Fälle zu haben, damit ich nicht ständig zurückgehen und überprüfen muss, welche Farbe ich mit welcher assoziiert habe. Das Wichtigste ist, eine gute Unterstützung für das Hot-Reload von Shader-Code zu haben, sodass Sie Ihre verfolgten Daten / Ereignisse fast interaktiv ändern und die Debug-Visualisierung einfach ein- und ausschalten können.
Wenn Sie Fehler beheben müssen, die nicht einfach auf dem Bildschirm angezeigt werden können, können Sie immer dasselbe tun und ein Frame-Analysetool verwenden, um Ihre Ergebnisse zu überprüfen. Ich habe einige von ihnen als Antwort auf diese andere Frage aufgelistet .
Es versteht sich von selbst, dass ich, wenn ich keinen Pixel-Shader oder Compute-Shader "debugge", diese "debugColor" -Information in der gesamten Pipeline weitergebe, ohne sie zu interpolieren (in GLSL mit
flat
Schlüsselwort).Auch dies ist sehr hackig und weit davon entfernt, das richtige Debuggen durchzuführen, aber ich bin fest davon überzeugt, dass ich keine richtige Alternative kenne.
quelle
Es gibt auch einen GLSL-Debugger . Es ist ein Debugger, der früher als "GLSL Devil" bekannt war.
Der Debugger selbst ist nicht nur für GLSL-Code, sondern auch für OpenGL selbst sehr praktisch. Sie haben die Möglichkeit, zwischen Zeichnungsaufrufen zu wechseln und Shader-Schalter zu deaktivieren. Außerdem werden Fehlermeldungen angezeigt, die von OpenGL an die Anwendung selbst zurückgemeldet werden.
quelle
Es gibt verschiedene Angebote von GPU-Anbietern wie AMDs CodeXL oder NVIDIAs nSight / Linux GFX-Debugger, die das Durchlaufen von Shadern ermöglichen, jedoch an die Hardware des jeweiligen Anbieters gebunden sind.
Lassen Sie mich bemerken, dass ich, obwohl sie unter Linux verfügbar sind, dort immer nur sehr wenig Erfolg hatte. Ich kann die Situation unter Windows nicht kommentieren.
Die Option, die ich kürzlich verwendet habe, besteht darin, meinen Shader-Code über zu modularisieren
#includes
und den enthaltenen Code auf eine gemeinsame Teilmenge von GLSL und C ++ & glm zu beschränken .Wenn ich auf ein Problem stoße, versuche ich, es auf einem anderen Gerät zu reproduzieren, um festzustellen, ob das Problem dasselbe ist, was auf einen logischen Fehler hinweist (anstelle eines Treiberproblems / undefinierten Verhaltens). Es besteht auch die Möglichkeit, dass falsche Daten an die GPU übergeben werden (z. B. durch falsch gebundene Puffer usw.). Dies schließe ich normalerweise aus, indem ich wie in cifz answer ein Debugging durchführe oder die Daten per Apitrace überprüfe .
Wenn es sich um einen logischen Fehler handelt, versuche ich, die Situation von der GPU auf der CPU wiederherzustellen, indem ich den enthaltenen Code auf der CPU mit denselben Daten aufrufe. Dann kann ich es auf CPU durchlaufen.
Aufbauend auf der Modularität des Codes können Sie auch versuchen, Unittest dafür zu schreiben und die Ergebnisse zwischen einem GPU-Lauf und einem CPU-Lauf zu vergleichen. Sie müssen sich jedoch bewusst sein, dass es Eckfälle gibt, in denen sich C ++ möglicherweise anders als GLSL verhält, sodass Sie bei diesen Vergleichen falsch positive Ergebnisse erhalten.
Wenn Sie das Problem nicht auf einem anderen Gerät reproduzieren können, können Sie nur herausfinden, woher der Unterschied stammt. Mit Unittests können Sie möglicherweise eingrenzen, wo dies geschieht. Am Ende müssen Sie jedoch möglicherweise zusätzliche Debug-Informationen vom Shader wie in cifz answer ausschreiben .
Und um Ihnen einen Überblick zu geben, hier ein Flussdiagramm meines Debugging-Prozesses:
Abgerundet wird dies hier durch eine Liste zufälliger Vor- und Nachteile:
Profi
con
quelle
Es scheint zwar nicht möglich zu sein, einen OpenGL-Shader tatsächlich zu durchlaufen, es ist jedoch möglich, die Kompilierungsergebnisse abzurufen.
Das Folgende ist aus dem Android Cardboard Sample entnommen .
Wenn Ihr Code ordnungsgemäß kompiliert wurde, haben Sie keine andere Wahl, als den Status des Programms auf andere Weise zu kommunizieren. Sie können signalisieren, dass ein Teil des Codes erreicht wurde, indem Sie beispielsweise die Farbe eines Scheitelpunkts ändern oder eine andere Textur verwenden. Was umständlich ist, aber vorerst der einzige Weg zu sein scheint.
EDIT: Für WebGL schaue ich mir dieses Projekt an , aber ich habe es gerade erst gefunden ... kann nicht dafür bürgen.
quelle
Dies ist eine Kopie meiner Antwort auf die gleiche Frage bei StackOverflow .
Am Ende dieser Antwort befindet sich ein Beispiel für einen GLSL-Code, mit dem der vollständige
float
Wert als Farbe ausgegeben werden kann und der IEEE 754 codiertbinary32
. Ich benutze es wie folgt (dieses Snippet gibt eineyy
Komponente der Modelview-Matrix aus):Nachdem Sie dies auf dem Bildschirm erhalten haben, können Sie einfach eine beliebige Farbauswahl treffen, die Farbe als HTML formatieren (
00
an denrgb
Wert anhängen , wenn Sie keine höhere Genauigkeit benötigen, und einen zweiten Durchgang durchführen, um das niedrigere Byte zu erhalten, wenn Sie dies tun) und Sie erhalten die hexadezimale Darstellung desfloat
als IEEE 754binary32
.Hier ist die tatsächliche Implementierung von
toColor()
:quelle
Die Lösung, die für mich funktioniert hat, ist die Kompilierung von Shader-Code in C ++ - wie von Nobody erwähnt. Es hat sich als sehr effizient erwiesen, wenn an einem komplexen Code gearbeitet wurde, obwohl einige Einstellungen erforderlich sind.
Ich habe hauptsächlich mit HLSL-Compute-Shadern gearbeitet, für die ich eine Proof-of-Concept-Bibliothek entwickelt habe, die hier verfügbar ist:
https://github.com/cezbloch/shaderator
Auf einem Compute Shader aus DirectX SDK-Beispielen wird gezeigt, wie Sie C ++ - ähnliches HLSL-Debugging aktivieren und Unit-Tests einrichten.
Die Kompilierung des GLSL-Compute-Shaders in C ++ ist einfacher als die von HLSL. Hauptsächlich aufgrund von Syntaxkonstruktionen in HLSL. Ich habe ein triviales Beispiel für einen ausführbaren Unit-Test auf einem GLSL-Ray-Tracer-Compute-Shader hinzugefügt, den Sie auch in den Quellen des Shaderator-Projekts unter dem obigen Link finden.
quelle