gfx-rs / naga

Universal shader translation in Rust

Home Page:https://github.com/gfx-rs/wgpu/tree/trunk/naga

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Missing validation: Adding initializer to workgroup variable declaration in WGSL causes shader compiler error

Gobbel2000 opened this issue · comments

Example

The following example causes the spirv to nir compiler of mesa to fail, because the declaration in the first line of the shader erroneously contains an initializer value.

static SHADER: &str = "
var<workgroup> initialized: u32 = 0u;

@compute
@workgroup_size(1)
fn main() {
    initialized += 10u;
}
";

async fn run() {
    let instance = wgpu::Instance::default();
    let adapter = instance
        .request_adapter(&wgpu::RequestAdapterOptions::default())
        .await
        .unwrap();
    let (device, queue) = adapter
        .request_device(
            &wgpu::DeviceDescriptor {
                label: None,
                features: wgpu::Features::empty(),
                limits: wgpu::Limits::downlevel_defaults(),
            },
            None,
        )
        .await
        .unwrap();
    let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
        label: None,
        source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(SHADER)),
    });
    let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
        label: None,
        layout: None,
        module: &shader,
        entry_point: "main",
    });
    let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
        label: None,
    });
    {
        let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
            label: None,
        });
        cpass.set_pipeline(&pipeline);
        cpass.dispatch_workgroups(1, 1, 1);
    }
    queue.submit(Some(encoder.finish()));
}

fn main() { pollster::block_on(run()) }

When executed, the spirv code generated by naga causes mesa to abort. Only when mesa is compiled with the option b_ndebug=false, some kind of error message is printed:

SPIR-V parsing FAILED:
    In file ../mesa/src/compiler/spirv/vtn_variables.c:2179
    Workgroup variable 5 can only have OpConstantNull as initializer, but have 4 instead
    200 bytes into the SPIR-V binary
zsh: trace trap (core dumped)  cargo run

For context, this is the offending part in the spirv code:

...
%3 = OpTypeInt 32 0
%4 = OpConstant %3 0
%6 = OpTypePointer Workgroup %3
%5 = OpVariable %6 Workgroup %4
...

This is with mesa 23.3.0_devel on Arch Linux with an AMD RX 6700XT. I used wgpu version 0.17.0 and naga version 0.13.0.

The correct solution in this case is to simply change the first shader line to var<workgroup> initialized: u32;, but the missing error message makes that hard to find.

Expected behavior

According to the WGSL specification, initializers to workgroup variables are not allowed:

Variables in address spaces other than function or private must not have an initializer.

I would expect the validator to throw an error whenever a var declaration in the workgroup (probably also uniform and storage) address space contains an initializer, as is the case with the first shader line in the example above.