Validate vertex and index buffer alignment (#7929)

This commit is contained in:
Andy Leiserson 2025-07-11 14:43:03 -07:00 committed by GitHub
parent ae946dbb8c
commit c868142709
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 46 additions and 6 deletions

View File

@ -29,8 +29,8 @@ webgpu:api,validation,encoding,cmds,index_access:*
//FAIL: webgpu:api,validation,encoding,cmds,render,draw:*
webgpu:api,validation,encoding,cmds,render,draw:index_buffer_OOB:*
webgpu:api,validation,encoding,cmds,render,draw:unused_buffer_bound:*
webgpu:api,validation,encoding,cmds,render,setIndexBuffer:index_buffer_state:*
webgpu:api,validation,encoding,cmds,render,setVertexBuffer:vertex_buffer_state:*
webgpu:api,validation,encoding,cmds,render,setIndexBuffer:*
webgpu:api,validation,encoding,cmds,render,setVertexBuffer:*
webgpu:api,validation,encoding,encoder_state:*
webgpu:api,validation,encoding,encoder_open_state:non_pass_commands:*
webgpu:api,validation,encoding,encoder_open_state:render_pass_commands:*

View File

@ -622,6 +622,13 @@ fn set_index_buffer(
buffer.same_device(&state.device)?;
buffer.check_usage(wgt::BufferUsages::INDEX)?;
if offset % u64::try_from(index_format.byte_size()).unwrap() != 0 {
return Err(RenderCommandError::UnalignedIndexBuffer {
offset,
alignment: index_format.byte_size(),
}
.into());
}
let end = offset + buffer.resolve_binding_size(offset, size)?;
state
@ -663,6 +670,9 @@ fn set_vertex_buffer(
buffer.same_device(&state.device)?;
buffer.check_usage(wgt::BufferUsages::VERTEX)?;
if offset % wgt::VERTEX_ALIGNMENT != 0 {
return Err(RenderCommandError::UnalignedVertexBuffer { slot, offset }.into());
}
let end = offset + buffer.resolve_binding_size(offset, size)?;
state

View File

@ -73,6 +73,12 @@ pub enum RenderCommandError {
BindGroupIndexOutOfRange(#[from] pass::BindGroupIndexOutOfRange),
#[error("Vertex buffer index {index} is greater than the device's requested `max_vertex_buffers` limit {max}")]
VertexBufferIndexOutOfRange { index: u32, max: u32 },
#[error(
"Offset {offset} for vertex buffer in slot {slot} is not a multiple of `VERTEX_ALIGNMENT`"
)]
UnalignedVertexBuffer { slot: u32, offset: u64 },
#[error("Offset {offset} for index buffer is not a multiple of {alignment}")]
UnalignedIndexBuffer { offset: u64, alignment: usize },
#[error("Render pipeline targets are incompatible with render pass")]
IncompatiblePipelineTargets(#[from] crate::device::RenderPassCompatibilityError),
#[error("{0} writes to depth, while the pass has read-only depth access")]
@ -116,6 +122,8 @@ impl WebGpuError for RenderCommandError {
Self::BindGroupIndexOutOfRange { .. }
| Self::VertexBufferIndexOutOfRange { .. }
| Self::UnalignedIndexBuffer { .. }
| Self::UnalignedVertexBuffer { .. }
| Self::IncompatibleDepthAccess(..)
| Self::IncompatibleStencilAccess(..)
| Self::InvalidViewportRectSize { .. }

View File

@ -2344,6 +2344,13 @@ fn set_index_buffer(
buffer.check_usage(BufferUsages::INDEX)?;
if offset % u64::try_from(index_format.byte_size()).unwrap() != 0 {
return Err(RenderCommandError::UnalignedIndexBuffer {
offset,
alignment: index_format.byte_size(),
}
.into());
}
let (binding, resolved_size) = buffer
.binding(offset, size, state.general.snatch_guard)
.map_err(RenderCommandError::from)?;
@ -2397,6 +2404,9 @@ fn set_vertex_buffer(
buffer.check_usage(BufferUsages::VERTEX)?;
if offset % wgt::VERTEX_ALIGNMENT != 0 {
return Err(RenderCommandError::UnalignedVertexBuffer { slot, offset }.into());
}
let (binding, buffer_size) = buffer
.binding(offset, size, state.general.snatch_guard)
.map_err(RenderCommandError::from)?;

View File

@ -3159,7 +3159,7 @@ impl Device {
limit: self.limits.max_vertex_buffer_array_stride,
});
}
if vb_state.array_stride % wgt::VERTEX_STRIDE_ALIGNMENT != 0 {
if vb_state.array_stride % wgt::VERTEX_ALIGNMENT != 0 {
return Err(pipeline::CreateRenderPipelineError::UnalignedVertexStride {
index: i as u32,
stride: vb_state.array_stride,

View File

@ -512,7 +512,7 @@ pub enum CreateRenderPipelineError {
given: u32,
limit: u32,
},
#[error("Vertex buffer {index} stride {stride} does not respect `VERTEX_STRIDE_ALIGNMENT`")]
#[error("Vertex buffer {index} stride {stride} does not respect `VERTEX_ALIGNMENT`")]
UnalignedVertexStride {
index: u32,
stride: wgt::BufferAddress,

View File

@ -97,10 +97,18 @@ pub const COPY_BUFFER_ALIGNMENT: BufferAddress = 4;
/// [`get_mapped_range()`]: ../wgpu/struct.Buffer.html#method.get_mapped_range
pub const MAP_ALIGNMENT: BufferAddress = 8;
/// [Vertex buffer offsets] and [strides] have to be a multiple of this number.
///
/// [Vertex buffer offsets]: ../wgpu/util/trait.RenderEncoder.html#tymethod.set_vertex_buffer
/// [strides]: ../wgpu/struct.VertexBufferLayout.html#structfield.array_stride
pub const VERTEX_ALIGNMENT: BufferAddress = 4;
/// [Vertex buffer strides] have to be a multiple of this number.
///
/// [Vertex buffer strides]: ../wgpu/struct.VertexBufferLayout.html#structfield.array_stride
#[deprecated(note = "Use `VERTEX_ALIGNMENT` instead", since = "27.0.0")]
pub const VERTEX_STRIDE_ALIGNMENT: BufferAddress = 4;
/// Ranges of [writes to push constant storage] must be at least this aligned.
///
/// [writes to push constant storage]: ../wgpu/struct.RenderPass.html#method.set_push_constants

View File

@ -76,7 +76,7 @@ impl RenderPipeline {
pub struct VertexBufferLayout<'a> {
/// The stride, in bytes, between elements of this buffer (between vertices).
///
/// This must be a multiple of [`VERTEX_STRIDE_ALIGNMENT`].
/// This must be a multiple of [`VERTEX_ALIGNMENT`].
pub array_stride: BufferAddress,
/// How often this vertex buffer is "stepped" forward.
pub step_mode: VertexStepMode,

View File

@ -90,8 +90,12 @@ pub use wgt::{
TextureTransition, TextureUsages, TextureUses, TextureViewDimension, Trace, VertexAttribute,
VertexFormat, VertexStepMode, WasmNotSend, WasmNotSendSync, WasmNotSync, COPY_BUFFER_ALIGNMENT,
COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, PUSH_CONSTANT_ALIGNMENT,
QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, VERTEX_STRIDE_ALIGNMENT,
QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, VERTEX_ALIGNMENT,
};
#[expect(deprecated)]
pub use wgt::VERTEX_STRIDE_ALIGNMENT;
// wasm-only types, we try to keep as many types non-platform
// specific, but these need to depend on web-sys.
#[cfg(web)]