WebGPU Pipeline Layout and Storage Buffer Alignment Constraints
0 reputation · 26 Sept 2021, 18:45 UTC
0 reputation · 26 Sept 2021, 18:45 UTC
WebGPU utilizes a pipeline layout system to decouple resource definitions from specific pipeline states, allowing for more efficient switching between pipelines that share the same bind group layouts.
When utilizing storage buffers for read-write access in compute shaders, the API enforces strict alignment requirements. While minUniformBufferOffsetAlignment provides a clear metric for uniform buffers, the behavior regarding dynamic offsets and alignment for storage buffers can vary across different hardware backends like Vulkan, Metal, and Direct3D 12.
There is uncertainty regarding how to maintain portable resource layouts when the underlying hardware requires differing alignment for storage buffer offsets within a single bind group.
32275 reputation · 27 Sept 2021, 01:51 UTC
Use the adapter’s minStorageBufferOffsetAlignment limit to obtain the required alignment (currently 256 bytes on all implementations) and round both the buffer offset and size up to a multiple of that value before creating the GPUBufferBinding for a bind‑group entry.
GPUSupportedLimits.minStorageBufferOffsetAlignment (analogous to the uniform‑buffer limit).GPUAdapter via adapter.limits.minStorageBufferOffsetAlignment.const align = adapter.limits.minStorageBufferOffsetAlignment;const alignedOffset = Math.ceil(desiredOffset / align) * align;const alignedSize = Math.ceil(desiredSize / align) * align;alignedSize bytes, then bind it using { buffer, offset: alignedOffset, size: alignedSize }.{ type: "storage-buffer" } and use setBindGroup before dispatching compute work.If the returned alignment differs from 256 bytes (for example, a future hardware feature level), the same calculation will automatically produce a compatible offset, so no code change is required. To confirm the exact alignment for your hardware, please share the value returned by adapter.limits.minStorageBufferOffsetAlignment.
Use comments to ask for clarification. Post a solution as an answer.
32,275 reputation · 27 Sept 2021, 00:48 UTC
The WebGPU spec requires that the offset of a static (non‑dynamic) storage buffer binding be a multiple of 256 bytes, regardless of the value returned by adapter.limits.minStorageBufferOffsetAlignment. The size of the binding must also be a multiple of 4 bytes.
For dynamic offsets, the alignment constraint comes from minStorageBufferOffsetAlignment (often 256 bytes but can be larger on some adapters). Therefore a portable layout should:
const staticAlign = 256; // spec‑mandated for static storage buffers const dynAlign = adapter.limits.minStorageBufferOffsetAlignment; // static buffer const staticOffset = Math.ceil(desiredStaticOffset / staticAlign) * staticAlign; // dynamic buffer const dynOffset = Math.ceil(desiredDynamicOffset / dynAlign) * dynAlign;Mixing the two incorrectly leads to validation errors at bind‑group creation or dispatch time.