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 pub(super) fn tracker_assert_in_bounds(&self, index: usize) {
47 strict_assert!(index < self.owned.len());
48 strict_assert!(index < self.resources.len());
49 strict_assert!(if self.contains(index) {
50 self.resources[index].is_some()
51 } else {
52 true
53 });
54 }
55
56 pub(super) fn is_empty(&self) -> bool {
60 !self.owned.any()
61 }
62
63 pub(super) fn contains(&self, index: usize) -> bool {
65 self.owned.get(index).unwrap_or(false)
66 }
67
68 #[inline(always)]
75 pub(super) unsafe fn contains_unchecked(&self, index: usize) -> bool {
76 unsafe { self.owned.get(index).unwrap_unchecked() }
77 }
78
79 #[inline(always)]
92 pub(super) unsafe fn insert(&mut self, index: usize, resource: T) -> &T {
93 self.owned.set(index, true);
94 let resource_dst = unsafe { self.resources.get_unchecked_mut(index) };
95 resource_dst.insert(resource)
96 }
97
98 #[inline(always)]
105 pub(super) unsafe fn get_resource_unchecked(&self, index: usize) -> &T {
106 unsafe {
107 self.resources
108 .get_unchecked(index)
109 .as_ref()
110 .unwrap_unchecked()
111 }
112 }
113
114 pub(super) fn owned_resources(&self) -> impl Iterator<Item = &T> + '_ {
116 if !self.owned.is_empty() {
117 self.tracker_assert_in_bounds(self.owned.len() - 1)
118 };
119 iterate_bitvec_indices(&self.owned).map(move |index| {
120 let resource = unsafe { self.resources.get_unchecked(index) };
121 resource.as_ref().unwrap()
122 })
123 }
124
125 pub(super) fn owned_indices(&self) -> impl Iterator<Item = usize> + '_ {
127 if !self.owned.is_empty() {
128 self.tracker_assert_in_bounds(self.owned.len() - 1)
129 };
130 iterate_bitvec_indices(&self.owned)
131 }
132
133 pub(super) unsafe fn remove(&mut self, index: usize) {
135 unsafe {
136 *self.resources.get_unchecked_mut(index) = None;
137 }
138 self.owned.set(index, false);
139 }
140}
141
142pub(super) enum ResourceMetadataProvider<'a, T: Clone> {
147 Direct { resource: &'a T },
149 Indirect { metadata: &'a ResourceMetadata<T> },
151}
152impl<T: Clone> ResourceMetadataProvider<'_, T> {
153 #[inline(always)]
159 pub(super) unsafe fn get(&self, index: usize) -> &T {
160 match self {
161 ResourceMetadataProvider::Direct { resource } => resource,
162 ResourceMetadataProvider::Indirect { metadata } => {
163 metadata.tracker_assert_in_bounds(index);
164 {
165 let resource = unsafe { metadata.resources.get_unchecked(index) }.as_ref();
166 unsafe { resource.unwrap_unchecked() }
167 }
168 }
169 }
170 }
171}
172
173fn resize_bitvec<B: bit_vec::BitBlock>(vec: &mut BitVec<B>, size: usize) {
175 let owned_size_to_grow = size.checked_sub(vec.len());
176 if let Some(delta) = owned_size_to_grow {
177 if delta != 0 {
178 vec.grow(delta, false);
179 }
180 } else {
181 vec.truncate(size);
182 }
183}
184
185fn iterate_bitvec_indices(ownership: &BitVec<usize>) -> impl Iterator<Item = usize> + '_ {
189 const BITS_PER_BLOCK: usize = usize::BITS as usize;
190
191 let size = ownership.len();
192
193 ownership
194 .blocks()
195 .enumerate()
196 .filter(|&(_, word)| word != 0)
197 .flat_map(move |(word_index, mut word)| {
198 let bit_start = word_index * BITS_PER_BLOCK;
199 let bit_end = (bit_start + BITS_PER_BLOCK).min(size);
200
201 (bit_start..bit_end).filter(move |_| {
202 let active = word & 0b1 != 0;
203 word >>= 1;
204
205 active
206 })
207 })
208}