Pytanie Jak debugować moduł cieniujący GLSL?


Potrzebuję debugowania programu GLSL, ale nie wiem, jak wydrukować wynik pośredni. Czy możliwe jest tworzenie śladów debugowania (np. Z printf) za pomocą GLSL?


155
2018-03-24 15:11


pochodzenie


... bez korzystania z zewnętrznego oprogramowania, takiego jak glslDevil. - Franck Freiburger
Popatrz na to debugowanie wydruku zmiennych zmiennoprzecinkowych i tekstów z modułu cieniującego Fragment GLSL wystarczy pojedyncza, zapasowa jednostka teksturująca dla czcionki i stały stan wyjściowej wartości w wydrukowanym obszarze - Spektre


Odpowiedzi:


Nie można w łatwy sposób komunikować się z CPU z poziomu GLSL. Korzystanie z glslDevil lub innych narzędzi jest najlepszym rozwiązaniem.

Plik printf wymagałby próby powrotu do procesora z procesora graficznego z kodem GLSL. Zamiast tego możesz spróbować przejść do ekranu. Zamiast próbować wyprowadzać tekst, wypisz coś wizualnie wyróżniającego się na ekranie. Na przykład możesz namalować coś określonego koloru 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ą.


92
2018-03-24 17:14



Co się stanie, jeśli dokładnym powodem debugowania twojego modułu cieniującego jest fakt, że nic nie pojawia się na ekranie? - Jeroen Bollen
Dlaczego chcesz coś debugować? Ponieważ jego kod i on chce badać wartości czasu wykonywania, chciałbym ... - RichieHH
GLSL-Debugger jest open source widelcem glslDevil. - Magnus
@Magnus nie jest już aktywnie utrzymywany i obsługuje tylko GLSL do 1,20. - Ruslan


void main(){
  float bug=0.0;
  vec3 tile=texture2D(colMap, coords.st).xyz;
  vec4 col=vec4(tile, 1.0);

  if(something) bug=1.0;

  col.x+=bug;

  gl_FragColor=col;
}

50
2017-10-13 00:56



Jest to urządzenie do debugowania. Jeśli chcesz wiedzieć, gdzie znajduje się pozycja światła w scenie, na przykład: if (lpos.x> 100) bug = 1.0. Jeśli pozycja światła jest większa niż 100, scena zmieni kolor na czerwony. - ste3e
To świetna sztuczka! ;) Dzięki Stephen! - sinner


znalazłem Przekształć opinię być użytecznym narzędziem do debugowania shaderów werteksów. Możesz go użyć do przechwycenia wartości wyjść VS i odczytania ich z powrotem po stronie procesora, bez konieczności przechodzenia przez rasteryzer.

Tutaj to kolejny link do samouczka na temat Transform Feedback.


12
2017-11-23 21:11





Jeśli chcesz wizualizować wariacje wartości na ekranie, możesz użyć podobnej do tej funkcji funkcji heatmap (napisałem ją w hlsl, ale można ją łatwo dostosować do glsl):

float4 HeatMapColor(float value, float minValue, float maxValue)
{
    #define HEATMAP_COLORS_COUNT 6
    float4 colors[HEATMAP_COLORS_COUNT] =
    {
        float4(0.32, 0.00, 0.32, 1.00),
        float4(0.00, 0.00, 1.00, 1.00),
        float4(0.00, 1.00, 0.00, 1.00),
        float4(1.00, 1.00, 0.00, 1.00),
        float4(1.00, 0.60, 0.00, 1.00),
        float4(1.00, 0.00, 0.00, 1.00),
    };
    float ratio=(HEATMAP_COLORS_COUNT-1.0)*saturate((value-minValue)/(maxValue-minValue));
    float indexMin=floor(ratio);
    float indexMax=min(indexMin+1,HEATMAP_COLORS_COUNT-1);
    return lerp(colors[indexMin], colors[indexMax], ratio-indexMin);
}

Następnie w twoim cieniującym pixelu po prostu wypisujesz coś takiego:

return HeatMapColor(myValue, 0.00, 50.00);

Można się zorientować, w jaki sposób różni się on między pikselami:

enter image description here

Oczywiście możesz użyć dowolnego zestawu kolorów, które lubisz.


8
2018-04-23 07:13





GLSL Sandbox było mi bardzo przydatne dla shaderów.

Nie debugowanie jako takie (które zostało uznane za niezdolne), ale przydatne, aby szybko zobaczyć zmiany w wynikach.


5
2018-05-18 01:28





Wykonuj renderowanie w trybie offline do tekstury i oceniaj dane tekstury. Możesz znaleźć pokrewny kod, wpisując go "go to texture" opengl Następnie użyj glReadPixels, aby odczytać dane wyjściowe do tablicy i wykonać na niej potwierdzenia (ponieważ przeglądanie tak dużej tablicy w debugerze zwykle nie jest zbyt użyteczne).

Również możesz chcieć wyłączyć zaciski dla wartości wyjściowych, które nie są w zakresie od 0 do 1, co jest obsługiwane tylko dla zmiennoprzecinkowe tekstury.

Osobiście niepokoił mnie problem prawidłowego debugowania shaderów przez jakiś czas. Nie wydaje się, aby był dobry sposób - Jeśli ktoś znajdzie dobry (i nieaktualny / przestarzały) debugger, proszę dać mi znać.


2
2018-01-01 16:45



Każda odpowiedź lub komentarz, który mówi "google xyz", powinna zostać zbanowana lub odrzucona przez Stackoverflow. - gregoiregentil


Dzielę się przykładem shadera fragmentów, jak właściwie debuguję.

#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 white
    else
        sampColor = texture2D(samp, fs_in.texcoord); //else sample from original
    color = sampColor;

}

enter image description here


2
2017-10-15 09:11





Obecne odpowiedzi są dobre, ale chciałem podzielić się jeszcze jednym małym klejnotem, który był cenny przy debugowaniu trudnych problemów z precyzją w shaderze GLSL. Przy bardzo dużych liczbach int reprezentowanych jako zmiennoprzecinkowe, należy zadbać o właściwe użycie podłogi (n) i podłogi (n + 0,5) do zaokrąglenia () do dokładnej int. Możliwe jest wówczas renderowanie wartości float, która jest dokładnym int przez następującą logikę, aby spakować komponenty bajtowe do wartości wyjściowych R, G i B.

  // Break components out of 24 bit float with rounded int value
  // scaledWOB = (offset >> 8) & 0xFFFF
  float scaledWOB = floor(offset / 256.0);
  // c2 = (scaledWOB >> 8) & 0xFF
  float c2 = floor(scaledWOB / 256.0);
  // c0 = offset - (scaledWOB << 8)
  float c0 = offset - floor(scaledWOB * 256.0);
  // c1 = scaledWOB - (c2 << 8)
  float c1 = scaledWOB - floor(c2 * 256.0);

  // Normalize to byte range
  vec4 pix;  
  pix.r = c0 / 255.0;
  pix.g = c1 / 255.0;
  pix.b = c2 / 255.0;
  pix.a = 1.0;
  gl_FragColor = pix;

1
2018-05-17 18:33





U dołu tej odpowiedzi znajduje się przykład kodu GLSL, który pozwala na wyprowadzenie pełnej float wartość jako kolor, kodowanie IEEE 754 binary32. Używam go w następujący sposób (ten fragment się ujawnia yy 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 wziąć dowolny próbnik kolorów, sformatować kolor jako HTML (dodając 00 do rgb wartość, jeśli nie potrzebujesz wyższej dokładności, i wykonaj drugie podanie, aby uzyskać niższy bajt, jeśli to zrobisz), a otrzymasz szesnastkową reprezentację float jako IEEE 754 binary32.

Oto rzeczywista implementacja toColor():

const int emax=127;
// Input: x>=0
// Output: base 2 exponent of x if (x!=0 && !isnan(x) && !isinf(x))
//         -emax if x==0
//         emax+1 otherwise
int 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 NaN
    return emax+1;
}

// Input: any x
// Output: IEEE 754 biased exponent with bias=emax
int 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 otherwise
float significand(float x)
{
    // converting int to float so that exp2(genType) gets correctly-typed value
    float 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 fraction
int part(float x,int N)
{
    // All comments about exactness here assume that underflow and overflow don't occur
    const float byteShift=256.;
    // Multiplication is exact since it's just an increase of exponent by 8
    for(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 8
    float c=floor(byteShift*q);
    return int(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 7
    int s = x<0. ? 128 : 0;

    ivec4 binary32;
    binary32.yzw=significandAsIVec3(x);
    // clear the implicit integer bit of significand
    if(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.;
}

1
2018-06-26 14:54