wgpu_core/
registry.rs

1use std::sync::Arc;
2
3use wgt::Backend;
4
5use crate::{
6    id::Id,
7    identity::IdentityManager,
8    lock::{rank, RwLock, RwLockReadGuard, RwLockWriteGuard},
9    resource::Resource,
10    storage::{Element, InvalidId, Storage},
11};
12
13#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
14pub struct RegistryReport {
15    pub num_allocated: usize,
16    pub num_kept_from_user: usize,
17    pub num_released_from_user: usize,
18    pub num_error: usize,
19    pub element_size: usize,
20}
21
22impl RegistryReport {
23    pub fn is_empty(&self) -> bool {
24        self.num_allocated + self.num_kept_from_user == 0
25    }
26}
27
28/// Registry is the primary holder of each resource type
29/// Every resource is now arcanized so the last arc released
30/// will in the end free the memory and release the inner raw resource
31///
32/// Registry act as the main entry point to keep resource alive
33/// when created and released from user land code
34///
35/// A resource may still be alive when released from user land code
36/// if it's used in active submission or anyway kept alive from
37/// any other dependent resource
38///
39#[derive(Debug)]
40pub(crate) struct Registry<T: Resource> {
41    // Must only contain an id which has either never been used or has been released from `storage`
42    identity: Arc<IdentityManager<T::Marker>>,
43    storage: RwLock<Storage<T>>,
44    backend: Backend,
45}
46
47impl<T: Resource> Registry<T> {
48    pub(crate) fn new(backend: Backend) -> Self {
49        Self {
50            identity: Arc::new(IdentityManager::new()),
51            storage: RwLock::new(rank::REGISTRY_STORAGE, Storage::new()),
52            backend,
53        }
54    }
55
56    pub(crate) fn without_backend() -> Self {
57        Self::new(Backend::Empty)
58    }
59}
60
61#[must_use]
62pub(crate) struct FutureId<'a, T: Resource> {
63    id: Id<T::Marker>,
64    data: &'a RwLock<Storage<T>>,
65}
66
67impl<T: Resource> FutureId<'_, T> {
68    #[allow(dead_code)]
69    pub fn id(&self) -> Id<T::Marker> {
70        self.id
71    }
72
73    pub fn into_id(self) -> Id<T::Marker> {
74        self.id
75    }
76
77    pub fn init(&self, mut value: T) -> Arc<T> {
78        value.as_info_mut().set_id(self.id);
79        Arc::new(value)
80    }
81
82    pub fn init_in_place(&self, mut value: Arc<T>) -> Arc<T> {
83        Arc::get_mut(&mut value)
84            .unwrap()
85            .as_info_mut()
86            .set_id(self.id);
87        value
88    }
89
90    /// Assign a new resource to this ID.
91    ///
92    /// Registers it with the registry, and fills out the resource info.
93    pub fn assign(self, value: Arc<T>) -> (Id<T::Marker>, Arc<T>) {
94        let mut data = self.data.write();
95        data.insert(self.id, self.init_in_place(value));
96        (self.id, data.get(self.id).unwrap().clone())
97    }
98
99    /// Assign an existing resource to a new ID.
100    ///
101    /// Registers it with the registry.
102    pub fn assign_existing(self, value: &Arc<T>) -> Id<T::Marker> {
103        let mut data = self.data.write();
104        debug_assert!(!data.contains(self.id));
105        data.insert(self.id, value.clone());
106        self.id
107    }
108
109    pub fn assign_error(self, label: &str) -> Id<T::Marker> {
110        self.data.write().insert_error(self.id, label);
111        self.id
112    }
113}
114
115impl<T: Resource> Registry<T> {
116    pub(crate) fn prepare(&self, id_in: Option<Id<T::Marker>>) -> FutureId<T> {
117        FutureId {
118            id: match id_in {
119                Some(id_in) => {
120                    self.identity.mark_as_used(id_in);
121                    id_in
122                }
123                None => self.identity.process(self.backend),
124            },
125            data: &self.storage,
126        }
127    }
128
129    pub(crate) fn request(&self) -> FutureId<T> {
130        FutureId {
131            id: self.identity.process(self.backend),
132            data: &self.storage,
133        }
134    }
135    pub(crate) fn try_get(&self, id: Id<T::Marker>) -> Result<Option<Arc<T>>, InvalidId> {
136        self.read().try_get(id).map(|o| o.cloned())
137    }
138    pub(crate) fn get(&self, id: Id<T::Marker>) -> Result<Arc<T>, InvalidId> {
139        self.read().get_owned(id)
140    }
141    pub(crate) fn read<'a>(&'a self) -> RwLockReadGuard<'a, Storage<T>> {
142        self.storage.read()
143    }
144    pub(crate) fn write<'a>(&'a self) -> RwLockWriteGuard<'a, Storage<T>> {
145        self.storage.write()
146    }
147    pub(crate) fn unregister_locked(
148        &self,
149        id: Id<T::Marker>,
150        storage: &mut Storage<T>,
151    ) -> Option<Arc<T>> {
152        self.identity.free(id);
153        storage.remove(id)
154    }
155    pub(crate) fn force_replace(&self, id: Id<T::Marker>, mut value: T) {
156        let mut storage = self.storage.write();
157        value.as_info_mut().set_id(id);
158        storage.force_replace(id, value)
159    }
160    pub(crate) fn force_replace_with_error(&self, id: Id<T::Marker>, label: &str) {
161        let mut storage = self.storage.write();
162        storage.remove(id);
163        storage.insert_error(id, label);
164    }
165    pub(crate) fn unregister(&self, id: Id<T::Marker>) -> Option<Arc<T>> {
166        let value = self.storage.write().remove(id);
167        // This needs to happen *after* removing it from the storage, to maintain the
168        // invariant that `self.identity` only contains ids which are actually available
169        // See https://github.com/gfx-rs/wgpu/issues/5372
170        self.identity.free(id);
171        //Returning None is legal if it's an error ID
172        value
173    }
174
175    pub(crate) fn label_for_resource(&self, id: Id<T::Marker>) -> String {
176        let guard = self.storage.read();
177
178        let type_name = guard.kind();
179        match guard.get(id) {
180            Ok(res) => {
181                let label = res.label();
182                if label.is_empty() {
183                    format!("<{}-{:?}>", type_name, id.unzip())
184                } else {
185                    label
186                }
187            }
188            Err(_) => format!(
189                "<Invalid-{} label={}>",
190                type_name,
191                guard.label_for_invalid_id(id)
192            ),
193        }
194    }
195
196    pub(crate) fn generate_report(&self) -> RegistryReport {
197        let storage = self.storage.read();
198        let mut report = RegistryReport {
199            element_size: std::mem::size_of::<T>(),
200            ..Default::default()
201        };
202        report.num_allocated = self.identity.values.lock().count();
203        for element in storage.map.iter() {
204            match *element {
205                Element::Occupied(..) => report.num_kept_from_user += 1,
206                Element::Vacant => report.num_released_from_user += 1,
207                Element::Error(..) => report.num_error += 1,
208            }
209        }
210        report
211    }
212}
213
214#[cfg(test)]
215mod tests {
216    use std::sync::Arc;
217
218    use crate::{
219        id::Marker,
220        resource::{Resource, ResourceInfo, ResourceType},
221    };
222
223    use super::Registry;
224    struct TestData {
225        info: ResourceInfo<TestData>,
226    }
227    struct TestDataId;
228    impl Marker for TestDataId {}
229
230    impl Resource for TestData {
231        type Marker = TestDataId;
232
233        const TYPE: ResourceType = "Test data";
234
235        fn as_info(&self) -> &ResourceInfo<Self> {
236            &self.info
237        }
238
239        fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
240            &mut self.info
241        }
242    }
243
244    #[test]
245    fn simultaneous_registration() {
246        let registry = Registry::without_backend();
247        std::thread::scope(|s| {
248            for _ in 0..5 {
249                s.spawn(|| {
250                    for _ in 0..1000 {
251                        let value = Arc::new(TestData {
252                            info: ResourceInfo::new("Test data", None),
253                        });
254                        let new_id = registry.prepare(None);
255                        let (id, _) = new_id.assign(value);
256                        registry.unregister(id);
257                    }
258                });
259            }
260        })
261    }
262}