Necesito depurar un programa GLSL pero no sé cómo generar un resultado intermedio. ¿Es posible hacer algunos rastros de depuración (como con printf) con GLSL?
No puede comunicarse fácilmente con la CPU desde 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 su lugar, puede intentar avanzar hacia la pantalla. En lugar de intentar generar texto, muestre algo visualmente distintivo en 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.
Es un dispositivo de depuración. Si desea saber dónde está la posición de la luz en la escena, por ejemplo, vaya: if (lpos.x> 100) bug = 1.0. Si la posición de la luz es mayor que 100, la escena se volverá roja.
ste3e
12
He encontrado que Transform Feedback es una herramienta útil para depurar sombreadores de vértices. Puede usar esto para capturar los valores de las salidas VS y volver a leerlos en el lado de la CPU, sin tener que pasar por el rasterizador.
Aquí hay otro enlace a un tutorial sobre Transformar Comentarios.
Si desea visualizar las variaciones de un valor en la pantalla, puede usar una función de mapa de calor similar a esta (la escribí en hlsl, pero es fácil de adaptar a glsl):
Es posible que también desee probar ShaderToy, y tal vez ver un video como este ( https://youtu.be/EBrAdahFtuo ) del canal de YouTube "The Art of Code", donde puede ver algunas de las técnicas que funcionan bien para la depuración y visualizante. Puedo recomendar encarecidamente su canal, ya que escribe algunas cosas realmente buenas y también tiene una habilidad especial para presentar ideas complejas en formatos novedosos, altamente atractivos y fáciles de digerir (su video de Mandelbrot es un excelente ejemplo de exactamente eso: https: // youtu.be/6IWXkV82oyY )
Espero que a nadie le importe esta respuesta tardía, pero la pregunta ocupa un lugar destacado en las búsquedas de Google para la depuración de GLSL y, por supuesto, mucho ha cambiado en 9 años :-)
PD: Otras alternativas también podrían ser NVIDIA nSight y AMD ShaderAnalyzer, que ofrecen un depurador completo para sombreadores.
Estoy compartiendo un ejemplo de fragmento de sombreador, cómo realmente 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 whiteelse
sampColor = texture2D(samp, fs_in.texcoord);//else sample from original
color = sampColor;}
Al final de esta respuesta hay un ejemplo de código GLSL que permite generar el floatvalor completo como color, codificando IEEE 754 binary32. Lo uso de la siguiente manera (este fragmento proporciona el yycomponente de la matriz de modelview):
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);
Después de que aparezca esto en la pantalla, puede tomar cualquier selector de color, formatear el color como HTML (agregando 00alrgb valor si no necesita mayor precisión y haciendo un segundo pase para obtener el byte inferior si lo necesita), y obtienes la representación hexadecimal de floatcomo IEEE 754 binary32.
Aquí está la implementación real de 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.;}
Realice el renderizado sin conexión a una textura y evalúe los datos de la textura. Puede encontrar código relacionado buscando en Google para "render to texture" opengl. Luego use glReadPixels para leer la salida en una matriz y realizar aserciones 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 texturas de punto flotante .
Personalmente, me molestó el problema de depurar adecuadamente los sombreadores durante un tiempo. No parece haber una buena manera: si alguien encuentra un depurador bueno (y no desactualizado / desaprobado), hágamelo saber.
Cualquier respuesta o comentario que diga "google xyz" debe ser prohibido o rechazado en Stackoverflow.
gregoiregentil
1
Las respuestas existentes son todas buenas, pero quería compartir una pequeña joya más que ha sido valiosa para depurar problemas de precisión difíciles en un sombreador GLSL. Con números int muy grandes representados como un punto flotante, uno debe tener cuidado de usar floor (n) y floor (n + 0.5) adecuadamente 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.
Respuestas:
No puede comunicarse fácilmente con la CPU desde 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 su lugar, puede intentar avanzar hacia la pantalla. En lugar de intentar generar texto, muestre algo visualmente distintivo en 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.
fuente
fuente
He encontrado que Transform Feedback es una herramienta útil para depurar sombreadores de vértices. Puede usar esto para capturar los valores de las salidas VS y volver a leerlos en el lado de la CPU, sin tener que pasar por el rasterizador.
Aquí hay otro enlace a un tutorial sobre Transformar Comentarios.
fuente
Si desea visualizar las variaciones de un valor en la pantalla, puede usar una función de mapa de calor similar a esta (la escribí en hlsl, pero es fácil de adaptar a glsl):
Luego, en su sombreador de píxeles, simplemente genera algo como:
Y puede tener una idea de cómo varía según los píxeles:
Por supuesto, puede usar cualquier conjunto de colores que desee.
fuente
GLSL Sandbox ha sido muy útil para los sombreadores.
No depuración per se (que se ha respondido como incapaz) pero útil para ver los cambios en la salida rápidamente.
fuente
Puede probar esto: https://github.com/msqrt/shader-printf, que es una implementación llamada apropiadamente "Funcionalidad simple printf para GLSL".
Es posible que también desee probar ShaderToy, y tal vez ver un video como este ( https://youtu.be/EBrAdahFtuo ) del canal de YouTube "The Art of Code", donde puede ver algunas de las técnicas que funcionan bien para la depuración y visualizante. Puedo recomendar encarecidamente su canal, ya que escribe algunas cosas realmente buenas y también tiene una habilidad especial para presentar ideas complejas en formatos novedosos, altamente atractivos y fáciles de digerir (su video de Mandelbrot es un excelente ejemplo de exactamente eso: https: // youtu.be/6IWXkV82oyY )
Espero que a nadie le importe esta respuesta tardía, pero la pregunta ocupa un lugar destacado en las búsquedas de Google para la depuración de GLSL y, por supuesto, mucho ha cambiado en 9 años :-)
PD: Otras alternativas también podrían ser NVIDIA nSight y AMD ShaderAnalyzer, que ofrecen un depurador completo para sombreadores.
fuente
Estoy compartiendo un ejemplo de fragmento de sombreador, cómo realmente depuro.
fuente
Al final de esta respuesta hay un ejemplo de código GLSL que permite generar el
float
valor completo como color, codificando IEEE 754binary32
. Lo uso de la siguiente manera (este fragmento proporciona elyy
componente de la matriz de modelview):Después de que aparezca esto en la pantalla, puede tomar cualquier selector de color, formatear el color como HTML (agregando
00
alrgb
valor si no necesita mayor precisión y haciendo un segundo pase para obtener el byte inferior si lo necesita), y obtienes la representación hexadecimal defloat
como IEEE 754binary32
.Aquí está la implementación real de
toColor()
:fuente
Realice el renderizado sin conexión a una textura y evalúe los datos de la textura. Puede encontrar código relacionado buscando en Google para "render to texture" opengl. Luego use glReadPixels para leer la salida en una matriz y realizar aserciones 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 texturas de punto flotante .
Personalmente, me molestó el problema de depurar adecuadamente los sombreadores durante un tiempo. No parece haber una buena manera: si alguien encuentra un depurador bueno (y no desactualizado / desaprobado), hágamelo saber.
fuente
Las respuestas existentes son todas buenas, pero quería compartir una pequeña joya más que ha sido valiosa para depurar problemas de precisión difíciles en un sombreador GLSL. Con números int muy grandes representados como un punto flotante, uno debe tener cuidado de usar floor (n) y floor (n + 0.5) adecuadamente 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.
fuente