summaryrefslogtreecommitdiffstats
path: root/third_party/rust/wgpu-core/src/registry.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/wgpu-core/src/registry.rs
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/wgpu-core/src/registry.rs')
-rw-r--r--third_party/rust/wgpu-core/src/registry.rs200
1 files changed, 200 insertions, 0 deletions
diff --git a/third_party/rust/wgpu-core/src/registry.rs b/third_party/rust/wgpu-core/src/registry.rs
new file mode 100644
index 0000000000..f55809770b
--- /dev/null
+++ b/third_party/rust/wgpu-core/src/registry.rs
@@ -0,0 +1,200 @@
+use std::sync::Arc;
+
+use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
+use wgt::Backend;
+
+use crate::{
+ id::Id,
+ identity::IdentityManager,
+ resource::Resource,
+ storage::{Element, InvalidId, Storage},
+};
+
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
+pub struct RegistryReport {
+ pub num_allocated: usize,
+ pub num_kept_from_user: usize,
+ pub num_released_from_user: usize,
+ pub num_error: usize,
+ pub element_size: usize,
+}
+
+impl RegistryReport {
+ pub fn is_empty(&self) -> bool {
+ self.num_allocated + self.num_kept_from_user == 0
+ }
+}
+
+/// Registry is the primary holder of each resource type
+/// Every resource is now arcanized so the last arc released
+/// will in the end free the memory and release the inner raw resource
+///
+/// Registry act as the main entry point to keep resource alive
+/// when created and released from user land code
+///
+/// A resource may still be alive when released from user land code
+/// if it's used in active submission or anyway kept alive from
+/// any other dependent resource
+///
+#[derive(Debug)]
+pub struct Registry<T: Resource> {
+ identity: Arc<IdentityManager<T::Marker>>,
+ storage: RwLock<Storage<T>>,
+ backend: Backend,
+}
+
+impl<T: Resource> Registry<T> {
+ pub(crate) fn new(backend: Backend) -> Self {
+ Self {
+ identity: Arc::new(IdentityManager::new()),
+ storage: RwLock::new(Storage::new()),
+ backend,
+ }
+ }
+
+ pub(crate) fn without_backend() -> Self {
+ Self::new(Backend::Empty)
+ }
+}
+
+#[must_use]
+pub(crate) struct FutureId<'a, T: Resource> {
+ id: Id<T::Marker>,
+ identity: Arc<IdentityManager<T::Marker>>,
+ data: &'a RwLock<Storage<T>>,
+}
+
+impl<T: Resource> FutureId<'_, T> {
+ #[allow(dead_code)]
+ pub fn id(&self) -> Id<T::Marker> {
+ self.id
+ }
+
+ pub fn into_id(self) -> Id<T::Marker> {
+ self.id
+ }
+
+ pub fn init(&self, mut value: T) -> Arc<T> {
+ value.as_info_mut().set_id(self.id, &self.identity);
+ Arc::new(value)
+ }
+
+ /// Assign a new resource to this ID.
+ ///
+ /// Registers it with the registry, and fills out the resource info.
+ pub fn assign(self, value: T) -> (Id<T::Marker>, Arc<T>) {
+ let mut data = self.data.write();
+ data.insert(self.id, self.init(value));
+ (self.id, data.get(self.id).unwrap().clone())
+ }
+
+ /// Assign an existing resource to a new ID.
+ ///
+ /// Registers it with the registry.
+ ///
+ /// This _will_ leak the ID, and it will not be recycled again.
+ /// See https://github.com/gfx-rs/wgpu/issues/4912.
+ pub fn assign_existing(self, value: &Arc<T>) -> Id<T::Marker> {
+ let mut data = self.data.write();
+ debug_assert!(!data.contains(self.id));
+ data.insert(self.id, value.clone());
+ self.id
+ }
+
+ pub fn assign_error(self, label: &str) -> Id<T::Marker> {
+ self.data.write().insert_error(self.id, label);
+ self.id
+ }
+}
+
+impl<T: Resource> Registry<T> {
+ pub(crate) fn prepare(&self, id_in: Option<Id<T::Marker>>) -> FutureId<T> {
+ FutureId {
+ id: match id_in {
+ Some(id_in) => {
+ self.identity.mark_as_used(id_in);
+ id_in
+ }
+ None => self.identity.process(self.backend),
+ },
+ identity: self.identity.clone(),
+ data: &self.storage,
+ }
+ }
+
+ pub(crate) fn request(&self) -> FutureId<T> {
+ FutureId {
+ id: self.identity.process(self.backend),
+ identity: self.identity.clone(),
+ data: &self.storage,
+ }
+ }
+ pub(crate) fn try_get(&self, id: Id<T::Marker>) -> Result<Option<Arc<T>>, InvalidId> {
+ self.read().try_get(id).map(|o| o.cloned())
+ }
+ pub(crate) fn get(&self, id: Id<T::Marker>) -> Result<Arc<T>, InvalidId> {
+ self.read().get_owned(id)
+ }
+ pub(crate) fn read<'a>(&'a self) -> RwLockReadGuard<'a, Storage<T>> {
+ self.storage.read()
+ }
+ pub(crate) fn write<'a>(&'a self) -> RwLockWriteGuard<'a, Storage<T>> {
+ self.storage.write()
+ }
+ pub fn unregister_locked(&self, id: Id<T::Marker>, storage: &mut Storage<T>) -> Option<Arc<T>> {
+ storage.remove(id)
+ }
+ pub fn force_replace(&self, id: Id<T::Marker>, mut value: T) {
+ let mut storage = self.storage.write();
+ value.as_info_mut().set_id(id, &self.identity);
+ storage.force_replace(id, value)
+ }
+ pub fn force_replace_with_error(&self, id: Id<T::Marker>, label: &str) {
+ let mut storage = self.storage.write();
+ storage.remove(id);
+ storage.insert_error(id, label);
+ }
+ pub(crate) fn unregister(&self, id: Id<T::Marker>) -> Option<Arc<T>> {
+ let value = self.storage.write().remove(id);
+ //Returning None is legal if it's an error ID
+ value
+ }
+
+ pub fn label_for_resource(&self, id: Id<T::Marker>) -> String {
+ let guard = self.storage.read();
+
+ let type_name = guard.kind();
+ match guard.get(id) {
+ Ok(res) => {
+ let label = res.label();
+ if label.is_empty() {
+ format!("<{}-{:?}>", type_name, id.unzip())
+ } else {
+ label
+ }
+ }
+ Err(_) => format!(
+ "<Invalid-{} label={}>",
+ type_name,
+ guard.label_for_invalid_id(id)
+ ),
+ }
+ }
+
+ pub(crate) fn generate_report(&self) -> RegistryReport {
+ let storage = self.storage.read();
+ let mut report = RegistryReport {
+ element_size: std::mem::size_of::<T>(),
+ ..Default::default()
+ };
+ report.num_allocated = self.identity.values.lock().count();
+ for element in storage.map.iter() {
+ match *element {
+ Element::Occupied(..) => report.num_kept_from_user += 1,
+ Element::Vacant => report.num_released_from_user += 1,
+ Element::Error(..) => report.num_error += 1,
+ }
+ }
+ report
+ }
+}