Error: GPUValidationError – buffer size not aligned to minUniformBufferOffsetAlignment
0 reputation · 04 Nov 2023, 08:07 UTC
0 reputation · 04 Nov 2023, 08:07 UTC
Goal: replace uniform buffer data in a running WebGPU application while the GPU continues executing existing command buffers, avoiding any visible frame drop or downtime.
Constraint: WebGPU requires that the offset and size of a GPUBuffer used as UNIFORM satisfy the device’s minUniformBufferOffsetAlignment limit, and the validation layer will reject a GPUBindGroup if the buffer range is misaligned.
Uncertainty: when mapping a buffer with GPUMapWrite and writing new data, it is unclear whether the validation occurs at map time, at bind group creation, or at command submission, and how to guarantee alignment across different hardware vendors.
MAP_WRITE?minUniformBufferOffsetAlignment across all target devices?WebGPU validates uniform buffer alignment during the creation of the GPUBindGroup. It does not validate alignment during the mapAsync or getMappedRange calls, as those operations deal with raw memory access rather than the GPU's resource binding logic.
If you update a buffer via MAP_WRITE, the data itself can be any size. However, the moment you attempt to bind a range of that buffer to a pipeline using createBindGroup, the offset and size parameters are checked against the device's minUniformBufferOffsetAlignment. If the offset is not a multiple of this limit, the GPUValidationError is thrown.
To ensure compatibility across different hardware vendors (where alignment may vary between 256 bytes or other values), you must query the device limits at runtime rather than hard-coding a value.
minUniformBufferOffsetAlignment from the GPUDevice.limits object.// Calculate aligned offset
const alignment = device.limits.minUniformBufferOffsetAlignment;
const alignedSize = Math.ceil(rawSize / alignment) * alignment;
// Example: Offset for the Nth element in a buffer
const offset = index * alignedSize;
To verify your alignment logic during development, log the following check before creating your bind group:
console.assert(offset % device.limits.minUniformBufferOffsetAlignment === 0, `Misaligned offset: ${offset}`);
This resolution assumes you are using a standard GPUBufferUsage.UNIFORM. If you are utilizing GPUBufferUsage.STORAGE, different alignment rules apply. We also assume the GPUValidationError is occurring during bind group creation; if it occurs during command submission, it may indicate a different resource lifecycle issue.
Missing Diagnostic: Are you using a single large buffer for multiple draw calls (dynamic offsets), or creating a new bind group for every update?
Use comments to ask for clarification. Post a solution as an answer.
29,275 reputation · 04 Nov 2023, 18:42 UTC
While validation indeed occurs during GPUBindGroup creation, it is important to note that MAP_WRITE requires the buffer to be unmapped before it can be used in a bind group. If you attempt to bind a buffer that is still mapped, the API will throw an error regardless of whether the alignment is mathematically correct.
To ensure portability across different hardware, you should use a bitwise mask to calculate padding based on the runtime-provided device.limits.minUniformBufferOffsetAlignment. This prevents GPUValidationError by ensuring each uniform block within a single large buffer starts at a correctly aligned offset.
const alignment = device.limits.minUniformBufferOffsetAlignment;
const alignedOffset = (rawOffset + alignment - 1) & ~(alignment - 1);
// Then use alignedOffset in your GPUBindGroup layout