diff --git a/player/src/main.rs b/player/src/main.rs index e4638f32d5..e6c7143b68 100644 --- a/player/src/main.rs +++ b/player/src/main.rs @@ -263,7 +263,8 @@ impl GlobalExt for wgc::hub::Global { entries_length: entries.len(), }, id, - ); + ) + .unwrap(); } A::DestroyBindGroupLayout(id) => { self.bind_group_layout_destroy::(id); diff --git a/wgpu-core/src/binding_model.rs b/wgpu-core/src/binding_model.rs index dc726c3221..f749365994 100644 --- a/wgpu-core/src/binding_model.rs +++ b/wgpu-core/src/binding_model.rs @@ -47,6 +47,38 @@ pub struct BindGroupLayoutEntry { pub storage_texture_format: wgt::TextureFormat, } +#[derive(Clone, Debug)] +pub enum BindGroupLayoutEntryError { + NoVisibility, + UnexpectedHasDynamicOffset, + UnexpectedMultisampled, +} + +impl BindGroupLayoutEntry { + pub(crate) fn validate(&self) -> Result<(), BindGroupLayoutEntryError> { + if self.visibility.is_empty() { + return Err(BindGroupLayoutEntryError::NoVisibility); + } + match self.ty { + BindingType::UniformBuffer | BindingType::StorageBuffer => {} + _ => { + if self.has_dynamic_offset { + return Err(BindGroupLayoutEntryError::UnexpectedHasDynamicOffset); + } + } + } + match self.ty { + BindingType::SampledTexture => {} + _ => { + if self.multisampled { + return Err(BindGroupLayoutEntryError::UnexpectedMultisampled); + } + } + } + Ok(()) + } +} + #[repr(C)] #[derive(Debug)] pub struct BindGroupLayoutDescriptor { @@ -55,6 +87,12 @@ pub struct BindGroupLayoutDescriptor { pub entries_length: usize, } +#[derive(Clone, Debug)] +pub enum BindGroupLayoutError { + ConflictBinding(u32), + Entry(u32, BindGroupLayoutEntryError), +} + #[derive(Debug)] pub struct BindGroupLayout { pub(crate) raw: B::DescriptorSetLayout, diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 10024a15ad..e1da2eb72d 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -1085,12 +1085,21 @@ impl Global { device_id: id::DeviceId, desc: &binding_model::BindGroupLayoutDescriptor, id_in: Input, - ) -> id::BindGroupLayoutId { + ) -> Result { let mut token = Token::root(); let hub = B::hub(self); let entries = unsafe { slice::from_raw_parts(desc.entries, desc.entries_length) }; - let entry_map: FastHashMap<_, _> = - entries.iter().cloned().map(|b| (b.binding, b)).collect(); + let mut entry_map = FastHashMap::default(); + for entry in entries { + if let Err(e) = entry.validate() { + return Err(binding_model::BindGroupLayoutError::Entry(entry.binding, e)); + } + if entry_map.insert(entry.binding, entry.clone()).is_some() { + return Err(binding_model::BindGroupLayoutError::ConflictBinding( + entry.binding, + )); + } + } // TODO: deduplicate the bind group layouts at some level. // We can't do it right here, because in the remote scenario @@ -1102,7 +1111,7 @@ impl Global { .find(|(_, bgl)| bgl.entries == entry_map); if let Some((id, _)) = bind_group_layout_id { - return id; + return Ok(id); } } @@ -1157,7 +1166,7 @@ impl Global { }), None => (), }; - id + Ok(id) } pub fn bind_group_layout_destroy(