2010-03-24 12 views
150

Necesito depurar un programa GLSL pero no sé cómo dar salida al resultado intermedio. ¿Es posible hacer algunas huellas de depuración (como con printf) con GLSL?Cómo depurar un sombreador GLSL?

+6

... sin necesidad de utilizar software externo como glslDevil. –

+0

eche un vistazo a esto [impresión de depuración de variables de flotación y textos del sombreador de Fragmentos GLSL] (https://stackoverflow.com/a/44797902/2521214) solo necesita una unidad de textura de repuesto única para fuente y estado constante de valor superado en área impresa – Spektre

Respuesta

90

No se puede volver a comunicar fácilmente a la CPU desde dentro de GLSL. Usar glslDevil u otras herramientas es su mejor opción.

Un printf requeriría intentar volver a la CPU desde la GPU que ejecuta el código GLSL. En cambio, puede intentar avanzar hacia la pantalla. En lugar de intentar emitir texto, muestra algo visualmente distintivo de la pantalla. Por ejemplo, puede pintar algo de un color específico solo si llega al punto de su código donde desea agregar un printf. Si necesita imprimir un valor, puede establecer el color de acuerdo con ese valor.

+24

¿Qué sucede si la razón exacta por la que desea depurar el sombreador es porque no aparece nada en la pantalla? –

+5

¿Por qué querrías depurar algo? Debido a que su código y él quiere examinar los valores de tiempo de ejecución me arriesgaría .... – RichieHH

+3

[GLSL-Debugger] (http://glsl-debugger.github.io/) es una bifurcación de código abierto de glslDevil. – Magnus

2

Realice la reproducción sin conexión a una textura y evalúe los datos de la textura. Puede encontrar el código relacionado buscando en Google para "renderizar a textura" opengl Luego use glReadPixels para leer el resultado en una matriz y realizar afirmaciones en ella (ya que mirar a través de una matriz tan grande en el depurador generalmente no es realmente útil).

También es posible que desee deshabilitar la fijación a valores de salida que no están entre 0 y 1, que solo es compatible con floating point textures.

Personalmente, me molestó el problema de depurar correctamente los sombreadores por un tiempo. No parece haber una buena manera: si alguien encuentra un buen depurador (y no desactualizado/obsoleto), házmelo saber.

+1

Cualquier respuesta o comentario que diga "google xyz" debe ser rechazada o rechazada por Stackoverflow. – gregoiregentil

48
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; 
} 
+7

Es un dispositivo de depuración. Si quiere saber dónde está la posición de luz en la escena, por ejemplo, vaya: if (lpos.x> 100) bug = 1.0. Si la posición de luz es mayor que 100, la escena se volverá roja. – ste3e

+0

¡Eso es un gran truco! ;) Gracias Stephen! – sinner

12

He encontrado Transform Feedback para ser una herramienta útil para la depuración vertex shaders. Puede usar esto para capturar los valores de las salidas VS y leerlas en el lado de la CPU, sin tener que pasar por el rasterizador.

Here es otro enlace a un tutorial sobre Transform Feedback.

2

Estoy compartiendo un ejemplo de sombreador de fragmentos, como realmente lo depuro.

#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

7

Si quiere visualizar las variaciones de un valor a través de la pantalla, puede utilizar una función de mapa de calor similar a esto (lo escribí en HLSL, pero es fácil de adaptar a 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); 
} 

Luego, en el sombreado de píxeles que algo sólo una salida como:

return HeatMapColor(myValue, 0.00, 50.00); 

Y puede tener una idea de la forma en que varía a través de sus píxeles:

enter image description here

Por supuesto se puede utilizar cualquier conjunto de colores que te gusta.

4

GLSL Sandbox ha sido muy útil para los shaders.

No depurando per se (que se ha respondido como incapaz) pero útil para ver los cambios en la salida rápidamente.

1

Las respuestas existentes son todas buenas, pero quería compartir una pequeña gema más que ha sido valiosa en la depuración de problemas de precisión difíciles en un sombreador GLSL. Con números int muy grandes representados como un punto flotante, se debe tener cuidado de usar floor (n) y floor (n + 0.5) correctamente para implementar round() a un int exacto. Entonces es posible representar un valor flotante que es un int exacto mediante la siguiente lógica para empaquetar los componentes de bytes en valores de salida R, G y 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

En la parte inferior de esta respuesta es un ejemplo de código GLSL que permite a la salida el valor total float como el color, la codificación de IEEE 754 binary32. Lo utilizo como sigue (este fragmento da a cabo yy componente de la matriz modelview):

Después de obtener esta en la pantalla, sólo puede tomar cualquier selector de color, formatear el color como HTML (introducción de 00 a la rgb valor si no necesita una mayor precisión, y haciendo un segundo pase para obtener el byte inferior si lo hace), y obtiene la representación hexadecimal del float como IEEE 754 binary32.

Aquí está la implementación real de toColor():

#version 120 

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=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 int 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(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 binary32/255.; 
} 
Cuestiones relacionadas