bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
36.09k stars 3.56k forks source link

Glsl fragment shader nestet loops unsupported #6092

Open htrojan opened 2 years ago

htrojan commented 2 years ago

Bevy version

0.8.1

[Optional] Relevant system information

`AdapterInfo { name: "NVIDIA GeForce RTX 3060", vendor: 4318, device: 9476, device_type: DiscreteGpu, backend: Vulkan }`

What you did

Glsl fragment shaders ignore the outer loop when nesting for loops. Here is a minimal example of a nested for loop. What should have happened is, that the texture is averaged over a certain width. Instead only the height is averaged and the outer loop is completely ignored.

    vec4 sum = vec4(0.0);
    for (int i = 0; i < 9; ++i) {
       for(int j = 0; j < 9; ++j) {
           vec2 tc = uv + vec2(float(i - 4) / width, float(j - 4) / height);
           sum +=  texture(sampler2D(input_texture, our_sampler), tc);
       }
    }

Interestingly, the code aboves seems to leave i=0 constant and does not iterate the outer loop at all, causing a constant shift of 4 pixels in x direction. Moreover, this code

    vec4 sum = vec4(0.0);
    for (int i = 8; i < 9; ++i) {
       for(int j = 0; j < 9; ++j) {
           vec2 tc = uv + vec2(float(i - 4) / width, float(j - 4) / height);
           sum +=  texture(sampler2D(input_texture, our_sampler), tc);
       }
    }

causes a constant shift of 4 pixels in the opposite direction as the code above, while the y-direction averages correctly.

I do not know what module exactly is responsible for this, but I would assume something in the parsing of the GLSL shader is not working as expected.

Example output

This shows the first example. Only the y axis (the inner loop) is considered. image

When using the second code example, all red rectangles gain a constant x offset image Here the rectangle is not emitted from the sprite origin, but is offset to the right (the offset is 50 pixels, so more exaggerated than in the code fragment above)

bjorn3 commented 2 years ago

This is likely a bug in naga (which wgpu uses for translating from glsl to spir-v). Did you try reproducing with just wgpu?

htrojan commented 2 years ago

I'm not quite sure how to check that in pure wgpu without building too much stuff around it. What I tried is to use naga, let it parse the input and then output again as a fragment shader.

naga blur.frag output.frag

In the output, both for loops are present with variables i and j that are incremented within their respective loops. So I'm not quite sure what to make of that