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 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 pub unsafe fn instance_as_hal<A: HalApi>(&self) -> Option<&A::Instance> {
78 A::instance_as_hal(&self.instance)
79 }
80
81 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 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 #[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 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}