diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index c84d0838c..bd3a7b8f5 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -376,7 +376,7 @@ impl RenderBundleEncoder { state.pipeline_layout = Some(pipeline.layout_id.value); state.set_pipeline( - &pipeline.vertex_strides, + &pipeline.vertex_steps, &layout.bind_group_layout_ids, &layout.push_constant_ranges, ); @@ -996,8 +996,7 @@ impl IndexState { struct VertexState { buffer: Option, range: Range, - stride: wgt::BufferAddress, - rate: wgt::VertexStepMode, + step: pipeline::VertexStep, is_dirty: bool, } @@ -1008,8 +1007,7 @@ impl VertexState { Self { buffer: None, range: 0..0, - stride: 0, - rate: wgt::VertexStepMode::Vertex, + step: pipeline::VertexStep::default(), is_dirty: false, } } @@ -1149,11 +1147,11 @@ impl State { instance_limit_slot: 0, }; for (idx, vbs) in self.vertex.iter().enumerate() { - if vbs.stride == 0 { + if vbs.step.stride == 0 { continue; } - let limit = ((vbs.range.end - vbs.range.start) / vbs.stride) as u32; - match vbs.rate { + let limit = ((vbs.range.end - vbs.range.start) / vbs.step.stride) as u32; + match vbs.step.mode { wgt::VertexStepMode::Vertex => { if limit < vert_state.vertex_limit { vert_state.vertex_limit = limit; @@ -1211,13 +1209,12 @@ impl State { fn set_pipeline( &mut self, - vertex_strides: &[(wgt::BufferAddress, wgt::VertexStepMode)], + steps: &[pipeline::VertexStep], layout_ids: &[id::Valid], push_constant_layouts: &[wgt::PushConstantRange], ) { - for (vs, &(stride, step_mode)) in self.vertex.iter_mut().zip(vertex_strides) { - vs.stride = stride; - vs.rate = step_mode; + for (vs, &step) in self.vertex.iter_mut().zip(steps) { + vs.step = step; } let push_constants_changed = self diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 5ce6fb3a6..67e9e55d4 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -17,7 +17,7 @@ use crate::{ hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, id, init_tracker::{MemoryInitKind, TextureInitRange, TextureInitTrackerAction}, - pipeline::PipelineFlags, + pipeline::{self, PipelineFlags}, resource::{self, Buffer, Texture, TextureView}, track::{TextureSelector, UsageConflict, UsageScope}, validation::{ @@ -298,16 +298,17 @@ impl IndexState { #[derive(Clone, Copy, Debug)] struct VertexBufferState { total_size: BufferAddress, - stride: BufferAddress, - rate: VertexStepMode, + step: pipeline::VertexStep, bound: bool, } impl VertexBufferState { const EMPTY: Self = Self { total_size: 0, - stride: 0, - rate: VertexStepMode::Vertex, + step: pipeline::VertexStep { + stride: 0, + mode: VertexStepMode::Vertex, + }, bound: false, }; } @@ -332,11 +333,11 @@ impl VertexState { self.vertex_limit = u32::MAX; self.instance_limit = u32::MAX; for (idx, vbs) in self.inputs.iter().enumerate() { - if vbs.stride == 0 || !vbs.bound { + if vbs.step.stride == 0 || !vbs.bound { continue; } - let limit = (vbs.total_size / vbs.stride) as u32; - match vbs.rate { + let limit = (vbs.total_size / vbs.step.stride) as u32; + match vbs.step.mode { VertexStepMode::Vertex => { if limit < self.vertex_limit { self.vertex_limit = limit; @@ -1340,24 +1341,25 @@ impl Global { state.index.pipeline_format = pipeline.strip_index_format; - let vertex_strides_len = pipeline.vertex_strides.len(); - state.vertex.buffers_required = vertex_strides_len as u32; + let vertex_steps_len = pipeline.vertex_steps.len(); + state.vertex.buffers_required = vertex_steps_len as u32; - while state.vertex.inputs.len() < vertex_strides_len { + // Initialize each `vertex.inputs[i].step` from + // `pipeline.vertex_steps[i]`. Enlarge `vertex.inputs` + // as necessary to accomodate all slots in the + // pipeline. If `vertex.inputs` is longer, fill the + // extra entries with default `VertexStep`s. + while state.vertex.inputs.len() < vertex_steps_len { state.vertex.inputs.push(VertexBufferState::EMPTY); } - // Update vertex buffer limits - for (vbs, &(stride, rate)) in - state.vertex.inputs.iter_mut().zip(&pipeline.vertex_strides) - { - vbs.stride = stride; - vbs.rate = rate; - } - for vbs in state.vertex.inputs.iter_mut().skip(vertex_strides_len) { - vbs.stride = 0; - vbs.rate = VertexStepMode::Vertex; + // This is worse as a `zip`, but it's close. + let mut steps = pipeline.vertex_steps.iter(); + for input in state.vertex.inputs.iter_mut() { + input.step = steps.next().cloned().unwrap_or_default(); } + + // Update vertex buffer limits. state.vertex.update_limits(); } RenderCommand::SetIndexBuffer { diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 796a12fa8..7021cc462 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -2458,13 +2458,14 @@ impl Device { let mut io = validation::StageIo::default(); let mut validated_stages = wgt::ShaderStages::empty(); - let mut vertex_strides = Vec::with_capacity(desc.vertex.buffers.len()); + let mut vertex_steps = Vec::with_capacity(desc.vertex.buffers.len()); let mut vertex_buffers = Vec::with_capacity(desc.vertex.buffers.len()); let mut total_attributes = 0; for (i, vb_state) in desc.vertex.buffers.iter().enumerate() { - vertex_strides - .alloc() - .init((vb_state.array_stride, vb_state.step_mode)); + vertex_steps.alloc().init(pipeline::VertexStep { + stride: vb_state.array_stride, + mode: vb_state.step_mode, + }); if vb_state.attributes.is_empty() { continue; } @@ -2862,7 +2863,7 @@ impl Device { pass_context, flags, strip_index_format: desc.primitive.strip_index_format, - vertex_strides, + vertex_steps, late_sized_buffer_groups, life_guard: LifeGuard::new(desc.label.borrow_or_default()), }; diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index 21b99b654..69b045b81 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -357,6 +357,25 @@ bitflags::bitflags! { } } +/// How a render pipeline will retrieve attributes from a particular vertex buffer. +#[derive(Clone, Copy, Debug)] +pub struct VertexStep { + /// The byte stride in the buffer between one attribute value and the next. + pub stride: wgt::BufferAddress, + + /// Whether the buffer is indexed by vertex number or instance number. + pub mode: wgt::VertexStepMode, +} + +impl Default for VertexStep { + fn default() -> Self { + Self { + stride: 0, + mode: wgt::VertexStepMode::Vertex, + } + } +} + #[derive(Debug)] pub struct RenderPipeline { pub(crate) raw: A::RenderPipeline, @@ -365,7 +384,7 @@ pub struct RenderPipeline { pub(crate) pass_context: RenderPassContext, pub(crate) flags: PipelineFlags, pub(crate) strip_index_format: Option, - pub(crate) vertex_strides: Vec<(wgt::BufferAddress, wgt::VertexStepMode)>, + pub(crate) vertex_steps: Vec, pub(crate) late_sized_buffer_groups: ArrayVec, pub(crate) life_guard: LifeGuard, }