2010-03-24 41 views
150

Tôi cần gỡ lỗi chương trình GLSL nhưng tôi không biết cách xuất kết quả trung gian. Có thể thực hiện một số dấu vết gỡ rối (như với printf) bằng GLSL không?Làm cách nào để gỡ lỗi trình đổ bóng GLSL?

+6

... mà không cần sử dụng phần mềm bên ngoài như glslDevil. –

+0

hãy xem [sửa lỗi in biến nổi và văn bản từ trình đổ vỡ đoạn GLSL] (https://stackoverflow.com/a/44797902/2521214) bạn chỉ cần đơn vị kết cấu dự phòng đơn cho phông chữ và trạng thái không đổi của giá trị được xuất trong khu vực in – Spektre

Trả lời

90

Bạn không thể dễ dàng liên lạc lại với CPU từ bên trong GLSL. Sử dụng glslDevil hoặc các công cụ khác là đặt cược tốt nhất của bạn.

Printf sẽ yêu cầu cố gắng lấy lại CPU từ GPU chạy mã GLSL. Thay vào đó, bạn có thể thử đẩy trước màn hình. Thay vì cố gắng xuất văn bản, xuất ra một cái gì đó trực quan khác biệt với màn hình. Ví dụ: bạn có thể tô màu cho một thứ cụ thể chỉ khi bạn đạt đến điểm mã của mình nơi bạn muốn thêm printf. Nếu bạn cần printf một giá trị, bạn có thể đặt màu theo giá trị đó.

+24

Điều gì xảy ra nếu lý do chính xác bạn muốn gỡ lỗi trình đổ bóng của bạn là vì không có gì xuất hiện trên màn hình? –

+5

Tại sao bạn muốn gỡ lỗi mọi thứ? Bởi vì mã của nó và anh ta muốn kiểm tra giá trị thời gian chạy tôi sẽ gây nguy hiểm .... – RichieHH

+3

[GLSL-Debugger] (http://glsl-debugger.github.io/) là một nhánh nguồn mở của glslDevil. – Magnus

2

Hiển thị kết xuất ngoại tuyến thành kết cấu và đánh giá dữ liệu của kết cấu. Bạn có thể tìm mã liên quan bằng cách googling cho "render to texture" opengl Sau đó sử dụng glReadPixels để đọc đầu ra vào một mảng và thực hiện các xác nhận trên nó (vì nhìn qua một mảng khổng lồ trong trình gỡ rối thường không thực sự hữu ích).

Ngoài ra, bạn có thể muốn tắt tính năng kẹp thành giá trị đầu ra không nằm trong khoảng từ 0 đến 1, chỉ được hỗ trợ cho floating point textures.

Cá nhân tôi đã bị làm phiền bởi sự cố gỡ lỗi đúng cách trong một thời gian. Có vẻ như không phải là một cách hay - Nếu có ai tìm thấy trình gỡ rối tốt (và không lỗi thời/không dùng nữa), hãy cho tôi biết.

+1

Bất kỳ câu trả lời hoặc nhận xét nào cho biết "google xyz" đều bị cấm hoặc bị bỏ phiếu từ 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

Đây là thiết bị gỡ lỗi. Nếu bạn muốn biết vị trí ánh sáng ở hiện trường, ví dụ: hãy đi: if (lpos.x> 100) bug = 1.0. Nếu vị trí ánh sáng lớn hơn 100, cảnh sẽ chuyển sang màu đỏ. – ste3e

+0

Đó là một mẹo tuyệt vời! ;) Cảm ơn Stephen! – sinner

12

Tôi đã tìm thấy Transform Feedback là công cụ hữu ích để gỡ lỗi trình tạo bóng đỉnh. Bạn có thể sử dụng điều này để nắm bắt các giá trị của các đầu ra VS, và đọc chúng trở lại ở phía CPU, mà không cần phải đi qua rasterizer.

Here là một liên kết khác đến hướng dẫn về Chuyển đổi phản hồi.

2

Tôi đang chia sẻ một ví dụ về trình đổ bóng phân đoạn, cách tôi thực sự gỡ lỗi.

#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

Nếu bạn muốn hình dung các biến thể của một giá trị trên màn hình, bạn có thể sử dụng một hàm Heatmap tương tự như sau (tôi đã viết nó trong HLSL, nhưng nó rất dễ dàng để thích ứng với 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); 
} 

Sau đó, trong pixel shader của bạn, bạn chỉ ra một cái gì đó như:

return HeatMapColor(myValue, 0.00, 50.00); 

Và có thể có được một ý tưởng về cách nó thay đổi trên pixel của bạn:

enter image description here

Tất nhiên bạn có thể sử dụng bất kỳ tập hợp các màu sắc mà bạn thích.

4

GLSL Sandbox khá tiện dụng đối với tôi đối với trình đổ bóng.

Không gỡ lỗi mỗi lần (đã được trả lời là không có khả năng) nhưng tiện dụng để xem các thay đổi về đầu ra nhanh chóng.

1

Câu trả lời hiện có là tất cả các công cụ tốt, nhưng tôi muốn chia sẻ thêm một ít đá quý có giá trị trong việc gỡ lỗi các vấn đề chính xác phức tạp trong trình đổ bóng GLSL. Với các số int rất lớn được biểu diễn như một điểm nổi, người ta cần phải cẩn thận để sử dụng sàn (n) và sàn (n + 0.5) đúng để thực hiện vòng() đến một int chính xác. Sau đó, có thể hiển thị một giá trị float là một int chính xác theo logic sau để đóng gói các thành phần byte vào các giá trị đầu ra R, G và 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

Ở dưới cùng của câu trả lời này là một ví dụ về mã GLSL cho phép để sản xuất các giá trị đầy đủ float như màu sắc, mã hóa IEEE 754 binary32. Tôi sử dụng nó như sau (đoạn này đưa ra yy thành phần của ma trận modelview):

Sau khi bạn có được điều này trên màn hình, bạn chỉ có thể lấy bất kỳ chọn màu, định dạng màu dưới dạng HTML (phụ 00 đến rgb giá trị nếu bạn không cần độ chính xác cao hơn và thực hiện lần thứ hai để nhận byte thấp hơn nếu bạn thực hiện) và bạn nhận được biểu diễn thập lục phân của float là IEEE 754 binary32.

Đây là việc thực hiện thực tế của 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.; 
} 
Các vấn đề liên quan