cart_tmp_wgc/
hub.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use crate::{
6    backend,
7    binding_model::{BindGroup, BindGroupLayout, PipelineLayout},
8    command::{CommandBuffer, RenderBundle},
9    device::Device,
10    id::{
11        AdapterId, BindGroupId, BindGroupLayoutId, BufferId, CommandBufferId, ComputePipelineId,
12        DeviceId, PipelineLayoutId, RenderBundleId, RenderPipelineId, SamplerId, ShaderModuleId,
13        SurfaceId, SwapChainId, TextureId, TextureViewId, TypedId,
14    },
15    instance::{Adapter, Instance, Surface},
16    pipeline::{ComputePipeline, RenderPipeline, ShaderModule},
17    resource::{Buffer, Sampler, Texture, TextureView},
18    span,
19    swap_chain::SwapChain,
20    Epoch, Index,
21};
22
23use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
24use vec_map::VecMap;
25use wgt::Backend;
26
27#[cfg(debug_assertions)]
28use std::cell::Cell;
29use std::{fmt::Debug, marker::PhantomData, ops, thread};
30
31/// A simple structure to manage identities of objects.
32#[derive(Debug)]
33pub struct IdentityManager {
34    free: Vec<Index>,
35    epochs: Vec<Epoch>,
36}
37
38impl Default for IdentityManager {
39    fn default() -> Self {
40        IdentityManager {
41            free: Default::default(),
42            epochs: Default::default(),
43        }
44    }
45}
46
47impl IdentityManager {
48    pub fn from_index(min_index: u32) -> Self {
49        IdentityManager {
50            free: (0..min_index).collect(),
51            epochs: vec![1; min_index as usize],
52        }
53    }
54
55    pub fn alloc<I: TypedId>(&mut self, backend: Backend) -> I {
56        match self.free.pop() {
57            Some(index) => I::zip(index, self.epochs[index as usize], backend),
58            None => {
59                let epoch = 1;
60                let id = I::zip(self.epochs.len() as Index, epoch, backend);
61                self.epochs.push(epoch);
62                id
63            }
64        }
65    }
66
67    pub fn free<I: TypedId + Debug>(&mut self, id: I) {
68        let (index, epoch, _backend) = id.unzip();
69        // avoid doing this check in release
70        if cfg!(debug_assertions) {
71            assert!(!self.free.contains(&index));
72        }
73        let pe = &mut self.epochs[index as usize];
74        assert_eq!(*pe, epoch);
75        *pe += 1;
76        self.free.push(index);
77    }
78}
79
80#[derive(Debug)]
81pub struct Storage<T, I: TypedId> {
82    //TODO: consider concurrent hashmap?
83    map: VecMap<(T, Epoch)>,
84    kind: &'static str,
85    _phantom: PhantomData<I>,
86}
87
88impl<T, I: TypedId> ops::Index<I> for Storage<T, I> {
89    type Output = T;
90    fn index(&self, id: I) -> &T {
91        let (index, epoch, _) = id.unzip();
92        let (ref value, storage_epoch) = match self.map.get(index as usize) {
93            Some(v) => v,
94            None => panic!("{}[{}] does not exist", self.kind, index),
95        };
96        assert_eq!(
97            epoch, *storage_epoch,
98            "{}[{}] is no longer alive",
99            self.kind, index
100        );
101        value
102    }
103}
104
105impl<T, I: TypedId> ops::IndexMut<I> for Storage<T, I> {
106    fn index_mut(&mut self, id: I) -> &mut T {
107        let (index, epoch, _) = id.unzip();
108        let (ref mut value, storage_epoch) = match self.map.get_mut(index as usize) {
109            Some(v) => v,
110            None => panic!("{}[{}] does not exist", self.kind, index),
111        };
112        assert_eq!(
113            epoch, *storage_epoch,
114            "{}[{}] is no longer alive",
115            self.kind, index
116        );
117        value
118    }
119}
120
121impl<T, I: TypedId> Storage<T, I> {
122    pub fn contains(&self, id: I) -> bool {
123        let (index, epoch, _) = id.unzip();
124        match self.map.get(index as usize) {
125            Some(&(_, storage_epoch)) => epoch == storage_epoch,
126            None => false,
127        }
128    }
129
130    pub fn insert(&mut self, id: I, value: T) -> Option<T> {
131        let (index, epoch, _) = id.unzip();
132        let old = self.map.insert(index as usize, (value, epoch));
133        old.map(|(v, _storage_epoch)| v)
134    }
135
136    pub fn remove(&mut self, id: I) -> Option<T> {
137        let (index, epoch, _) = id.unzip();
138        self.map
139            .remove(index as usize)
140            .map(|(value, storage_epoch)| {
141                assert_eq!(epoch, storage_epoch);
142                value
143            })
144    }
145
146    pub fn iter(&self, backend: Backend) -> impl Iterator<Item = (I, &T)> {
147        self.map.iter().map(move |(index, (value, storage_epoch))| {
148            (I::zip(index as Index, *storage_epoch, backend), value)
149        })
150    }
151}
152
153/// Type system for enforcing the lock order on shared HUB structures.
154/// If type A implements `Access<B>`, that means we are allowed to proceed
155/// with locking resource `B` after we lock `A`.
156///
157/// The implenentations basically describe the edges in a directed graph
158/// of lock transitions. As long as it doesn't have loops, we can have
159/// multiple concurrent paths on this graph (from multiple threads) without
160/// deadlocks, i.e. there is always a path whose next resource is not locked
161/// by some other path, at any time.
162pub trait Access<B> {}
163
164pub enum Root {}
165//TODO: establish an order instead of declaring all the pairs.
166impl Access<Instance> for Root {}
167impl Access<Surface> for Root {}
168impl Access<Surface> for Instance {}
169impl<B: hal::Backend> Access<Adapter<B>> for Root {}
170impl<B: hal::Backend> Access<Adapter<B>> for Surface {}
171impl<B: hal::Backend> Access<Device<B>> for Root {}
172impl<B: hal::Backend> Access<Device<B>> for Surface {}
173impl<B: hal::Backend> Access<Device<B>> for Adapter<B> {}
174impl<B: hal::Backend> Access<SwapChain<B>> for Root {}
175impl<B: hal::Backend> Access<SwapChain<B>> for Device<B> {}
176impl<B: hal::Backend> Access<PipelineLayout<B>> for Root {}
177impl<B: hal::Backend> Access<PipelineLayout<B>> for Device<B> {}
178impl<B: hal::Backend> Access<PipelineLayout<B>> for RenderBundle {}
179impl<B: hal::Backend> Access<BindGroupLayout<B>> for Root {}
180impl<B: hal::Backend> Access<BindGroupLayout<B>> for Device<B> {}
181impl<B: hal::Backend> Access<BindGroupLayout<B>> for PipelineLayout<B> {}
182impl<B: hal::Backend> Access<BindGroup<B>> for Root {}
183impl<B: hal::Backend> Access<BindGroup<B>> for Device<B> {}
184impl<B: hal::Backend> Access<BindGroup<B>> for BindGroupLayout<B> {}
185impl<B: hal::Backend> Access<BindGroup<B>> for PipelineLayout<B> {}
186impl<B: hal::Backend> Access<BindGroup<B>> for CommandBuffer<B> {}
187impl<B: hal::Backend> Access<CommandBuffer<B>> for Root {}
188impl<B: hal::Backend> Access<CommandBuffer<B>> for Device<B> {}
189impl<B: hal::Backend> Access<CommandBuffer<B>> for SwapChain<B> {}
190impl<B: hal::Backend> Access<RenderBundle> for Device<B> {}
191impl<B: hal::Backend> Access<RenderBundle> for CommandBuffer<B> {}
192impl<B: hal::Backend> Access<ComputePipeline<B>> for Device<B> {}
193impl<B: hal::Backend> Access<ComputePipeline<B>> for BindGroup<B> {}
194impl<B: hal::Backend> Access<RenderPipeline<B>> for Device<B> {}
195impl<B: hal::Backend> Access<RenderPipeline<B>> for BindGroup<B> {}
196impl<B: hal::Backend> Access<RenderPipeline<B>> for ComputePipeline<B> {}
197impl<B: hal::Backend> Access<ShaderModule<B>> for Device<B> {}
198impl<B: hal::Backend> Access<ShaderModule<B>> for BindGroupLayout<B> {}
199impl<B: hal::Backend> Access<Buffer<B>> for Root {}
200impl<B: hal::Backend> Access<Buffer<B>> for Device<B> {}
201impl<B: hal::Backend> Access<Buffer<B>> for BindGroupLayout<B> {}
202impl<B: hal::Backend> Access<Buffer<B>> for BindGroup<B> {}
203impl<B: hal::Backend> Access<Buffer<B>> for CommandBuffer<B> {}
204impl<B: hal::Backend> Access<Buffer<B>> for ComputePipeline<B> {}
205impl<B: hal::Backend> Access<Buffer<B>> for RenderPipeline<B> {}
206impl<B: hal::Backend> Access<Texture<B>> for Root {}
207impl<B: hal::Backend> Access<Texture<B>> for Device<B> {}
208impl<B: hal::Backend> Access<Texture<B>> for Buffer<B> {}
209impl<B: hal::Backend> Access<TextureView<B>> for Root {}
210impl<B: hal::Backend> Access<TextureView<B>> for SwapChain<B> {}
211impl<B: hal::Backend> Access<TextureView<B>> for Device<B> {}
212impl<B: hal::Backend> Access<TextureView<B>> for Texture<B> {}
213impl<B: hal::Backend> Access<Sampler<B>> for Root {}
214impl<B: hal::Backend> Access<Sampler<B>> for Device<B> {}
215impl<B: hal::Backend> Access<Sampler<B>> for TextureView<B> {}
216
217#[cfg(debug_assertions)]
218thread_local! {
219    static ACTIVE_TOKEN: Cell<u8> = Cell::new(0);
220}
221
222/// A permission token to lock resource `T` or anything after it,
223/// as defined by the `Access` implementations.
224///
225/// Note: there can only be one non-borrowed `Token` alive on a thread
226/// at a time, which is enforced by `ACTIVE_TOKEN`.
227pub struct Token<'a, T: 'a> {
228    level: PhantomData<&'a T>,
229}
230
231impl<'a, T> Token<'a, T> {
232    fn new() -> Self {
233        #[cfg(debug_assertions)]
234        ACTIVE_TOKEN.with(|active| {
235            let old = active.get();
236            assert_ne!(old, 0, "Root token was dropped");
237            active.set(old + 1);
238        });
239        Token { level: PhantomData }
240    }
241}
242
243impl Token<'static, Root> {
244    pub fn root() -> Self {
245        #[cfg(debug_assertions)]
246        ACTIVE_TOKEN.with(|active| {
247            assert_eq!(0, active.replace(1), "Root token is already active");
248        });
249
250        Token { level: PhantomData }
251    }
252}
253
254impl<'a, T> Drop for Token<'a, T> {
255    fn drop(&mut self) {
256        #[cfg(debug_assertions)]
257        ACTIVE_TOKEN.with(|active| {
258            let old = active.get();
259            active.set(old - 1);
260        });
261    }
262}
263
264pub trait IdentityHandler<I>: Debug {
265    type Input: Clone + Debug;
266    fn process(&self, id: Self::Input, backend: Backend) -> I;
267    fn free(&self, id: I);
268}
269
270impl<I: TypedId + Debug> IdentityHandler<I> for Mutex<IdentityManager> {
271    type Input = PhantomData<I>;
272    fn process(&self, _id: Self::Input, backend: Backend) -> I {
273        self.lock().alloc(backend)
274    }
275    fn free(&self, id: I) {
276        self.lock().free(id)
277    }
278}
279
280pub trait IdentityHandlerFactory<I> {
281    type Filter: IdentityHandler<I>;
282    fn spawn(&self, min_index: Index) -> Self::Filter;
283}
284
285#[derive(Debug)]
286pub struct IdentityManagerFactory;
287
288impl<I: TypedId + Debug> IdentityHandlerFactory<I> for IdentityManagerFactory {
289    type Filter = Mutex<IdentityManager>;
290    fn spawn(&self, min_index: Index) -> Self::Filter {
291        Mutex::new(IdentityManager::from_index(min_index))
292    }
293}
294
295pub trait GlobalIdentityHandlerFactory:
296    IdentityHandlerFactory<AdapterId>
297    + IdentityHandlerFactory<DeviceId>
298    + IdentityHandlerFactory<SwapChainId>
299    + IdentityHandlerFactory<PipelineLayoutId>
300    + IdentityHandlerFactory<ShaderModuleId>
301    + IdentityHandlerFactory<BindGroupLayoutId>
302    + IdentityHandlerFactory<BindGroupId>
303    + IdentityHandlerFactory<CommandBufferId>
304    + IdentityHandlerFactory<RenderBundleId>
305    + IdentityHandlerFactory<RenderPipelineId>
306    + IdentityHandlerFactory<ComputePipelineId>
307    + IdentityHandlerFactory<BufferId>
308    + IdentityHandlerFactory<TextureId>
309    + IdentityHandlerFactory<TextureViewId>
310    + IdentityHandlerFactory<SamplerId>
311    + IdentityHandlerFactory<SurfaceId>
312{
313}
314
315impl GlobalIdentityHandlerFactory for IdentityManagerFactory {}
316
317pub type Input<G, I> = <<G as IdentityHandlerFactory<I>>::Filter as IdentityHandler<I>>::Input;
318
319#[derive(Debug)]
320pub struct Registry<T, I: TypedId, F: IdentityHandlerFactory<I>> {
321    identity: F::Filter,
322    data: RwLock<Storage<T, I>>,
323    backend: Backend,
324}
325
326impl<T, I: TypedId, F: IdentityHandlerFactory<I>> Registry<T, I, F> {
327    fn new(backend: Backend, factory: &F, kind: &'static str) -> Self {
328        Registry {
329            identity: factory.spawn(0),
330            data: RwLock::new(Storage {
331                map: VecMap::new(),
332                kind,
333                _phantom: PhantomData,
334            }),
335            backend,
336        }
337    }
338
339    fn without_backend(factory: &F, kind: &'static str) -> Self {
340        Registry {
341            identity: factory.spawn(1),
342            data: RwLock::new(Storage {
343                map: VecMap::new(),
344                kind,
345                _phantom: PhantomData,
346            }),
347            backend: Backend::Empty,
348        }
349    }
350}
351
352impl<T, I: TypedId + Copy, F: IdentityHandlerFactory<I>> Registry<T, I, F> {
353    pub fn register<A: Access<T>>(&self, id: I, value: T, _token: &mut Token<A>) {
354        debug_assert_eq!(id.unzip().2, self.backend);
355        let old = self.data.write().insert(id, value);
356        assert!(old.is_none());
357    }
358
359    pub fn read<'a, A: Access<T>>(
360        &'a self,
361        _token: &'a mut Token<A>,
362    ) -> (RwLockReadGuard<'a, Storage<T, I>>, Token<'a, T>) {
363        (self.data.read(), Token::new())
364    }
365
366    pub fn write<'a, A: Access<T>>(
367        &'a self,
368        _token: &'a mut Token<A>,
369    ) -> (RwLockWriteGuard<'a, Storage<T, I>>, Token<'a, T>) {
370        (self.data.write(), Token::new())
371    }
372}
373
374impl<T, I: TypedId + Copy, F: IdentityHandlerFactory<I>> Registry<T, I, F> {
375    pub fn register_identity<A: Access<T>>(
376        &self,
377        id_in: <F::Filter as IdentityHandler<I>>::Input,
378        value: T,
379        token: &mut Token<A>,
380    ) -> I {
381        let id = self.identity.process(id_in, self.backend);
382        self.register(id, value, token);
383        id
384    }
385
386    pub fn unregister<'a, A: Access<T>>(
387        &self,
388        id: I,
389        _token: &'a mut Token<A>,
390    ) -> (T, Token<'a, T>) {
391        let value = self.data.write().remove(id).unwrap();
392        //Note: careful about the order here!
393        self.identity.free(id);
394        (value, Token::new())
395    }
396
397    pub fn free_id(&self, id: I) {
398        self.identity.free(id)
399    }
400}
401
402#[derive(Debug)]
403pub struct Hub<B: hal::Backend, F: GlobalIdentityHandlerFactory> {
404    pub adapters: Registry<Adapter<B>, AdapterId, F>,
405    pub devices: Registry<Device<B>, DeviceId, F>,
406    pub swap_chains: Registry<SwapChain<B>, SwapChainId, F>,
407    pub pipeline_layouts: Registry<PipelineLayout<B>, PipelineLayoutId, F>,
408    pub shader_modules: Registry<ShaderModule<B>, ShaderModuleId, F>,
409    pub bind_group_layouts: Registry<BindGroupLayout<B>, BindGroupLayoutId, F>,
410    pub bind_groups: Registry<BindGroup<B>, BindGroupId, F>,
411    pub command_buffers: Registry<CommandBuffer<B>, CommandBufferId, F>,
412    pub render_bundles: Registry<RenderBundle, RenderBundleId, F>,
413    pub render_pipelines: Registry<RenderPipeline<B>, RenderPipelineId, F>,
414    pub compute_pipelines: Registry<ComputePipeline<B>, ComputePipelineId, F>,
415    pub buffers: Registry<Buffer<B>, BufferId, F>,
416    pub textures: Registry<Texture<B>, TextureId, F>,
417    pub texture_views: Registry<TextureView<B>, TextureViewId, F>,
418    pub samplers: Registry<Sampler<B>, SamplerId, F>,
419}
420
421impl<B: GfxBackend, F: GlobalIdentityHandlerFactory> Hub<B, F> {
422    fn new(factory: &F) -> Self {
423        Hub {
424            adapters: Registry::new(B::VARIANT, factory, "Adapter"),
425            devices: Registry::new(B::VARIANT, factory, "Device"),
426            swap_chains: Registry::new(B::VARIANT, factory, "SwapChain"),
427            pipeline_layouts: Registry::new(B::VARIANT, factory, "PipelineLayout"),
428            shader_modules: Registry::new(B::VARIANT, factory, "ShaderModule"),
429            bind_group_layouts: Registry::new(B::VARIANT, factory, "BindGroupLayout"),
430            bind_groups: Registry::new(B::VARIANT, factory, "BindGroup"),
431            command_buffers: Registry::new(B::VARIANT, factory, "CommandBuffer"),
432            render_bundles: Registry::new(B::VARIANT, factory, "RenderBundle"),
433            render_pipelines: Registry::new(B::VARIANT, factory, "RenderPipeline"),
434            compute_pipelines: Registry::new(B::VARIANT, factory, "ComputePipeline"),
435            buffers: Registry::new(B::VARIANT, factory, "Buffer"),
436            textures: Registry::new(B::VARIANT, factory, "Texture"),
437            texture_views: Registry::new(B::VARIANT, factory, "TextureView"),
438            samplers: Registry::new(B::VARIANT, factory, "Sampler"),
439        }
440    }
441}
442
443impl<B: GfxBackend, F: GlobalIdentityHandlerFactory> Hub<B, F> {
444    fn clear(&mut self, surface_guard: &mut Storage<Surface, SurfaceId>) {
445        use crate::resource::TextureViewInner;
446        use hal::{device::Device as _, window::PresentationSurface as _};
447
448        let mut devices = self.devices.data.write();
449        for (device, _) in devices.map.values_mut() {
450            device.prepare_to_die();
451        }
452
453        for (_, (sampler, _)) in self.samplers.data.write().map.drain() {
454            unsafe {
455                devices[sampler.device_id.value]
456                    .raw
457                    .destroy_sampler(sampler.raw);
458            }
459        }
460        {
461            let textures = self.textures.data.read();
462            for (_, (texture_view, _)) in self.texture_views.data.write().map.drain() {
463                match texture_view.inner {
464                    TextureViewInner::Native { raw, source_id } => {
465                        let device = &devices[textures[source_id.value].device_id.value];
466                        unsafe {
467                            device.raw.destroy_image_view(raw);
468                        }
469                    }
470                    TextureViewInner::SwapChain { .. } => {} //TODO
471                }
472            }
473        }
474
475        for (_, (texture, _)) in self.textures.data.write().map.drain() {
476            devices[texture.device_id.value].destroy_texture(texture);
477        }
478        for (_, (buffer, _)) in self.buffers.data.write().map.drain() {
479            //TODO: unmap if needed
480            devices[buffer.device_id.value].destroy_buffer(buffer);
481        }
482        for (_, (command_buffer, _)) in self.command_buffers.data.write().map.drain() {
483            devices[command_buffer.device_id.value]
484                .com_allocator
485                .after_submit(command_buffer, 0);
486        }
487        for (_, (bind_group, _)) in self.bind_groups.data.write().map.drain() {
488            let device = &devices[bind_group.device_id.value];
489            device.destroy_bind_group(bind_group);
490        }
491
492        for (_, (module, _)) in self.shader_modules.data.write().map.drain() {
493            let device = &devices[module.device_id.value];
494            unsafe {
495                device.raw.destroy_shader_module(module.raw);
496            }
497        }
498        for (_, (bgl, _)) in self.bind_group_layouts.data.write().map.drain() {
499            let device = &devices[bgl.device_id.value];
500            unsafe {
501                device.raw.destroy_descriptor_set_layout(bgl.raw);
502            }
503        }
504        for (_, (pipeline_layout, _)) in self.pipeline_layouts.data.write().map.drain() {
505            let device = &devices[pipeline_layout.device_id.value];
506            unsafe {
507                device.raw.destroy_pipeline_layout(pipeline_layout.raw);
508            }
509        }
510        for (_, (pipeline, _)) in self.compute_pipelines.data.write().map.drain() {
511            let device = &devices[pipeline.device_id.value];
512            unsafe {
513                device.raw.destroy_compute_pipeline(pipeline.raw);
514            }
515        }
516        for (_, (pipeline, _)) in self.render_pipelines.data.write().map.drain() {
517            let device = &devices[pipeline.device_id.value];
518            unsafe {
519                device.raw.destroy_graphics_pipeline(pipeline.raw);
520            }
521        }
522
523        for (index, (swap_chain, epoch)) in self.swap_chains.data.write().map.drain() {
524            let device = &devices[swap_chain.device_id.value];
525            let surface = &mut surface_guard[TypedId::zip(index as Index, epoch, B::VARIANT)];
526            let suf = B::get_surface_mut(surface);
527            unsafe {
528                device.raw.destroy_semaphore(swap_chain.semaphore);
529                suf.unconfigure_swapchain(&device.raw);
530            }
531        }
532
533        for (_, (device, _)) in devices.map.drain() {
534            device.dispose();
535        }
536    }
537}
538
539#[derive(Debug)]
540pub struct Hubs<F: GlobalIdentityHandlerFactory> {
541    #[cfg(any(
542        not(any(target_os = "ios", target_os = "macos")),
543        feature = "gfx-backend-vulkan"
544    ))]
545    vulkan: Hub<backend::Vulkan, F>,
546    #[cfg(any(target_os = "ios", target_os = "macos"))]
547    metal: Hub<backend::Metal, F>,
548    #[cfg(windows)]
549    dx12: Hub<backend::Dx12, F>,
550    #[cfg(windows)]
551    dx11: Hub<backend::Dx11, F>,
552}
553
554impl<F: GlobalIdentityHandlerFactory> Hubs<F> {
555    fn new(factory: &F) -> Self {
556        backends! {
557            Hubs {
558                #[vulkan]
559                vulkan: Hub::new(factory),
560                #[metal]
561                metal: Hub::new(factory),
562                #[dx12]
563                dx12: Hub::new(factory),
564                #[dx11]
565                dx11: Hub::new(factory),
566            }
567        }
568    }
569}
570
571#[derive(Debug)]
572pub struct Global<G: GlobalIdentityHandlerFactory> {
573    pub instance: Instance,
574    pub surfaces: Registry<Surface, SurfaceId, G>,
575    hubs: Hubs<G>,
576}
577
578impl<G: GlobalIdentityHandlerFactory> Global<G> {
579    pub fn new(name: &str, factory: G, backends: wgt::BackendBit) -> Self {
580        span!(_guard, INFO, "Global::new");
581        Global {
582            instance: Instance::new(name, 1, backends),
583            surfaces: Registry::without_backend(&factory, "Surface"),
584            hubs: Hubs::new(&factory),
585        }
586    }
587}
588
589impl<G: GlobalIdentityHandlerFactory> Drop for Global<G> {
590    fn drop(&mut self) {
591        if !thread::panicking() {
592            log::info!("Dropping Global");
593            let mut surface_guard = self.surfaces.data.write();
594
595            // destroy hubs
596            backends! {
597                #[vulkan] {
598                    self.hubs.vulkan.clear(&mut *surface_guard);
599                }
600                #[metal] {
601                    self.hubs.metal.clear(&mut *surface_guard);
602                }
603                #[dx12] {
604                    self.hubs.dx12.clear(&mut *surface_guard);
605                }
606                #[dx11] {
607                    self.hubs.dx11.clear(&mut *surface_guard);
608                }
609            }
610
611            // destroy surfaces
612            for (_, (surface, _)) in surface_guard.map.drain() {
613                self.instance.destroy_surface(surface);
614            }
615        }
616    }
617}
618
619pub trait GfxBackend: hal::Backend {
620    const VARIANT: Backend;
621    fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self, G>;
622    fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface;
623}
624
625#[cfg(any(
626    not(any(target_os = "ios", target_os = "macos")),
627    feature = "gfx-backend-vulkan"
628))]
629impl GfxBackend for backend::Vulkan {
630    const VARIANT: Backend = Backend::Vulkan;
631    fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self, G> {
632        &global.hubs.vulkan
633    }
634    fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface {
635        surface.vulkan.as_mut().unwrap()
636    }
637}
638
639#[cfg(any(target_os = "ios", target_os = "macos"))]
640impl GfxBackend for backend::Metal {
641    const VARIANT: Backend = Backend::Metal;
642    fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self, G> {
643        &global.hubs.metal
644    }
645    fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface {
646        surface.metal.as_mut().unwrap()
647    }
648}
649
650#[cfg(windows)]
651impl GfxBackend for backend::Dx12 {
652    const VARIANT: Backend = Backend::Dx12;
653    fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self, G> {
654        &global.hubs.dx12
655    }
656    fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface {
657        surface.dx12.as_mut().unwrap()
658    }
659}
660
661#[cfg(windows)]
662impl GfxBackend for backend::Dx11 {
663    const VARIANT: Backend = Backend::Dx11;
664    fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self, G> {
665        &global.hubs.dx11
666    }
667    fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface {
668        surface.dx11.as_mut().unwrap()
669    }
670}
671
672#[cfg(test)]
673fn _test_send_sync(global: &Global<IdentityManagerFactory>) {
674    fn test_internal<T: Send + Sync>(_: T) {}
675    test_internal(global)
676}