Bir GLSL programında hata ayıklamak gerekiyor, ancak ara sonuç çıktısını bilmiyorum. GLSL ile bazı hata ayıklama izleri (printf gibi) yapmak mümkün müdür?
Bir GLSL programında hata ayıklamak gerekiyor, ancak ara sonuç çıktısını bilmiyorum. GLSL ile bazı hata ayıklama izleri (printf gibi) yapmak mümkün müdür?
Yanıtlar:
GLSL içinden CPU ile kolayca iletişim kuramazsınız. GlslDevil veya diğer araçları kullanmak en iyi seçenektir.
Bir printf, GLSL kodunu çalıştıran GPU'dan CPU'ya geri dönmeye çalışmayı gerektirir. Bunun yerine, ekrana ilerlemeyi deneyebilirsiniz. Metin çıktısını almak yerine, ekrana görsel olarak farklı bir şey çıktılayın. Örneğin, belirli bir rengi yalnızca kodunuzun printf eklemek istediğiniz noktasına ulaşırsanız boyayabilirsiniz. Bir değeri yazdırmanız gerekiyorsa, rengi bu değere göre ayarlayabilirsiniz.
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'ın köşe gölgelendiricilerin hata ayıklaması için yararlı bir araç olduğunu gördüm . Rasterizatörden geçmek zorunda kalmadan VS çıkışlarının değerlerini yakalamak ve CPU tarafında tekrar okumak için bunu kullanabilirsiniz.
İşte Transform Feedback ile ilgili bir eğiticiye başka bir link.
Ekrandaki bir değerin varyasyonlarını görselleştirmek istiyorsanız, buna benzer bir ısı haritası işlevini kullanabilirsiniz (hlsl'de yazdım, ancak glsl'ye uyum sağlamak kolaydır):
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);
}
Sonra piksel gölgelendiricinizde sadece şöyle bir şey çıkarırsınız:
return HeatMapColor(myValue, 0.00, 50.00);
Ve pikselleriniz arasında nasıl değiştiği hakkında bir fikir edinebilirsiniz:
Tabii ki istediğiniz herhangi bir renk setini kullanabilirsiniz.
GLSL Sandbox , gölgelendiriciler için benim için oldukça kullanışlı oldu.
Kendi başına hata ayıklama değil (aciz olarak cevaplandı) ama çıkıştaki değişiklikleri hızlı bir şekilde görmek için kullanışlı.
Bunu deneyebilirsiniz: https://github.com/msqrt/shader-printf , "GLSL için basit printf işlevselliği" adı verilen bir uygulamadır.
Ayrıca ShaderToy'u denemek ve hata ayıklama için iyi çalışan bazı teknikleri görebileceğiniz "Kod Sanatı" YouTube kanalından böyle bir video (belki de https://youtu.be/EBrAdahFtuo ) izlemek isteyebilirsiniz. görselleştirilmesi. Kanalını gerçekten iyi şeyler yazarken şiddetle tavsiye edebilirim ve aynı zamanda roman, son derece ilgi çekici ve sindirimi kolay formatlarda karmaşık fikirler sunmak için bir ustalığa sahiptir (Mandelbrot videosu tam olarak bunun mükemmel bir örneğidir: https: // youtu.be/6IWXkV82oyY )
Umarım kimse bu geç cevabı akla getirmez, ancak soru Google'ın GLSL hata ayıklama arayışlarında üst sıralardadır ve elbette 9 yıl içinde çok şey değişmiştir :-)
Not: Diğer alternatifler, gölgelendiriciler için tam bir adım ayıklayıcı sunan NVIDIA nSight ve AMD ShaderAnalyzer de olabilir.
Ben aslında nasıl hata ayıklama bir fragman gölgelendirici örneği paylaşıyorum.
#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;
}
Bu cevabın altında, float
IEEE 754'ü kodlayan , tam değerin renk olarak çıkmasına izin veren bir GLSL kodu örneği verilmiştir binary32
. Ben aşağıdaki gibi kullanın (bu snippet yy
modelview matris bileşeni verir ):
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);
Ekranda bu aldıktan sonra, sadece (ekleme HTML olarak rengini biçimlendirmek, herhangi bir renk seçici alabilir 00
için rgb
daha yüksek hassasiyet gerekmez ve bunu yaparsanız ikinci geçiş yapıyor alt byte olsun eğer değeri) ve float
IEEE 754'ün onaltılı gösterimini elde edersiniz binary32
.
İşte gerçek uygulama 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.;
}
Bir dokuya çevrimdışı oluşturma yapın ve doku verilerini değerlendirin. İlgili kodu, "render to texture" opengl için googling yaparak bulabilirsiniz. Daha sonra çıktıyı bir diziye okumak ve üzerinde iddiayı gerçekleştirmek için glReadPixels kullanın (hata ayıklayıcıda böyle büyük bir diziye bakmak genellikle yararlı değildir).
Ayrıca, yalnızca kayan nokta dokuları için desteklenen 0 ile 1 arasında olmayan çıkış değerlerine sıkıştırmayı devre dışı bırakmak isteyebilirsiniz .
Şahsen bir süre düzgün gölgelendirici hata ayıklama sorunu tarafından rahatsız edildi. İyi bir yol yok gibi görünüyor - Herkes iyi (ve eski / kullanımdan kaldırılmamış) bir hata ayıklayıcı bulursa, lütfen bana bildirin.
Mevcut cevapların hepsi iyi şeyler, ama bir GLSL gölgelendiricideki zor hassas sorunları ayıklamada değerli olan bir küçük taş daha paylaşmak istedim. Kayan nokta olarak temsil edilen çok büyük int sayıları ile, yuvarlak () 'yi kesin bir int değerine uygulamak için zeminin (n) ve zeminin (n + 0.5) doğru kullanılmasına özen gösterilmelidir. Daha sonra bayt bileşenlerini R, G ve B çıkış değerlerine paketlemek için aşağıdaki mantıkla tam bir int olan bir kayan değer oluşturmak mümkündür.
// 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;