Introduce VertexStep: a stride and a step mode. (#2768)

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`.
This commit is contained in:
Jim Blandy 2022-06-13 21:42:03 -07:00 committed by GitHub
parent a4352a1dac
commit 3a193ec3d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 39 deletions

View File

@ -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<id::BufferId>,
range: Range<wgt::BufferAddress>,
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<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;
@ -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

View File

@ -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<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 {

View File

@ -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;
}
@ -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()),
};

View File

@ -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,
@ -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,
}