Мне нужно отладить программу GLSL, но я не знаю, как вывести промежуточный результат. Можно ли сделать несколько отладочных трасс (например, с printf) с помощью GLSL?
Вы не можете легко связаться с процессором из GLSL. Использование glslDevil или других инструментов - ваш лучший выбор.
Для printf потребуется попытаться вернуться к ЦП с графического процессора, на котором выполняется код GLSL. Вместо этого вы можете попытаться продвинуться к дисплею. Вместо того, чтобы пытаться выводить текст, выведите на экран что-то визуально отличительное. Например, вы можете нарисовать что-то определенным цветом, только если вы достигнете точки своего кода, где вы хотите добавить printf. Если вам нужно напечатать значение, вы можете установить цвет в соответствии с этим значением.
Это отладочное устройство. Например, если вы хотите узнать, где находится светлая сцена на сцене, перейдите: if (lpos.x> 100) bug = 1.0. Если положение освещения больше 100, сцена станет красной.
Ste3e
13
Я нашел Transform Feedback полезным инструментом для отладки вершинных шейдеров. Вы можете использовать это для захвата значений выходов VS и считывания их обратно на стороне процессора, без необходимости проходить через растеризатор.
Вот еще одна ссылка на учебник по Transform Feedback.
Если вы хотите визуализировать изменения значения на экране, вы можете использовать функцию тепловой карты, аналогичную этой (я написал ее в hlsl, но ее легко адаптировать к glsl):
Вы можете попробовать это: https://github.com/msqrt/shader-printf, который является реализацией, которая называется «Простая функциональность printf для GLSL».
Вы также можете попробовать ShaderToy и, возможно, посмотреть видео, подобное этому ( https://youtu.be/EBrAdahFtuo ), на канале YouTube «Искусство кода», где вы можете увидеть некоторые методы, которые хорошо работают для отладки и визуализации. Я настоятельно рекомендую его канал, так как он пишет действительно хорошие вещи, и он также умеет представлять сложные идеи в новых, увлекательных и легко усваиваемых форматах (его видео Мандельброта является превосходным примером именно этого: https: // youtu.be/6IWXkV82oyY )
Я надеюсь, что никто не возражает против этого позднего ответа, но этот вопрос занимает первое место в поиске Google для отладки GLSL и, конечно, многое изменилось за 9 лет :-)
PS: Другими альтернативами также могут быть NVIDIA nSight и AMD ShaderAnalyzer, которые предлагают полный пошаговый отладчик для шейдеров.
Я делюсь примером фрагмента шейдера, как я на самом деле отлаживать.
#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;}
Внизу этого ответа приведен пример кода GLSL, который позволяет выводить полное floatзначение в виде цвета, кодируя IEEE 754 binary32. Я использую его следующим образом (этот фрагмент 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():
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.;}
Сделайте рендеринг текстуры в автономном режиме и оцените данные текстуры. Вы можете найти связанный код путем поиска в Google для «рендеринга в текстуру» opengl. Затем используйте glReadPixels, чтобы прочитать выходные данные в массив и выполнить утверждения для него (поскольку просмотр такого огромного массива в отладчике обычно не очень полезен).
Также вы можете отключить ограничение для выходных значений, которые не находятся между 0 и 1, что поддерживается только для текстур с плавающей запятой .
Меня лично некоторое время беспокоила проблема правильной отладки шейдеров. Кажется, нет хорошего пути - если кто-то найдет хороший (и не устаревший / устаревший) отладчик, пожалуйста, дайте мне знать.
Любой ответ или комментарий, в которых говорится, что "google xyz" должен быть забанен или отклонен из Stackoverflow.
gregoiregentil
1
Все существующие ответы - хорошие вещи, но я хотел бы поделиться еще одной маленькой драгоценностью, которая была полезна при отладке сложных проблем точности в шейдере GLSL. С очень большими числами int, представленными в виде числа с плавающей запятой, нужно позаботиться о том, чтобы правильно использовать floor (n) и floor (n + 0.5), чтобы реализовать round () с точностью до int. Затем можно отобразить значение с плавающей точкой, которое является точным int, с помощью следующей логики, чтобы упаковать байтовые компоненты в выходные значения R, G и B.
Ответы:
Вы не можете легко связаться с процессором из GLSL. Использование glslDevil или других инструментов - ваш лучший выбор.
Для printf потребуется попытаться вернуться к ЦП с графического процессора, на котором выполняется код GLSL. Вместо этого вы можете попытаться продвинуться к дисплею. Вместо того, чтобы пытаться выводить текст, выведите на экран что-то визуально отличительное. Например, вы можете нарисовать что-то определенным цветом, только если вы достигнете точки своего кода, где вы хотите добавить printf. Если вам нужно напечатать значение, вы можете установить цвет в соответствии с этим значением.
источник
источник
Я нашел Transform Feedback полезным инструментом для отладки вершинных шейдеров. Вы можете использовать это для захвата значений выходов VS и считывания их обратно на стороне процессора, без необходимости проходить через растеризатор.
Вот еще одна ссылка на учебник по Transform Feedback.
источник
Если вы хотите визуализировать изменения значения на экране, вы можете использовать функцию тепловой карты, аналогичную этой (я написал ее в hlsl, но ее легко адаптировать к glsl):
Затем в вашем пиксельном шейдере вы просто выводите что-то вроде:
И можете получить представление о том, как оно меняется в зависимости от ваших пикселей:
Конечно, вы можете использовать любой набор цветов, которые вам нравятся.
источник
GLSL Sandbox мне очень пригодился для шейдеров.
Не отладка как таковая (на которую был дан ответ как неспособный), но удобная для быстрого просмотра изменений в выводе.
источник
Вы можете попробовать это: https://github.com/msqrt/shader-printf, который является реализацией, которая называется «Простая функциональность printf для GLSL».
Вы также можете попробовать ShaderToy и, возможно, посмотреть видео, подобное этому ( https://youtu.be/EBrAdahFtuo ), на канале YouTube «Искусство кода», где вы можете увидеть некоторые методы, которые хорошо работают для отладки и визуализации. Я настоятельно рекомендую его канал, так как он пишет действительно хорошие вещи, и он также умеет представлять сложные идеи в новых, увлекательных и легко усваиваемых форматах (его видео Мандельброта является превосходным примером именно этого: https: // youtu.be/6IWXkV82oyY )
Я надеюсь, что никто не возражает против этого позднего ответа, но этот вопрос занимает первое место в поиске Google для отладки GLSL и, конечно, многое изменилось за 9 лет :-)
PS: Другими альтернативами также могут быть NVIDIA nSight и AMD ShaderAnalyzer, которые предлагают полный пошаговый отладчик для шейдеров.
источник
Я делюсь примером фрагмента шейдера, как я на самом деле отлаживать.
источник
Внизу этого ответа приведен пример кода GLSL, который позволяет выводить полное
float
значение в виде цвета, кодируя IEEE 754binary32
. Я использую его следующим образом (этот фрагментyy
кода выдает компонент матрицы вида модели):После того, как вы получите это на экране, вы можете просто взять любой палитру цветов, отформатировать цвет как HTML (добавив
00
кrgb
значению, если вам не нужна более высокая точность, и сделав второй проход, чтобы получить младший байт, если вы это сделаете), и Вы получите шестнадцатеричное представлениеfloat
как IEEE 754binary32
.Вот фактическая реализация
toColor()
:источник
Сделайте рендеринг текстуры в автономном режиме и оцените данные текстуры. Вы можете найти связанный код путем поиска в Google для «рендеринга в текстуру» opengl. Затем используйте glReadPixels, чтобы прочитать выходные данные в массив и выполнить утверждения для него (поскольку просмотр такого огромного массива в отладчике обычно не очень полезен).
Также вы можете отключить ограничение для выходных значений, которые не находятся между 0 и 1, что поддерживается только для текстур с плавающей запятой .
Меня лично некоторое время беспокоила проблема правильной отладки шейдеров. Кажется, нет хорошего пути - если кто-то найдет хороший (и не устаревший / устаревший) отладчик, пожалуйста, дайте мне знать.
источник
Все существующие ответы - хорошие вещи, но я хотел бы поделиться еще одной маленькой драгоценностью, которая была полезна при отладке сложных проблем точности в шейдере GLSL. С очень большими числами int, представленными в виде числа с плавающей запятой, нужно позаботиться о том, чтобы правильно использовать floor (n) и floor (n + 0.5), чтобы реализовать round () с точностью до int. Затем можно отобразить значение с плавающей точкой, которое является точным int, с помощью следующей логики, чтобы упаковать байтовые компоненты в выходные значения R, G и B.
источник