Skip to content

Commit c868142

Browse files
Validate vertex and index buffer alignment (#7929)
1 parent ae946db commit c868142

File tree

9 files changed

+46
-6
lines changed

9 files changed

+46
-6
lines changed

cts_runner/test.lst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ webgpu:api,validation,encoding,cmds,index_access:*
2929
//FAIL: webgpu:api,validation,encoding,cmds,render,draw:*
3030
webgpu:api,validation,encoding,cmds,render,draw:index_buffer_OOB:*
3131
webgpu:api,validation,encoding,cmds,render,draw:unused_buffer_bound:*
32-
webgpu:api,validation,encoding,cmds,render,setIndexBuffer:index_buffer_state:*
33-
webgpu:api,validation,encoding,cmds,render,setVertexBuffer:vertex_buffer_state:*
32+
webgpu:api,validation,encoding,cmds,render,setIndexBuffer:*
33+
webgpu:api,validation,encoding,cmds,render,setVertexBuffer:*
3434
webgpu:api,validation,encoding,encoder_state:*
3535
webgpu:api,validation,encoding,encoder_open_state:non_pass_commands:*
3636
webgpu:api,validation,encoding,encoder_open_state:render_pass_commands:*

wgpu-core/src/command/bundle.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,13 @@ fn set_index_buffer(
622622
buffer.same_device(&state.device)?;
623623
buffer.check_usage(wgt::BufferUsages::INDEX)?;
624624

625+
if offset % u64::try_from(index_format.byte_size()).unwrap() != 0 {
626+
return Err(RenderCommandError::UnalignedIndexBuffer {
627+
offset,
628+
alignment: index_format.byte_size(),
629+
}
630+
.into());
631+
}
625632
let end = offset + buffer.resolve_binding_size(offset, size)?;
626633

627634
state
@@ -663,6 +670,9 @@ fn set_vertex_buffer(
663670
buffer.same_device(&state.device)?;
664671
buffer.check_usage(wgt::BufferUsages::VERTEX)?;
665672

673+
if offset % wgt::VERTEX_ALIGNMENT != 0 {
674+
return Err(RenderCommandError::UnalignedVertexBuffer { slot, offset }.into());
675+
}
666676
let end = offset + buffer.resolve_binding_size(offset, size)?;
667677

668678
state

wgpu-core/src/command/draw.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ pub enum RenderCommandError {
7373
BindGroupIndexOutOfRange(#[from] pass::BindGroupIndexOutOfRange),
7474
#[error("Vertex buffer index {index} is greater than the device's requested `max_vertex_buffers` limit {max}")]
7575
VertexBufferIndexOutOfRange { index: u32, max: u32 },
76+
#[error(
77+
"Offset {offset} for vertex buffer in slot {slot} is not a multiple of `VERTEX_ALIGNMENT`"
78+
)]
79+
UnalignedVertexBuffer { slot: u32, offset: u64 },
80+
#[error("Offset {offset} for index buffer is not a multiple of {alignment}")]
81+
UnalignedIndexBuffer { offset: u64, alignment: usize },
7682
#[error("Render pipeline targets are incompatible with render pass")]
7783
IncompatiblePipelineTargets(#[from] crate::device::RenderPassCompatibilityError),
7884
#[error("{0} writes to depth, while the pass has read-only depth access")]
@@ -116,6 +122,8 @@ impl WebGpuError for RenderCommandError {
116122

117123
Self::BindGroupIndexOutOfRange { .. }
118124
| Self::VertexBufferIndexOutOfRange { .. }
125+
| Self::UnalignedIndexBuffer { .. }
126+
| Self::UnalignedVertexBuffer { .. }
119127
| Self::IncompatibleDepthAccess(..)
120128
| Self::IncompatibleStencilAccess(..)
121129
| Self::InvalidViewportRectSize { .. }

wgpu-core/src/command/render.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2344,6 +2344,13 @@ fn set_index_buffer(
23442344

23452345
buffer.check_usage(BufferUsages::INDEX)?;
23462346

2347+
if offset % u64::try_from(index_format.byte_size()).unwrap() != 0 {
2348+
return Err(RenderCommandError::UnalignedIndexBuffer {
2349+
offset,
2350+
alignment: index_format.byte_size(),
2351+
}
2352+
.into());
2353+
}
23472354
let (binding, resolved_size) = buffer
23482355
.binding(offset, size, state.general.snatch_guard)
23492356
.map_err(RenderCommandError::from)?;
@@ -2397,6 +2404,9 @@ fn set_vertex_buffer(
23972404

23982405
buffer.check_usage(BufferUsages::VERTEX)?;
23992406

2407+
if offset % wgt::VERTEX_ALIGNMENT != 0 {
2408+
return Err(RenderCommandError::UnalignedVertexBuffer { slot, offset }.into());
2409+
}
24002410
let (binding, buffer_size) = buffer
24012411
.binding(offset, size, state.general.snatch_guard)
24022412
.map_err(RenderCommandError::from)?;

wgpu-core/src/device/resource.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3159,7 +3159,7 @@ impl Device {
31593159
limit: self.limits.max_vertex_buffer_array_stride,
31603160
});
31613161
}
3162-
if vb_state.array_stride % wgt::VERTEX_STRIDE_ALIGNMENT != 0 {
3162+
if vb_state.array_stride % wgt::VERTEX_ALIGNMENT != 0 {
31633163
return Err(pipeline::CreateRenderPipelineError::UnalignedVertexStride {
31643164
index: i as u32,
31653165
stride: vb_state.array_stride,

wgpu-core/src/pipeline.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ pub enum CreateRenderPipelineError {
512512
given: u32,
513513
limit: u32,
514514
},
515-
#[error("Vertex buffer {index} stride {stride} does not respect `VERTEX_STRIDE_ALIGNMENT`")]
515+
#[error("Vertex buffer {index} stride {stride} does not respect `VERTEX_ALIGNMENT`")]
516516
UnalignedVertexStride {
517517
index: u32,
518518
stride: wgt::BufferAddress,

wgpu-types/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,18 @@ pub const COPY_BUFFER_ALIGNMENT: BufferAddress = 4;
9797
/// [`get_mapped_range()`]: ../wgpu/struct.Buffer.html#method.get_mapped_range
9898
pub const MAP_ALIGNMENT: BufferAddress = 8;
9999

100+
/// [Vertex buffer offsets] and [strides] have to be a multiple of this number.
101+
///
102+
/// [Vertex buffer offsets]: ../wgpu/util/trait.RenderEncoder.html#tymethod.set_vertex_buffer
103+
/// [strides]: ../wgpu/struct.VertexBufferLayout.html#structfield.array_stride
104+
pub const VERTEX_ALIGNMENT: BufferAddress = 4;
105+
100106
/// [Vertex buffer strides] have to be a multiple of this number.
101107
///
102108
/// [Vertex buffer strides]: ../wgpu/struct.VertexBufferLayout.html#structfield.array_stride
109+
#[deprecated(note = "Use `VERTEX_ALIGNMENT` instead", since = "27.0.0")]
103110
pub const VERTEX_STRIDE_ALIGNMENT: BufferAddress = 4;
111+
104112
/// Ranges of [writes to push constant storage] must be at least this aligned.
105113
///
106114
/// [writes to push constant storage]: ../wgpu/struct.RenderPass.html#method.set_push_constants

wgpu/src/api/render_pipeline.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ impl RenderPipeline {
7676
pub struct VertexBufferLayout<'a> {
7777
/// The stride, in bytes, between elements of this buffer (between vertices).
7878
///
79-
/// This must be a multiple of [`VERTEX_STRIDE_ALIGNMENT`].
79+
/// This must be a multiple of [`VERTEX_ALIGNMENT`].
8080
pub array_stride: BufferAddress,
8181
/// How often this vertex buffer is "stepped" forward.
8282
pub step_mode: VertexStepMode,

wgpu/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,12 @@ pub use wgt::{
9090
TextureTransition, TextureUsages, TextureUses, TextureViewDimension, Trace, VertexAttribute,
9191
VertexFormat, VertexStepMode, WasmNotSend, WasmNotSendSync, WasmNotSync, COPY_BUFFER_ALIGNMENT,
9292
COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, PUSH_CONSTANT_ALIGNMENT,
93-
QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, VERTEX_STRIDE_ALIGNMENT,
93+
QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, VERTEX_ALIGNMENT,
9494
};
95+
96+
#[expect(deprecated)]
97+
pub use wgt::VERTEX_STRIDE_ALIGNMENT;
98+
9599
// wasm-only types, we try to keep as many types non-platform
96100
// specific, but these need to depend on web-sys.
97101
#[cfg(web)]

0 commit comments

Comments
 (0)