Validate sampler type in create_bind_group

This commit is contained in:
Gabriel Majeri 2020-06-19 17:19:04 +03:00
parent d7d0fd5dfe
commit 69b41dc0d3
4 changed files with 107 additions and 45 deletions

View File

@ -301,7 +301,8 @@ impl GlobalExt for wgc::hub::Global<IdentityPassThroughFactory> {
bindings: &entry_vec,
},
id,
);
)
.unwrap();
}
A::DestroyBindGroup(id) => {
self.bind_group_destroy::<B>(id);

View File

@ -28,6 +28,27 @@ pub enum BindGroupLayoutError {
ArrayUnsupported,
}
#[derive(Clone, Debug)]
pub enum BindGroupError {
/// Number of bindings in bind group descriptor does not match
/// the number of bindings defined in the bind group layout.
BindingsNumMismatch { actual: usize, expected: usize },
/// Unable to find a corresponding declaration for the given binding,
MissingBindingDeclaration(u32),
/// The given binding has a different type than the one in the layout.
WrongBindingType {
// Index of the binding
binding: u32,
// The type given to the function
actual: wgt::BindingType,
// Human-readable description of expected types
expected: &'static str,
},
/// The given sampler is/is not a comparison sampler,
/// while the layout type indicates otherwise.
WrongSamplerComparison,
}
pub(crate) type BindEntryMap = FastHashMap<u32, wgt::BindGroupLayoutEntry>;
#[derive(Debug)]

View File

@ -3,7 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{
binding_model, command, conv,
binding_model::{self, BindGroupError},
command, conv,
hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Hub, Input, Token},
id, pipeline, resource, swap_chain,
track::{BufferState, TextureState, TrackerSet},
@ -1115,6 +1116,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
ref_count: device.life_guard.add_ref(),
},
life_guard: LifeGuard::new(),
comparison: info.comparison.is_some(),
};
let ref_count = sampler.life_guard.add_ref();
@ -1398,7 +1400,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
device_id: id::DeviceId,
desc: &binding_model::BindGroupDescriptor,
id_in: Input<G, id::BindGroupId>,
) -> id::BindGroupId {
) -> Result<id::BindGroupId, BindGroupError> {
use crate::binding_model::BindingResource as Br;
let hub = B::hub(self);
let mut token = Token::root();
@ -1406,7 +1410,14 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let device = &device_guard[device_id];
let (bind_group_layout_guard, mut token) = hub.bind_group_layouts.read(&mut token);
let bind_group_layout = &bind_group_layout_guard[desc.layout];
assert_eq!(desc.bindings.len(), bind_group_layout.entries.len(), "Bind group has {} entries and bind group layout has {} entries, they should be the same.", desc.bindings.len(), bind_group_layout.entries.len());
// Check that the number of bindings in the descriptor matches
// the number of bindings in the layout.
let actual = desc.bindings.len();
let expected = bind_group_layout.entries.len();
if actual != expected {
return Err(BindGroupError::BindingsNumMismatch { expected, actual });
}
let mut desc_set = unsafe {
let mut desc_sets = ArrayVec::<[_; 1]>::new();
@ -1447,19 +1458,28 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
//TODO: group writes into contiguous sections
let mut writes = Vec::new();
for b in desc.bindings {
let binding = b.binding;
// Find the corresponding declaration in the layout
let decl = bind_group_layout
.entries
.get(&b.binding)
.expect("Failed to find binding declaration for binding");
.get(&binding)
.ok_or(BindGroupError::MissingBindingDeclaration(binding))?;
let descriptors: SmallVec<[_; 1]> = match b.resource {
binding_model::BindingResource::Buffer(ref bb) => {
Br::Buffer(ref bb) => {
let (pub_usage, internal_use, min_size) = match decl.ty {
wgt::BindingType::UniformBuffer { dynamic: _, min_binding_size } => (
wgt::BindingType::UniformBuffer {
dynamic: _,
min_binding_size,
} => (
wgt::BufferUsage::UNIFORM,
resource::BufferUse::UNIFORM,
min_binding_size,
),
wgt::BindingType::StorageBuffer { dynamic: _, min_binding_size, readonly } => (
wgt::BindingType::StorageBuffer {
dynamic: _,
min_binding_size,
readonly,
} => (
wgt::BufferUsage::STORAGE,
if readonly {
resource::BufferUse::STORAGE_STORE
@ -1468,10 +1488,13 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
},
min_binding_size,
),
wgt::BindingType::Sampler { .. }
| wgt::BindingType::StorageTexture { .. }
| wgt::BindingType::SampledTexture { .. } | _ => {
panic!("Mismatched buffer binding type for {:?}. Expected a type of UniformBuffer, StorageBuffer or ReadonlyStorageBuffer", decl)
_ => {
return Err(BindGroupError::WrongBindingType {
binding,
actual: decl.ty.clone(),
expected:
"UniformBuffer, StorageBuffer or ReadonlyStorageBuffer",
})
}
};
@ -1519,19 +1542,31 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
};
SmallVec::from([hal::pso::Descriptor::Buffer(&buffer.raw, sub_range)])
}
binding_model::BindingResource::Sampler(id) => {
Br::Sampler(id) => {
match decl.ty {
wgt::BindingType::Sampler{ .. } => {}
_ => panic!("Mismatched sampler binding type in {:?}. Expected a type of Sampler", decl.ty),
}
wgt::BindingType::Sampler { comparison } => {
let sampler = used
.samplers
.use_extend(&*sampler_guard, id, (), ())
.unwrap();
let sampler = used
.samplers
.use_extend(&*sampler_guard, id, (), ())
.unwrap();
SmallVec::from([hal::pso::Descriptor::Sampler(&sampler.raw)])
// Check the actual sampler to also (not) be a comparison sampler
if sampler.comparison != comparison {
return Err(BindGroupError::WrongSamplerComparison);
}
SmallVec::from([hal::pso::Descriptor::Sampler(&sampler.raw)])
}
_ => {
return Err(BindGroupError::WrongBindingType {
binding,
actual: decl.ty.clone(),
expected: "Sampler",
})
}
}
}
binding_model::BindingResource::TextureView(id) => {
Br::TextureView(id) => {
let view = used
.views
.use_extend(&*texture_view_guard, id, (), ())
@ -1549,7 +1584,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
resource::TextureUse::STORAGE_STORE
},
),
_ => panic!("Mismatched texture binding type in {:?}. Expected a type of SampledTexture, ReadonlyStorageTexture or WriteonlyStorageTexture", decl),
_ => return Err(BindGroupError::WrongBindingType {
binding,
actual: decl.ty.clone(),
expected: "SampledTexture, ReadonlyStorageTexture or WriteonlyStorageTexture"
})
};
match view.inner {
resource::TextureViewInner::Native {
@ -1582,7 +1621,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
}
}
binding_model::BindingResource::TextureViewArray(ref bindings_array) => {
Br::TextureViewArray(ref bindings_array) => {
assert!(
device.capabilities.contains(wgt::Capabilities::SAMPLED_TEXTURE_BINDING_ARRAY),
"Capability SAMPLED_TEXTURE_BINDING_ARRAY must be supported to use TextureViewArrays in a bind group"
@ -1603,11 +1642,16 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
let (pub_usage, internal_use) = match decl.ty {
wgt::BindingType::SampledTexture { .. } => (
wgt::TextureUsage::SAMPLED,
resource::TextureUse::SAMPLED,
),
_ => panic!("Mismatched texture binding type in {:?}. Expected a type of SampledTextureArray", decl),
wgt::BindingType::SampledTexture { .. } => {
(wgt::TextureUsage::SAMPLED, resource::TextureUse::SAMPLED)
}
_ => {
return Err(BindGroupError::WrongBindingType {
binding,
actual: decl.ty.clone(),
expected: "SampledTextureArray",
})
}
};
bindings_array
.iter()
@ -1698,20 +1742,14 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.iter()
.map(|entry| {
let res = match entry.resource {
binding_model::BindingResource::Buffer(ref binding) => {
trace::BindingResource::Buffer {
id: binding.buffer_id,
offset: binding.offset,
size: binding.size,
}
}
binding_model::BindingResource::TextureView(id) => {
trace::BindingResource::TextureView(id)
}
binding_model::BindingResource::Sampler(id) => {
trace::BindingResource::Sampler(id)
}
binding_model::BindingResource::TextureViewArray(ref binding_array) => {
Br::Buffer(ref binding) => trace::BindingResource::Buffer {
id: binding.buffer_id,
offset: binding.offset,
size: binding.size,
},
Br::TextureView(id) => trace::BindingResource::TextureView(id),
Br::Sampler(id) => trace::BindingResource::Sampler(id),
Br::TextureViewArray(ref binding_array) => {
trace::BindingResource::TextureViewArray(binding_array.to_vec())
}
};
@ -1728,7 +1766,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.bind_groups
.init(id, ref_count, PhantomData)
.unwrap();
id
Ok(id)
}
pub fn bind_group_destroy<B: GfxBackend>(&self, bind_group_id: id::BindGroupId) {

View File

@ -215,6 +215,8 @@ pub struct Sampler<B: hal::Backend> {
pub(crate) raw: B::Sampler,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) life_guard: LifeGuard,
/// `true` if this is a comparison sampler
pub(crate) comparison: bool,
}
impl<B: hal::Backend> Borrow<RefCount> for Sampler<B> {