wgpu_core/
global.rs

1use std::sync::Arc;
2
3use wgt::Backend;
4
5use crate::{
6    hal_api::HalApi,
7    hub::{HubReport, Hubs},
8    instance::{Instance, Surface},
9    registry::{Registry, RegistryReport},
10    resource_log,
11    storage::Element,
12};
13
14#[derive(Debug, PartialEq, Eq)]
15pub struct GlobalReport {
16    pub surfaces: RegistryReport,
17    #[cfg(vulkan)]
18    pub vulkan: Option<HubReport>,
19    #[cfg(metal)]
20    pub metal: Option<HubReport>,
21    #[cfg(dx12)]
22    pub dx12: Option<HubReport>,
23    #[cfg(gles)]
24    pub gl: Option<HubReport>,
25}
26
27impl GlobalReport {
28    pub fn surfaces(&self) -> &RegistryReport {
29        &self.surfaces
30    }
31    pub fn hub_report(&self, backend: Backend) -> &HubReport {
32        match backend {
33            #[cfg(vulkan)]
34            Backend::Vulkan => self.vulkan.as_ref().unwrap(),
35            #[cfg(metal)]
36            Backend::Metal => self.metal.as_ref().unwrap(),
37            #[cfg(dx12)]
38            Backend::Dx12 => self.dx12.as_ref().unwrap(),
39            #[cfg(gles)]
40            Backend::Gl => self.gl.as_ref().unwrap(),
41            _ => panic!("HubReport is not supported on this backend"),
42        }
43    }
44}
45
46pub struct Global {
47    pub instance: Instance,
48    pub(crate) surfaces: Registry<Surface>,
49    pub(crate) hubs: Hubs,
50}
51
52impl Global {
53    pub fn new(name: &str, instance_desc: wgt::InstanceDescriptor) -> Self {
54        profiling::scope!("Global::new");
55        Self {
56            instance: Instance::new(name, instance_desc),
57            surfaces: Registry::without_backend(),
58            hubs: Hubs::new(),
59        }
60    }
61
62    /// # Safety
63    ///
64    /// Refer to the creation of wgpu-hal Instance for every backend.
65    pub unsafe fn from_hal_instance<A: HalApi>(name: &str, hal_instance: A::Instance) -> Self {
66        profiling::scope!("Global::new");
67        Self {
68            instance: A::create_instance_from_hal(name, hal_instance),
69            surfaces: Registry::without_backend(),
70            hubs: Hubs::new(),
71        }
72    }
73
74    /// # Safety
75    ///
76    /// - The raw instance handle returned must not be manually destroyed.
77    pub unsafe fn instance_as_hal<A: HalApi>(&self) -> Option<&A::Instance> {
78        A::instance_as_hal(&self.instance)
79    }
80
81    /// # Safety
82    ///
83    /// - The raw handles obtained from the Instance must not be manually destroyed
84    pub unsafe fn from_instance(instance: Instance) -> Self {
85        profiling::scope!("Global::new");
86        Self {
87            instance,
88            surfaces: Registry::without_backend(),
89            hubs: Hubs::new(),
90        }
91    }
92
93    pub fn clear_backend<A: HalApi>(&self, _dummy: ()) {
94        let hub = A::hub(self);
95        let surfaces_locked = self.surfaces.read();
96        // this is used for tests, which keep the adapter
97        hub.clear(&surfaces_locked, false);
98    }
99
100    pub fn generate_report(&self) -> GlobalReport {
101        GlobalReport {
102            surfaces: self.surfaces.generate_report(),
103            #[cfg(vulkan)]
104            vulkan: if self.instance.vulkan.is_some() {
105                Some(self.hubs.vulkan.generate_report())
106            } else {
107                None
108            },
109            #[cfg(metal)]
110            metal: if self.instance.metal.is_some() {
111                Some(self.hubs.metal.generate_report())
112            } else {
113                None
114            },
115            #[cfg(dx12)]
116            dx12: if self.instance.dx12.is_some() {
117                Some(self.hubs.dx12.generate_report())
118            } else {
119                None
120            },
121            #[cfg(gles)]
122            gl: if self.instance.gl.is_some() {
123                Some(self.hubs.gl.generate_report())
124            } else {
125                None
126            },
127        }
128    }
129}
130
131impl Drop for Global {
132    fn drop(&mut self) {
133        profiling::scope!("Global::drop");
134        resource_log!("Global::drop");
135        let mut surfaces_locked = self.surfaces.write();
136
137        // destroy hubs before the instance gets dropped
138        #[cfg(vulkan)]
139        {
140            self.hubs.vulkan.clear(&surfaces_locked, true);
141        }
142        #[cfg(metal)]
143        {
144            self.hubs.metal.clear(&surfaces_locked, true);
145        }
146        #[cfg(dx12)]
147        {
148            self.hubs.dx12.clear(&surfaces_locked, true);
149        }
150        #[cfg(gles)]
151        {
152            self.hubs.gl.clear(&surfaces_locked, true);
153        }
154
155        // destroy surfaces
156        for element in surfaces_locked.map.drain(..) {
157            if let Element::Occupied(arc_surface, _) = element {
158                let surface = Arc::into_inner(arc_surface)
159                    .expect("Surface cannot be destroyed because is still in use");
160                self.instance.destroy_surface(surface);
161            }
162        }
163    }
164}
165
166#[cfg(send_sync)]
167fn _test_send_sync(global: &Global) {
168    fn test_internal<T: Send + Sync>(_: T) {}
169    test_internal(global)
170}