Skip to main content

wgpu_core/device/
bgl.rs

1use core::hash::{Hash, Hasher};
2
3use crate::{
4    binding_model::{self},
5    FastIndexMap,
6};
7
8/// Where a given BGL came from.
9#[derive(Debug, Copy, Clone, PartialEq, Eq)]
10pub enum Origin {
11    /// The bind group layout was created by the user and is present in the BGL resource pool.
12    Pool,
13    /// The bind group layout was derived and is not present in the BGL resource pool.
14    Derived,
15}
16
17/// A HashMap-like structure that stores a BindGroupLayouts [`wgt::BindGroupLayoutEntry`]s.
18///
19/// It is hashable, so bind group layouts can be deduplicated.
20#[derive(Debug, Default, Clone, Eq)]
21pub struct EntryMap {
22    /// We use a IndexMap here so that we can sort the entries by their binding index,
23    /// guaranteeing that the hash of equivalent layouts will be the same.
24    inner: FastIndexMap<u32, wgt::BindGroupLayoutEntry>,
25    /// We keep track of whether the map is sorted or not, so that we can assert that
26    /// it is sorted, so that PartialEq and Hash will be stable.
27    ///
28    /// We only need sorted if it is used in a Hash or PartialEq, so we never need
29    /// to actively sort it.
30    sorted: bool,
31}
32
33impl PartialEq for EntryMap {
34    fn eq(&self, other: &Self) -> bool {
35        self.assert_sorted();
36        other.assert_sorted();
37
38        self.inner == other.inner
39    }
40}
41
42impl Hash for EntryMap {
43    fn hash<H: Hasher>(&self, state: &mut H) {
44        self.assert_sorted();
45
46        // We don't need to hash the keys, since they are just extracted from the values.
47        //
48        // We know this is stable and will match the behavior of PartialEq as we ensure
49        // that the array is sorted.
50        for entry in self.inner.values() {
51            entry.hash(state);
52        }
53    }
54}
55
56impl EntryMap {
57    fn assert_sorted(&self) {
58        assert!(self.sorted);
59    }
60
61    /// Create a new [`EntryMap`] from a slice of [`wgt::BindGroupLayoutEntry`]s.
62    ///
63    /// Errors if there are duplicate bindings or if any binding index is greater than
64    /// the device's limits.
65    pub fn from_entries<BGLE>(
66        entries: &[BGLE],
67    ) -> Result<Self, binding_model::CreateBindGroupLayoutError>
68    where
69        BGLE: TryInto<wgt::BindGroupLayoutEntry> + Copy,
70        binding_model::CreateBindGroupLayoutError:
71            From<<BGLE as TryInto<wgt::BindGroupLayoutEntry>>::Error>,
72    {
73        let mut inner = FastIndexMap::with_capacity_and_hasher(entries.len(), Default::default());
74        for entry in entries {
75            let entry: wgt::BindGroupLayoutEntry = (*entry).try_into()?;
76            if inner.insert(entry.binding, entry).is_some() {
77                return Err(binding_model::CreateBindGroupLayoutError::ConflictBinding(
78                    entry.binding,
79                ));
80            }
81        }
82        inner.sort_unstable_keys();
83
84        Ok(Self {
85            inner,
86            sorted: true,
87        })
88    }
89
90    /// Get the count of [`wgt::BindGroupLayoutEntry`]s in this map.
91    pub fn len(&self) -> usize {
92        self.inner.len()
93    }
94
95    /// Get the [`wgt::BindGroupLayoutEntry`] for the given binding index.
96    pub fn get(&self, binding: u32) -> Option<&wgt::BindGroupLayoutEntry> {
97        self.inner.get(&binding)
98    }
99
100    /// Iterator over all the binding indices in this map.
101    pub fn indices(&self) -> impl ExactSizeIterator<Item = u32> + '_ {
102        self.inner.keys().copied()
103    }
104
105    /// Iterator over all the [`wgt::BindGroupLayoutEntry`]s in this map.
106    pub fn values(&self) -> impl ExactSizeIterator<Item = &wgt::BindGroupLayoutEntry> + '_ {
107        self.inner.values()
108    }
109
110    pub fn iter(&self) -> impl ExactSizeIterator<Item = (&u32, &wgt::BindGroupLayoutEntry)> + '_ {
111        self.inner.iter()
112    }
113
114    pub fn is_empty(&self) -> bool {
115        self.inner.is_empty()
116    }
117
118    pub fn contains_key(&self, key: u32) -> bool {
119        self.inner.contains_key(&key)
120    }
121
122    pub fn entry(&mut self, key: u32) -> indexmap::map::Entry<'_, u32, wgt::BindGroupLayoutEntry> {
123        self.sorted = false;
124        self.inner.entry(key)
125    }
126
127    pub fn sort(&mut self) {
128        self.inner.sort_unstable_keys();
129        self.sorted = true;
130    }
131}