gpuweb / gpuweb

Where the GPU for the Web work happens!
https://webgpu.io
Other
4.85k stars 319 forks source link

Support pipeline-sized arrays in storage bindings #4892

Open Runi-c opened 2 months ago

Runi-c commented 2 months ago

I'm working on a hefty compute shader project in WGSL and running into a pair of issues that feel very constricting.

  1. The only way to have runtime or pipeline-sized array bindings is to use one storage buffer per array. This is because we can only have one runtime-sized array in a storage buffer (which makes sense), and pipeline-sized arrays (e.g. arrays sized by a pipeline constant) can only be used in the workgroup address space and therefore can't be bound.
  2. WebGPU implementations and/or graphics libraries have a relatively small maximum limit for maxStorageBuffersPerShaderStage (Chromium uses 10, wgpu uses 16, not sure why they're different)

What I would prefer to be able to do when I have multiple tightly related arrays with sizes only known at pipeline creation time is to put them all in a single read-only buffer binding like this:

override foo_count: u32;
override bar_count: u32;
override baz_count: u32;
struct SimulationData {
    stuff: array<Foo, foo_count>,
    other_stuff: array<Bar, bar_count>,
    more: array<Baz, baz_count>,
}
@group(0) @binding(0)
var<storage, read> data: SimulationData;

But because of the constraints on runtime- and pipeline-sized arrays, the only option I have is to allocate 3 runtime-sized storage buffers to what I would prefer to fill 1 buffer with:

@group(0) @binding(0)
var<storage, read> stuff: array<Foo>;
@group(0) @binding(1)
var<storage, read> other_stuff: array<Bar>;
@group(0) @binding(2)
var<storage, read> more: array<Baz>;

For a workload with many small arrays of CPU-derived data, this will run into the storage buffers limit very quickly unless we do something more drastic like a shader preprocessor hack, or setting an arbitrary max array size, or in the worst case, packing everything into one flat array and marshalling out the struct data manually in the shader kernel.

dneto0 commented 4 weeks ago

Thanks for the suggestion. Currently the places where an array can be sized by an override expression limited to what's common between Metal and Vulkan. (Direct3D doesn't support it, so we cover it up by delaying shader compilation until pipeline creation time.)

Putting this in M2 for consideration.