Как отладить шейдер GLSL?

Мне нужно отладить программу GLSL, но я не знаю, как выводить промежуточный результат. Можно ли сделать некоторые отладочные трассы (например, с printf) с помощью GLSL?

Вы не можете легко связаться с CPU из GLSL. Использование glslDevil или других инструментов – ваш лучший выбор.

Для printf потребовалось бы попытаться вернуться к процессору с графического процессора, работающего с кодом GLSL. Вместо этого вы можете попробовать перейти к дисплею. Вместо того, чтобы пытаться выводить текст, выводите что-то визуально своеобразное на экран. Например, вы можете нарисовать что-то определенного цвета только в том случае, если вы достигнете точки вашего кода, где хотите добавить printf. Если вам нужно напечатать значение, вы можете установить цвет в соответствии с этим значением.

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

Я нашел Transform Feedback полезным инструментом для отладки вершинных шейдеров. Вы можете использовать это для захвата значений VS-выходов и считывания их на стороне процессора, без необходимости проходить через растеризатор.

Вот еще одна ссылка на учебник по Transform Feedback.

Если вы хотите визуализировать вариации значения по экрану, вы можете использовать функцию тепловой карты, подобную этой (я написал ее в hlsl, но ее легко адаптировать к 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); } 

Затем в вашем пиксельном шейдере вы просто выводите что-то вроде:

 return HeatMapColor(myValue, 0.00, 50.00); 

И можете получить представление о том, как он меняется по вашим пикселям:

введите описание изображения здесь

Конечно, вы можете использовать любой набор цветов, которые вам нравятся.

GLSL Sandbox была очень удобна для шейдеров.

Не отладка сама по себе (на которую ответили как неспособные), но она удобна, чтобы быстро увидеть изменения в выходе.

Сделайте офлайн-рендеринг текстурой и оцените данные текстуры. Вы можете найти связанный код с помощью googling для «render to texture» opengl. Затем используйте glReadPixels для чтения вывода в массив и выполнения утверждений на нем (поскольку просмотр такого огромного массива в отладчике обычно не очень полезен).

Также вы можете отключить зажим для вывода значений, которые не находятся между 0 и 1, что поддерживается только для текстур с плавающей запятой .

Я лично был обеспокоен проблемой правильной отладки шейдеров на некоторое время. Кажется, что нет хорошего способа – если кто-нибудь найдет хороший (и не устаревший / устаревший) отладчик, сообщите мне.

Я использую пример fragmentарного шейдера, как я фактически отлаживаю.

 #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; } 

введите описание изображения здесь

Существующие ответы – все это хорошо, но я хотел поделиться еще одним маленьким драгоценным камнем, который был полезен при отладке сложных задач точности в шейдере GLSL. С очень большими номерами int, представленными как плавающие точки, нужно позаботиться о том, чтобы правильно использовать пол (n) и пол (n + 0,5) для реализации round () до точного int. Затем можно отобразить значение float, которое является точным int следующей логикой, чтобы упаковать байтовые компоненты в значения R, G и 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; 

В нижней части этого ответа приведен пример кода GLSL, который позволяет выводить полное значение float как цвет, binary32 IEEE 754 binary32 . Я использую его следующим образом (этот fragment выдает yy компонент матрицы вида модели):

 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); 

После того, как вы получите это на экране, вы можете просто взять любой набор цветов, отформатировать цвет как HTML (добавление 00 в значение rgb если вам не нужна более высокая точность, и сделать второй проход, чтобы получить младший байт, если вы это сделаете) , и вы получите шестнадцатеричное представление float как IEEE 754 binary32 .

Вот фактическая реализация 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=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.; } с 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=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.; } 
  • Жасмин: обратный вызов Async не вызывался в течение таймаута, указанного jasmine.DEFAULT_TIMEOUT_INTERVAL
  • Как избежать доступа к изменяемой переменной из закрытия
  • В настоящий момент точка останова не будет удалена. Для этого документа в приложении Silverlight не были загружены никакие символы
  • JavaScript console.log вызывает ошибку: «Синхронный XMLHttpRequest в основном streamе устарел ...»
  • Как отладить скрипт Greasemonkey с расширением Firebug?
  • Перерыв при исключении исключения
  • Будет ли # RELEASE работать, как #if DEBUG делает в C #?
  • Android: автоматически выбирает debug / release Maps api key?
  • Что такое «Async Pinned Handle»?
  • Как добавить NSDebug.h и использовать NSZombie в iPhone SDK
  • Как обнаружить системную информацию типа os или типа устройства
  • Давайте будем гением компьютера.