Ich muss ein GLSL-Programm debuggen, weiß aber nicht, wie ich ein Zwischenergebnis ausgeben soll. Ist es möglich, mit GLSL einige Debug-Traces (wie bei printf) zu erstellen?
Sie können innerhalb von GLSL nicht einfach mit der CPU kommunizieren. Die Verwendung von glslDevil oder anderen Tools ist die beste Wahl.
Ein printf würde den Versuch erfordern, von der GPU, auf der der GLSL-Code ausgeführt wird, zur CPU zurückzukehren. Stattdessen können Sie versuchen, zum Display zu gelangen. Anstatt zu versuchen, Text auszugeben, geben Sie etwas visuell Unterscheidbares für den Bildschirm aus. Sie können beispielsweise nur dann eine bestimmte Farbe malen, wenn Sie den Punkt Ihres Codes erreichen, an dem Sie einen Druck hinzufügen möchten. Wenn Sie einen Wert drucken müssen, können Sie die Farbe entsprechend diesem Wert einstellen.
Es ist ein Debugging-Gerät. Wenn Sie beispielsweise wissen möchten, wo sich die Lichtposition in der Szene befindet, gehen Sie zu: if (lpos.x> 100) bug = 1.0. Wenn die Lichtposition größer als 100 ist, wird die Szene rot.
ste3e
12
Ich habe festgestellt, dass Transform Feedback ein nützliches Tool zum Debuggen von Vertex-Shadern ist. Sie können dies verwenden, um die Werte von VS-Ausgängen zu erfassen und auf der CPU-Seite zurückzulesen, ohne den Rasterizer durchlaufen zu müssen.
Hier ist ein weiterer Link zu einem Tutorial zu Transform Feedback.
Wenn Sie die Variationen eines Werts auf dem Bildschirm visualisieren möchten, können Sie eine ähnliche Heatmap-Funktion verwenden (ich habe sie in hlsl geschrieben, aber es ist einfach, sie an glsl anzupassen):
Sie können dies versuchen: https://github.com/msqrt/shader-printf , eine Implementierung, die entsprechend als "Einfache printf-Funktionalität für GLSL" bezeichnet wird.
Vielleicht möchten Sie auch ShaderToy ausprobieren und sich ein Video wie dieses ( https://youtu.be/EBrAdahFtuo ) vom YouTube-Kanal "The Art of Code" ansehen, in dem Sie einige der Techniken sehen können, die sich gut zum Debuggen eignen visualisieren. Ich kann seinen Kanal nur empfehlen, da er einige wirklich gute Sachen schreibt und er auch ein Händchen für die Präsentation komplexer Ideen in neuartigen, hochinteressanten und leicht verdaulichen Formaten hat (sein Mandelbrot-Video ist ein hervorragendes Beispiel dafür: https: // youtu.be/6IWXkV82oyY )
Ich hoffe, niemand hat etwas gegen diese späte Antwort einzuwenden, aber die Frage hat bei der Google-Suche nach GLSL-Debugging einen hohen Stellenwert und in 9 Jahren hat sich natürlich viel geändert :-)
PS: Andere Alternativen könnten auch NVIDIA nSight und AMD ShaderAnalyzer sein, die einen vollständigen Step-Debugger für Shader bieten.
Ich teile ein Fragment-Shader-Beispiel, wie ich tatsächlich debugge.
#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;}
Am Ende dieser Antwort befindet sich ein Beispiel für einen GLSL-Code, mit dem der vollständige floatWert als Farbe ausgegeben werden kann, wobei IEEE 754 codiert wird binary32. Ich benutze es wie folgt (dieses Snippet gibt eine yyKomponente der Modelview-Matrix aus):
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);
Nachdem Sie dies auf dem Bildschirm angezeigt haben, können Sie einfach einen beliebigen Farbwähler verwenden, die Farbe als HTML formatieren ( 00an den rgbWert anhängen , wenn Sie keine höhere Genauigkeit benötigen, und einen zweiten Durchgang ausführen, um das niedrigere Byte zu erhalten, wenn Sie dies tun) Sie erhalten die hexadezimale Darstellung des floatals IEEE 754 binary32.
Hier ist die tatsächliche Implementierung von 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.;}
Führen Sie ein Offline-Rendering für eine Textur durch und werten Sie die Daten der Textur aus. Sie können verwandten Code finden, indem Sie nach "Rendern in Textur" opengl googeln. Verwenden Sie dann glReadPixels, um die Ausgabe in ein Array einzulesen und Assertions darauf auszuführen (da das Durchsuchen eines so großen Arrays im Debugger normalerweise nicht wirklich nützlich ist).
Möglicherweise möchten Sie auch die Klemmung für Ausgabewerte deaktivieren, die nicht zwischen 0 und 1 liegen. Dies wird nur für Gleitkomma-Texturen unterstützt .
Ich persönlich war von dem Problem betroffen, Shader für eine Weile richtig zu debuggen. Es scheint keinen guten Weg zu geben - Wenn jemand einen guten (und nicht veralteten / veralteten) Debugger findet, lassen Sie es mich bitte wissen.
Jede Antwort oder jeder Kommentar mit der Aufschrift "google xyz" sollte von Stackoverflow gesperrt oder abgelehnt werden.
Gregoiregentil
1
Die vorhandenen Antworten sind alle gute Dinge, aber ich wollte noch ein kleines Juwel teilen, das beim Debuggen kniffliger Präzisionsprobleme in einem GLSL-Shader hilfreich war. Bei sehr großen int-Zahlen, die als Gleitkomma dargestellt werden, muss darauf geachtet werden, dass Etage (n) und Etage (n + 0,5) ordnungsgemäß verwendet werden, um round () auf eine exakte int zu implementieren. Es ist dann möglich, einen Gleitkommawert, der ein genaues int ist, durch die folgende Logik zu rendern, um die Bytekomponenten in R-, G- und B-Ausgabewerte zu packen.
Antworten:
Sie können innerhalb von GLSL nicht einfach mit der CPU kommunizieren. Die Verwendung von glslDevil oder anderen Tools ist die beste Wahl.
Ein printf würde den Versuch erfordern, von der GPU, auf der der GLSL-Code ausgeführt wird, zur CPU zurückzukehren. Stattdessen können Sie versuchen, zum Display zu gelangen. Anstatt zu versuchen, Text auszugeben, geben Sie etwas visuell Unterscheidbares für den Bildschirm aus. Sie können beispielsweise nur dann eine bestimmte Farbe malen, wenn Sie den Punkt Ihres Codes erreichen, an dem Sie einen Druck hinzufügen möchten. Wenn Sie einen Wert drucken müssen, können Sie die Farbe entsprechend diesem Wert einstellen.
quelle
quelle
Ich habe festgestellt, dass Transform Feedback ein nützliches Tool zum Debuggen von Vertex-Shadern ist. Sie können dies verwenden, um die Werte von VS-Ausgängen zu erfassen und auf der CPU-Seite zurückzulesen, ohne den Rasterizer durchlaufen zu müssen.
Hier ist ein weiterer Link zu einem Tutorial zu Transform Feedback.
quelle
Wenn Sie die Variationen eines Werts auf dem Bildschirm visualisieren möchten, können Sie eine ähnliche Heatmap-Funktion verwenden (ich habe sie in hlsl geschrieben, aber es ist einfach, sie an glsl anzupassen):
Dann geben Sie in Ihrem Pixel-Shader einfach Folgendes aus:
Und Sie können sich ein Bild davon machen, wie unterschiedlich die Pixel sind:
Natürlich können Sie jede Reihe von Farben verwenden, die Sie mögen.
quelle
GLSL Sandbox war für Shader ziemlich praktisch für mich.
Kein Debuggen an sich (was als unfähig beantwortet wurde), aber praktisch, um die Änderungen in der Ausgabe schnell zu sehen.
quelle
Sie können dies versuchen: https://github.com/msqrt/shader-printf , eine Implementierung, die entsprechend als "Einfache printf-Funktionalität für GLSL" bezeichnet wird.
Vielleicht möchten Sie auch ShaderToy ausprobieren und sich ein Video wie dieses ( https://youtu.be/EBrAdahFtuo ) vom YouTube-Kanal "The Art of Code" ansehen, in dem Sie einige der Techniken sehen können, die sich gut zum Debuggen eignen visualisieren. Ich kann seinen Kanal nur empfehlen, da er einige wirklich gute Sachen schreibt und er auch ein Händchen für die Präsentation komplexer Ideen in neuartigen, hochinteressanten und leicht verdaulichen Formaten hat (sein Mandelbrot-Video ist ein hervorragendes Beispiel dafür: https: // youtu.be/6IWXkV82oyY )
Ich hoffe, niemand hat etwas gegen diese späte Antwort einzuwenden, aber die Frage hat bei der Google-Suche nach GLSL-Debugging einen hohen Stellenwert und in 9 Jahren hat sich natürlich viel geändert :-)
PS: Andere Alternativen könnten auch NVIDIA nSight und AMD ShaderAnalyzer sein, die einen vollständigen Step-Debugger für Shader bieten.
quelle
Ich teile ein Fragment-Shader-Beispiel, wie ich tatsächlich debugge.
quelle
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, wobei IEEE 754 codiert wirdbinary32
. Ich benutze es wie folgt (dieses Snippet gibt eineyy
Komponente der Modelview-Matrix aus):Nachdem Sie dies auf dem Bildschirm angezeigt haben, können Sie einfach einen beliebigen Farbwähler verwenden, die Farbe als HTML formatieren (
00
an denrgb
Wert anhängen , wenn Sie keine höhere Genauigkeit benötigen, und einen zweiten Durchgang ausführen, um das niedrigere Byte zu erhalten, wenn Sie dies tun) Sie erhalten die hexadezimale Darstellung desfloat
als IEEE 754binary32
.Hier ist die tatsächliche Implementierung von
toColor()
:quelle
Führen Sie ein Offline-Rendering für eine Textur durch und werten Sie die Daten der Textur aus. Sie können verwandten Code finden, indem Sie nach "Rendern in Textur" opengl googeln. Verwenden Sie dann glReadPixels, um die Ausgabe in ein Array einzulesen und Assertions darauf auszuführen (da das Durchsuchen eines so großen Arrays im Debugger normalerweise nicht wirklich nützlich ist).
Möglicherweise möchten Sie auch die Klemmung für Ausgabewerte deaktivieren, die nicht zwischen 0 und 1 liegen. Dies wird nur für Gleitkomma-Texturen unterstützt .
Ich persönlich war von dem Problem betroffen, Shader für eine Weile richtig zu debuggen. Es scheint keinen guten Weg zu geben - Wenn jemand einen guten (und nicht veralteten / veralteten) Debugger findet, lassen Sie es mich bitte wissen.
quelle
Die vorhandenen Antworten sind alle gute Dinge, aber ich wollte noch ein kleines Juwel teilen, das beim Debuggen kniffliger Präzisionsprobleme in einem GLSL-Shader hilfreich war. Bei sehr großen int-Zahlen, die als Gleitkomma dargestellt werden, muss darauf geachtet werden, dass Etage (n) und Etage (n + 0,5) ordnungsgemäß verwendet werden, um round () auf eine exakte int zu implementieren. Es ist dann möglich, einen Gleitkommawert, der ein genaues int ist, durch die folgende Logik zu rendern, um die Bytekomponenten in R-, G- und B-Ausgabewerte zu packen.
quelle