Potrzebuję debugować program GLSL, ale nie wiem, jak wyprowadzić wynik pośredni. Czy można zrobić jakieś ślady debugowania (jak w printf) za pomocą GLSL?
Nie można łatwo komunikować się z powrotem z procesorem z poziomu GLSL. Używanie glslDevil lub innych narzędzi jest najlepszym wyborem.
Printf wymagałby próby powrotu do procesora z GPU z uruchomionym kodem GLSL. Zamiast tego możesz spróbować przesunąć się do przodu. Zamiast próbować wyprowadzać tekst, wypisuj na ekranie coś wizualnie charakterystycznego. Na przykład możesz pomalować coś w określonym kolorze tylko wtedy, gdy osiągniesz punkt kodu, w którym chcesz dodać printf. Jeśli chcesz wydrukować wartość, możesz ustawić kolor zgodnie z tą wartością.
To urządzenie do debugowania. Jeśli chcesz na przykład wiedzieć, gdzie jest pozycja światła w scenie, przejdź: if (lpos.x> 100) bug = 1.0. Jeśli pozycja światła jest większa niż 100, scena zmieni kolor na czerwony.
ste3e
13
Znalazłem informacje zwrotne dotyczące transformacji jest użytecznym narzędziem do debugowania shaderów wierzchołków. Możesz użyć tego do przechwycenia wartości wyjść VS i odczytania ich z powrotem po stronie procesora, bez konieczności przechodzenia przez rasterizer.
Oto kolejny link do samouczka na temat przekształcania opinii.
Jeśli chcesz wizualizować warianty wartości na ekranie, możesz użyć funkcji Heatmap podobnej do tej (napisałem ją w hlsl, ale łatwo ją dostosować do glsl):
Możesz także wypróbować ShaderToy, a może obejrzeć film taki jak ten ( https://youtu.be/EBrAdahFtuo ) z kanału YouTube „The Art of Code”, gdzie możesz zobaczyć niektóre techniki, które sprawdzają się przy debugowaniu i wizualizacja. Mogę zdecydowanie polecić jego kanał, ponieważ pisze naprawdę dobre rzeczy, a także ma talent do prezentowania złożonych pomysłów w nowatorskich, bardzo angażujących i łatwych do strawienia formatach (jego film Mandelbrot jest doskonałym przykładem tego: https: // youtu.be/6IWXkV82oyY )
Mam nadzieję, że nikomu nie przeszkadza ta późna odpowiedź, ale pytanie to zajmuje wysokie miejsce w wyszukiwaniach Google dotyczących debugowania GLSL i wiele się zmieniło od 9 lat :-)
PS: Innymi alternatywami mogą być również NVIDIA nSight i AMD ShaderAnalyzer, które oferują pełny krok debuggera dla shaderów.
Udostępniam przykład modułu cieniującego fragmenty, w jaki sposób faktycznie debugowałem.
#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;}
Na dole tej odpowiedzi znajduje się przykład kodu GLSL, który pozwala na wyświetlenie pełnej floatwartości w kolorze, kodując IEEE 754 binary32. Używam go w następujący sposób (ten fragment yyujawnia składnik macierzy widoku modelu):
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);
Po wyświetleniu tego na ekranie możesz po prostu wybrać dowolny próbnik kolorów, sformatować kolor jako HTML (dołączając 00do rgbwartości, jeśli nie potrzebujesz większej precyzji, i wykonując drugie przejście, aby uzyskać niższy bajt, jeśli to zrobisz), i otrzymasz szesnastkową reprezentację floatjako IEEE 754 binary32.
Oto faktyczna realizacja 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.;}
Wykonaj renderowanie offline dla tekstury i oceń dane tekstury. Możesz znaleźć pokrewny kod, przechodząc do „renderowania do tekstury” opengl Następnie użyj glReadPixels, aby odczytać dane wyjściowe do tablicy i wykonać na nim asercje (ponieważ przeglądanie tak dużej tablicy w debuggerze zwykle nie jest zbyt przydatne).
Możesz także chcieć wyłączyć zaciskanie do wartości wyjściowych, które nie mieszczą się w zakresie od 0 do 1, co jest obsługiwane tylko dla tekstur zmiennoprzecinkowych .
Osobiście niepokoiło mnie przez pewien czas problem z poprawnym debugowaniem shaderów. Wydaje się, że nie ma dobrego sposobu - jeśli ktoś znajdzie dobry (i nie przestarzały / przestarzały) debugger, daj mi znać.
Każda odpowiedź lub komentarz, który mówi „google xyz”, powinna zostać zbanowana lub odrzucona z Stackoverflow.
gregoiregentil
1
Wszystkie istniejące odpowiedzi są dobre, ale chciałem podzielić się jeszcze jednym małym klejnotem, który był cenny w debugowaniu trudnych problemów z precyzją w module cieniującym GLSL. Z bardzo dużymi liczbami całkowitymi reprezentowanymi jako zmiennoprzecinkowe, należy zadbać o prawidłowe użycie floor (n) i floor (n + 0,5), aby zaimplementować round () do dokładnej int. Możliwe jest wówczas wyrenderowanie wartości zmiennoprzecinkowej, która jest dokładną int, za pomocą następującej logiki, aby spakować komponenty bajtów do wartości wyjściowych R, G i B.
Odpowiedzi:
Nie można łatwo komunikować się z powrotem z procesorem z poziomu GLSL. Używanie glslDevil lub innych narzędzi jest najlepszym wyborem.
Printf wymagałby próby powrotu do procesora z GPU z uruchomionym kodem GLSL. Zamiast tego możesz spróbować przesunąć się do przodu. Zamiast próbować wyprowadzać tekst, wypisuj na ekranie coś wizualnie charakterystycznego. Na przykład możesz pomalować coś w określonym kolorze tylko wtedy, gdy osiągniesz punkt kodu, w którym chcesz dodać printf. Jeśli chcesz wydrukować wartość, możesz ustawić kolor zgodnie z tą wartością.
źródło
źródło
Znalazłem informacje zwrotne dotyczące transformacji jest użytecznym narzędziem do debugowania shaderów wierzchołków. Możesz użyć tego do przechwycenia wartości wyjść VS i odczytania ich z powrotem po stronie procesora, bez konieczności przechodzenia przez rasterizer.
Oto kolejny link do samouczka na temat przekształcania opinii.
źródło
Jeśli chcesz wizualizować warianty wartości na ekranie, możesz użyć funkcji Heatmap podobnej do tej (napisałem ją w hlsl, ale łatwo ją dostosować do glsl):
Następnie w swoim module cieniującym wyświetlasz po prostu coś takiego:
I może zorientować się, jak zmienia się on w poszczególnych pikselach:
Oczywiście możesz użyć dowolnego zestawu kolorów, który ci się podoba.
źródło
GLSL Sandbox był bardzo przydatny dla shaderów.
Nie jest to samo debugowanie (na które odpowiedziano jako niezdolne), ale przydatne, aby szybko zobaczyć zmiany w wynikach.
źródło
Możesz spróbować: https://github.com/msqrt/shader-printf, która jest implementacją o nazwie odpowiednio „Prosta funkcjonalność printf dla GLSL”.
Możesz także wypróbować ShaderToy, a może obejrzeć film taki jak ten ( https://youtu.be/EBrAdahFtuo ) z kanału YouTube „The Art of Code”, gdzie możesz zobaczyć niektóre techniki, które sprawdzają się przy debugowaniu i wizualizacja. Mogę zdecydowanie polecić jego kanał, ponieważ pisze naprawdę dobre rzeczy, a także ma talent do prezentowania złożonych pomysłów w nowatorskich, bardzo angażujących i łatwych do strawienia formatach (jego film Mandelbrot jest doskonałym przykładem tego: https: // youtu.be/6IWXkV82oyY )
Mam nadzieję, że nikomu nie przeszkadza ta późna odpowiedź, ale pytanie to zajmuje wysokie miejsce w wyszukiwaniach Google dotyczących debugowania GLSL i wiele się zmieniło od 9 lat :-)
PS: Innymi alternatywami mogą być również NVIDIA nSight i AMD ShaderAnalyzer, które oferują pełny krok debuggera dla shaderów.
źródło
Udostępniam przykład modułu cieniującego fragmenty, w jaki sposób faktycznie debugowałem.
źródło
Na dole tej odpowiedzi znajduje się przykład kodu GLSL, który pozwala na wyświetlenie pełnej
float
wartości w kolorze, kodując IEEE 754binary32
. Używam go w następujący sposób (ten fragmentyy
ujawnia składnik macierzy widoku modelu):Po wyświetleniu tego na ekranie możesz po prostu wybrać dowolny próbnik kolorów, sformatować kolor jako HTML (dołączając
00
dorgb
wartości, jeśli nie potrzebujesz większej precyzji, i wykonując drugie przejście, aby uzyskać niższy bajt, jeśli to zrobisz), i otrzymasz szesnastkową reprezentacjęfloat
jako IEEE 754binary32
.Oto faktyczna realizacja
toColor()
:źródło
Wykonaj renderowanie offline dla tekstury i oceń dane tekstury. Możesz znaleźć pokrewny kod, przechodząc do „renderowania do tekstury” opengl Następnie użyj glReadPixels, aby odczytać dane wyjściowe do tablicy i wykonać na nim asercje (ponieważ przeglądanie tak dużej tablicy w debuggerze zwykle nie jest zbyt przydatne).
Możesz także chcieć wyłączyć zaciskanie do wartości wyjściowych, które nie mieszczą się w zakresie od 0 do 1, co jest obsługiwane tylko dla tekstur zmiennoprzecinkowych .
Osobiście niepokoiło mnie przez pewien czas problem z poprawnym debugowaniem shaderów. Wydaje się, że nie ma dobrego sposobu - jeśli ktoś znajdzie dobry (i nie przestarzały / przestarzały) debugger, daj mi znać.
źródło
Wszystkie istniejące odpowiedzi są dobre, ale chciałem podzielić się jeszcze jednym małym klejnotem, który był cenny w debugowaniu trudnych problemów z precyzją w module cieniującym GLSL. Z bardzo dużymi liczbami całkowitymi reprezentowanymi jako zmiennoprzecinkowe, należy zadbać o prawidłowe użycie floor (n) i floor (n + 0,5), aby zaimplementować round () do dokładnej int. Możliwe jest wówczas wyrenderowanie wartości zmiennoprzecinkowej, która jest dokładną int, za pomocą następującej logiki, aby spakować komponenty bajtów do wartości wyjściowych R, G i B.
źródło