wgpu_core/track/
metadata.rs1use alloc::vec::Vec;
4
5use bit_vec::BitVec;
6use wgt::strict_assert;
7
8#[derive(Debug)]
16pub(super) struct ResourceMetadata<T: Clone> {
17    owned: BitVec<usize>,
19
20    resources: Vec<Option<T>>,
22}
23
24impl<T: Clone> ResourceMetadata<T> {
25    pub(super) fn new() -> Self {
26        Self {
27            owned: BitVec::default(),
28            resources: Vec::new(),
29        }
30    }
31
32    pub(super) fn set_size(&mut self, size: usize) {
33        self.resources.resize(size, None);
34        resize_bitvec(&mut self.owned, size);
35    }
36
37    pub(super) fn clear(&mut self) {
38        self.resources.clear();
39        self.owned.clear();
40    }
41
42    #[cfg_attr(not(feature = "strict_asserts"), allow(unused_variables))]
47    pub(super) fn tracker_assert_in_bounds(&self, index: usize) {
48        strict_assert!(index < self.owned.len());
49        strict_assert!(index < self.resources.len());
50        strict_assert!(if self.contains(index) {
51            self.resources[index].is_some()
52        } else {
53            true
54        });
55    }
56
57    pub(super) fn is_empty(&self) -> bool {
61        !self.owned.any()
62    }
63
64    pub(super) fn contains(&self, index: usize) -> bool {
66        self.owned.get(index).unwrap_or(false)
67    }
68
69    #[inline(always)]
76    pub(super) unsafe fn contains_unchecked(&self, index: usize) -> bool {
77        unsafe { self.owned.get(index).unwrap_unchecked() }
78    }
79
80    #[inline(always)]
93    pub(super) unsafe fn insert(&mut self, index: usize, resource: T) -> &T {
94        self.owned.set(index, true);
95        let resource_dst = unsafe { self.resources.get_unchecked_mut(index) };
96        resource_dst.insert(resource)
97    }
98
99    #[inline(always)]
106    pub(super) unsafe fn get_resource_unchecked(&self, index: usize) -> &T {
107        unsafe {
108            self.resources
109                .get_unchecked(index)
110                .as_ref()
111                .unwrap_unchecked()
112        }
113    }
114
115    pub(super) fn owned_resources(&self) -> impl Iterator<Item = &T> + '_ {
117        if !self.owned.is_empty() {
118            self.tracker_assert_in_bounds(self.owned.len() - 1)
119        };
120        iterate_bitvec_indices(&self.owned).map(move |index| {
121            let resource = unsafe { self.resources.get_unchecked(index) };
122            resource.as_ref().unwrap()
123        })
124    }
125
126    pub(super) fn owned_indices(&self) -> impl Iterator<Item = usize> + '_ {
128        if !self.owned.is_empty() {
129            self.tracker_assert_in_bounds(self.owned.len() - 1)
130        };
131        iterate_bitvec_indices(&self.owned)
132    }
133
134    pub(super) unsafe fn remove(&mut self, index: usize) {
136        unsafe {
137            *self.resources.get_unchecked_mut(index) = None;
138        }
139        self.owned.set(index, false);
140    }
141}
142
143pub(super) enum ResourceMetadataProvider<'a, T: Clone> {
148    Direct { resource: &'a T },
150    Indirect { metadata: &'a ResourceMetadata<T> },
152}
153impl<T: Clone> ResourceMetadataProvider<'_, T> {
154    #[inline(always)]
160    pub(super) unsafe fn get(&self, index: usize) -> &T {
161        match self {
162            ResourceMetadataProvider::Direct { resource } => resource,
163            ResourceMetadataProvider::Indirect { metadata } => {
164                metadata.tracker_assert_in_bounds(index);
165                {
166                    let resource = unsafe { metadata.resources.get_unchecked(index) }.as_ref();
167                    unsafe { resource.unwrap_unchecked() }
168                }
169            }
170        }
171    }
172}
173
174fn resize_bitvec<B: bit_vec::BitBlock>(vec: &mut BitVec<B>, size: usize) {
176    let owned_size_to_grow = size.checked_sub(vec.len());
177    if let Some(delta) = owned_size_to_grow {
178        if delta != 0 {
179            vec.grow(delta, false);
180        }
181    } else {
182        vec.truncate(size);
183    }
184}
185
186fn iterate_bitvec_indices(ownership: &BitVec<usize>) -> impl Iterator<Item = usize> + '_ {
190    const BITS_PER_BLOCK: usize = usize::BITS as usize;
191
192    let size = ownership.len();
193
194    ownership
195        .blocks()
196        .enumerate()
197        .filter(|&(_, word)| word != 0)
198        .flat_map(move |(word_index, mut word)| {
199            let bit_start = word_index * BITS_PER_BLOCK;
200            let bit_end = (bit_start + BITS_PER_BLOCK).min(size);
201
202            (bit_start..bit_end).filter(move |_| {
203                let active = word & 0b1 != 0;
204                word >>= 1;
205
206                active
207            })
208        })
209}