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
135pub(super) enum ResourceMetadataProvider<'a, T: Clone> {
140 Direct { resource: &'a T },
142 Indirect { metadata: &'a ResourceMetadata<T> },
144}
145impl<T: Clone> ResourceMetadataProvider<'_, T> {
146 #[inline(always)]
152 pub(super) unsafe fn get(&self, index: usize) -> &T {
153 match self {
154 ResourceMetadataProvider::Direct { resource } => resource,
155 ResourceMetadataProvider::Indirect { metadata } => {
156 metadata.tracker_assert_in_bounds(index);
157 {
158 let resource = unsafe { metadata.resources.get_unchecked(index) }.as_ref();
159 unsafe { resource.unwrap_unchecked() }
160 }
161 }
162 }
163 }
164}
165
166fn resize_bitvec<B: bit_vec::BitBlock>(vec: &mut BitVec<B>, size: usize) {
168 let owned_size_to_grow = size.checked_sub(vec.len());
169 if let Some(delta) = owned_size_to_grow {
170 if delta != 0 {
171 vec.grow(delta, false);
172 }
173 } else {
174 vec.truncate(size);
175 }
176}
177
178fn iterate_bitvec_indices(ownership: &BitVec<usize>) -> impl Iterator<Item = usize> + '_ {
182 const BITS_PER_BLOCK: usize = usize::BITS as usize;
183
184 let size = ownership.len();
185
186 ownership
187 .blocks()
188 .enumerate()
189 .filter(|&(_, word)| word != 0)
190 .flat_map(move |(word_index, mut word)| {
191 let bit_start = word_index * BITS_PER_BLOCK;
192 let bit_end = (bit_start + BITS_PER_BLOCK).min(size);
193
194 (bit_start..bit_end).filter(move |_| {
195 let active = word & 0b1 != 0;
196 word >>= 1;
197
198 active
199 })
200 })
201}