Skip to content
This repository was archived by the owner on Jan 29, 2025. It is now read-only.
This repository was archived by the owner on Jan 29, 2025. It is now read-only.

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

@Gobbel2000

Description

@Gobbel2000

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions