diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index 85f4758875..9985482b12 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -313,20 +313,22 @@ impl RenderBundleEncoder { first_instance, } => { let scope = PassErrorScope::Draw; - let (vertex_limit, instance_limit) = state.vertex_limits(); + let vertex_limits = state.vertex_limits(); let last_vertex = first_vertex + vertex_count; - if last_vertex > vertex_limit { + if last_vertex > vertex_limits.vertex_limit { return Err(DrawError::VertexBeyondLimit { last_vertex, - vertex_limit, + vertex_limit: vertex_limits.vertex_limit, + slot: vertex_limits.vertex_limit_slot, }) .map_pass_err(scope); } let last_instance = first_instance + instance_count; - if last_instance > instance_limit { + if last_instance > vertex_limits.instance_limit { return Err(DrawError::InstanceBeyondLimit { last_instance, - instance_limit, + instance_limit: vertex_limits.instance_limit, + slot: vertex_limits.instance_limit_slot, }) .map_pass_err(scope); } @@ -343,7 +345,7 @@ impl RenderBundleEncoder { } => { let scope = PassErrorScope::DrawIndexed; //TODO: validate that base_vertex + max_index() is within the provided range - let (_, instance_limit) = state.vertex_limits(); + let vertex_limits = state.vertex_limits(); let index_limit = state.index.limit(); let last_index = first_index + index_count; if last_index > index_limit { @@ -354,10 +356,11 @@ impl RenderBundleEncoder { .map_pass_err(scope); } let last_instance = first_instance + instance_count; - if last_instance > instance_limit { + if last_instance > vertex_limits.instance_limit { return Err(DrawError::InstanceBeyondLimit { last_instance, - instance_limit, + instance_limit: vertex_limits.instance_limit, + slot: vertex_limits.instance_limit_slot, }) .map_pass_err(scope); } @@ -855,6 +858,18 @@ impl PushConstantState { } } +#[derive(Debug)] +struct VertexLimitState { + /// Length of the shortest vertex rate vertex buffer + vertex_limit: u32, + /// Buffer slot which the shortest vertex rate vertex buffer is bound to + vertex_limit_slot: u32, + /// Length of the shortest instance rate vertex buffer + instance_limit: u32, + /// Buffer slot which the shortest instance rate vertex buffer is bound to + instance_limit_slot: u32, +} + #[derive(Debug)] struct State { trackers: TrackerSet, @@ -869,20 +884,34 @@ struct State { } impl State { - fn vertex_limits(&self) -> (u32, u32) { - let mut vertex_limit = !0; - let mut instance_limit = !0; - for vbs in &self.vertex { + fn vertex_limits(&self) -> VertexLimitState { + let mut vert_state = VertexLimitState { + vertex_limit: u32::MAX, + vertex_limit_slot: 0, + instance_limit: u32::MAX, + instance_limit_slot: 0, + }; + for (idx, vbs) in self.vertex.iter().enumerate() { if vbs.stride == 0 { continue; } let limit = ((vbs.range.end - vbs.range.start) / vbs.stride) as u32; match vbs.rate { - wgt::InputStepMode::Vertex => vertex_limit = vertex_limit.min(limit), - wgt::InputStepMode::Instance => instance_limit = instance_limit.min(limit), + wgt::InputStepMode::Vertex => { + if limit < vert_state.vertex_limit { + vert_state.vertex_limit = limit; + vert_state.vertex_limit_slot = idx as _; + } + } + wgt::InputStepMode::Instance => { + if limit < vert_state.instance_limit { + vert_state.instance_limit = limit; + vert_state.instance_limit_slot = idx as _; + } + } } } - (vertex_limit, instance_limit) + vert_state } fn invalidate_group_from(&mut self, slot: usize) { diff --git a/wgpu-core/src/command/draw.rs b/wgpu-core/src/command/draw.rs index fe781b8e60..c589d55d89 100644 --- a/wgpu-core/src/command/draw.rs +++ b/wgpu-core/src/command/draw.rs @@ -36,12 +36,17 @@ pub enum DrawError { //expected: BindGroupLayoutId, //provided: Option<(BindGroupLayoutId, BindGroupId)>, }, - #[error("vertex {last_vertex} extends beyond limit {vertex_limit}. Did you bind the correct `Vertex` step-rate vertex buffer?")] - VertexBeyondLimit { last_vertex: u32, vertex_limit: u32 }, - #[error("instance {last_instance} extends beyond limit {instance_limit}. Did you bind the correct `Instance` step-rate vertex buffer?")] + #[error("vertex {last_vertex} extends beyond limit {vertex_limit} imposed by the buffer in slot {slot}. Did you bind the correct `Vertex` step-rate vertex buffer?")] + VertexBeyondLimit { + last_vertex: u32, + vertex_limit: u32, + slot: u32, + }, + #[error("instance {last_instance} extends beyond limit {instance_limit} imposed by the buffer in slot {slot}. Did you bind the correct `Instance` step-rate vertex buffer?")] InstanceBeyondLimit { last_instance: u32, instance_limit: u32, + slot: u32, }, #[error("index {last_index} extends beyond limit {index_limit}. Did you bind the correct index buffer?")] IndexBeyondLimit { last_index: u32, index_limit: u32 }, diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 46d4ceb825..d724bca260 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -274,23 +274,40 @@ impl VertexBufferState { #[derive(Debug, Default)] struct VertexState { inputs: ArrayVec<[VertexBufferState; MAX_VERTEX_BUFFERS]>, + /// Length of the shortest vertex rate vertex buffer vertex_limit: u32, + /// Buffer slot which the shortest vertex rate vertex buffer is bound to + vertex_limit_slot: u32, + /// Length of the shortest instance rate vertex buffer instance_limit: u32, + /// Buffer slot which the shortest instance rate vertex buffer is bound to + instance_limit_slot: u32, + /// Total amount of buffers required by the pipeline. buffers_required: u32, } impl VertexState { fn update_limits(&mut self) { - self.vertex_limit = !0; - self.instance_limit = !0; - for vbs in &self.inputs { + self.vertex_limit = u32::MAX; + self.instance_limit = u32::MAX; + for (idx, vbs) in self.inputs.iter().enumerate() { if vbs.stride == 0 || !vbs.bound { continue; } let limit = (vbs.total_size / vbs.stride) as u32; match vbs.rate { - InputStepMode::Vertex => self.vertex_limit = self.vertex_limit.min(limit), - InputStepMode::Instance => self.instance_limit = self.instance_limit.min(limit), + InputStepMode::Vertex => { + if limit < self.vertex_limit { + self.vertex_limit = limit; + self.vertex_limit_slot = idx as _; + } + } + InputStepMode::Instance => { + if limit < self.instance_limit { + self.instance_limit = limit; + self.instance_limit_slot = idx as _; + } + } } } } @@ -1427,6 +1444,7 @@ impl Global { return Err(DrawError::VertexBeyondLimit { last_vertex, vertex_limit, + slot: state.vertex.vertex_limit_slot, }) .map_pass_err(scope); } @@ -1436,6 +1454,7 @@ impl Global { return Err(DrawError::InstanceBeyondLimit { last_instance, instance_limit, + slot: state.vertex.instance_limit_slot, }) .map_pass_err(scope); } @@ -1473,6 +1492,7 @@ impl Global { return Err(DrawError::InstanceBeyondLimit { last_instance, instance_limit, + slot: state.vertex.instance_limit_slot, }) .map_pass_err(scope); }