diff --git a/wgpu-native/src/command/bind.rs b/wgpu-native/src/command/bind.rs index 41939dcec..a07f0fef7 100644 --- a/wgpu-native/src/command/bind.rs +++ b/wgpu-native/src/command/bind.rs @@ -22,9 +22,9 @@ pub struct BindGroupPair { } #[derive(Debug)] -pub enum LayoutChange { +pub enum LayoutChange<'a> { Unchanged, - Match(BindGroupId), + Match(BindGroupId, &'a [BufferAddress]), Mismatch, } @@ -33,7 +33,6 @@ pub enum Provision { Unchanged, Changed { was_compatible: bool, - now_compatible: bool, }, } @@ -93,7 +92,6 @@ impl BindGroupEntry { Provision::Changed { was_compatible, - now_compatible: self.expected_layout_id == Some(bind_group.layout_id), } } @@ -105,7 +103,8 @@ impl BindGroupEntry { Some(BindGroupPair { layout_id, ref group_id, - }) if layout_id == bind_group_layout_id => LayoutChange::Match(group_id.value), + }) if layout_id == bind_group_layout_id => + LayoutChange::Match(group_id.value, &self.dynamic_offsets), Some(_) | None => LayoutChange::Mismatch, } } else { @@ -168,36 +167,25 @@ impl Binder { match self.entries[index].provide(bind_group_id, bind_group, offsets) { Provision::Unchanged => None, - Provision::Changed { - now_compatible: false, - .. - } => { - trace!("\t\tnot compatible"); - None - } Provision::Changed { was_compatible, .. } => { - if self.entries[.. index].iter().all(|entry| entry.is_valid()) { - self.pipeline_layout_id.map(move |pipeline_layout_id| { - let end = if was_compatible { - trace!("\t\tgenerating follow-up sequence"); - MAX_BIND_GROUPS - } else { - index + 1 - }; - ( - pipeline_layout_id, - TakeSome { - iter: self.entries[index + 1 .. end] - .iter() - .map(|entry| entry.actual_value()), - }, - self.entries[index + 1 ..] + let compatible_count = self.compatible_count(); + if index < compatible_count { + let end = compatible_count + .min(if was_compatible { index + 1 } else { MAX_BIND_GROUPS }); + trace!("\t\tbinding up to {}", end); + Some(( + self.pipeline_layout_id?, + TakeSome { + iter: self.entries[index + 1 .. end] .iter() - .flat_map(|entry| entry.dynamic_offsets.as_slice()), - ) - }) + .map(|entry| entry.actual_value()), + }, + self.entries[index + 1 .. end] + .iter() + .flat_map(|entry| entry.dynamic_offsets.as_slice()), + )) } else { - trace!("\t\tbehind an incompatible"); + trace!("\t\tskipping above compatible {}", compatible_count); None } } @@ -213,4 +201,11 @@ impl Binder { } }) } + + fn compatible_count(&self) -> usize { + self.entries + .iter() + .position(|entry| !entry.is_valid()) + .unwrap_or(self.entries.len()) + } } diff --git a/wgpu-native/src/command/compute.rs b/wgpu-native/src/command/compute.rs index 755783df3..3461cb213 100644 --- a/wgpu-native/src/command/compute.rs +++ b/wgpu-native/src/command/compute.rs @@ -255,6 +255,7 @@ pub fn compute_pass_set_pipeline( pass.binder.pipeline_layout_id = Some(pipeline.layout_id.clone()); pass.binder .reset_expectations(pipeline_layout.bind_group_layout_ids.len()); + let mut is_compatible = true; for (index, (entry, &bgl_id)) in pass .binder @@ -263,15 +264,22 @@ pub fn compute_pass_set_pipeline( .zip(&pipeline_layout.bind_group_layout_ids) .enumerate() { - if let LayoutChange::Match(bg_id) = entry.expect_layout(bgl_id) { - let desc_set = bind_group_guard[bg_id].raw.raw(); - unsafe { - pass.raw.bind_compute_descriptor_sets( - &pipeline_layout.raw, - index, - iter::once(desc_set), - &[], - ); + match entry.expect_layout(bgl_id) { + LayoutChange::Match(bg_id, offsets) if is_compatible => { + let desc_set = bind_group_guard[bg_id].raw.raw(); + unsafe { + pass.raw.bind_compute_descriptor_sets( + &pipeline_layout.raw, + index, + iter::once(desc_set), + offsets.iter().map(|offset| *offset as u32), + ); + } + } + LayoutChange::Match(..) | + LayoutChange::Unchanged => {} + LayoutChange::Mismatch => { + is_compatible = false; } } } diff --git a/wgpu-native/src/command/render.rs b/wgpu-native/src/command/render.rs index 5ce504d78..9e9778238 100644 --- a/wgpu-native/src/command/render.rs +++ b/wgpu-native/src/command/render.rs @@ -593,6 +593,7 @@ pub fn render_pass_set_pipeline( pass.binder.pipeline_layout_id = Some(pipeline.layout_id.clone()); pass.binder .reset_expectations(pipeline_layout.bind_group_layout_ids.len()); + let mut is_compatible = true; for (index, (entry, &bgl_id)) in pass .binder @@ -601,15 +602,22 @@ pub fn render_pass_set_pipeline( .zip(&pipeline_layout.bind_group_layout_ids) .enumerate() { - if let LayoutChange::Match(bg_id) = entry.expect_layout(bgl_id) { - let desc_set = bind_group_guard[bg_id].raw.raw(); - unsafe { - pass.raw.bind_graphics_descriptor_sets( - &pipeline_layout.raw, - index, - iter::once(desc_set), - &[], - ); + match entry.expect_layout(bgl_id) { + LayoutChange::Match(bg_id, offsets) if is_compatible => { + let desc_set = bind_group_guard[bg_id].raw.raw(); + unsafe { + pass.raw.bind_graphics_descriptor_sets( + &pipeline_layout.raw, + index, + iter::once(desc_set), + offsets.iter().map(|offset| *offset as u32), + ); + } + } + LayoutChange::Match(..) | + LayoutChange::Unchanged => {} + LayoutChange::Mismatch => { + is_compatible = false; } } }