Skip to content

Commit

Permalink
Introduce VertexStep: a stride and a step mode. (#2768)
Browse files Browse the repository at this point in the history
This is used in various places around render pipelines, passes, and
bundles.

The public `wgpu_core::pipeline::VertexBufferLayout` could use
`VertexStep` as well, but I think it's best to let that continue to
resemble `GPUVertexBufferLayout`.
  • Loading branch information
jimblandy authored Jun 14, 2022
1 parent a4352a1 commit 3a193ec
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 39 deletions.
21 changes: 9 additions & 12 deletions wgpu-core/src/command/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
);
Expand Down Expand Up @@ -996,8 +996,7 @@ impl IndexState {
struct VertexState {
buffer: Option<id::BufferId>,
range: Range<wgt::BufferAddress>,
stride: wgt::BufferAddress,
rate: wgt::VertexStepMode,
step: pipeline::VertexStep,
is_dirty: bool,
}

Expand All @@ -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,
}
}
Expand Down Expand Up @@ -1149,11 +1147,11 @@ impl<A: HalApi> State<A> {
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;
Expand Down Expand Up @@ -1211,13 +1209,12 @@ impl<A: HalApi> State<A> {

fn set_pipeline(
&mut self,
vertex_strides: &[(wgt::BufferAddress, wgt::VertexStepMode)],
steps: &[pipeline::VertexStep],
layout_ids: &[id::Valid<id::BindGroupLayoutId>],
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
Expand Down
44 changes: 23 additions & 21 deletions wgpu-core/src/command/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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,
};
}
Expand All @@ -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;
Expand Down Expand Up @@ -1340,24 +1341,25 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {

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 {
Expand Down
11 changes: 6 additions & 5 deletions wgpu-core/src/device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2458,13 +2458,14 @@ impl<A: HalApi> Device<A> {
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;
}
Expand Down Expand Up @@ -2862,7 +2863,7 @@ impl<A: HalApi> Device<A> {
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()),
};
Expand Down
21 changes: 20 additions & 1 deletion wgpu-core/src/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<A: hal::Api> {
pub(crate) raw: A::RenderPipeline,
Expand All @@ -365,7 +384,7 @@ pub struct RenderPipeline<A: hal::Api> {
pub(crate) pass_context: RenderPassContext,
pub(crate) flags: PipelineFlags,
pub(crate) strip_index_format: Option<wgt::IndexFormat>,
pub(crate) vertex_strides: Vec<(wgt::BufferAddress, wgt::VertexStepMode)>,
pub(crate) vertex_steps: Vec<VertexStep>,
pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,
pub(crate) life_guard: LifeGuard,
}
Expand Down

0 comments on commit 3a193ec

Please sign in to comment.