1use 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#[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 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 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
153pub trait Access<B> {}
163
164pub enum Root {}
165impl 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
222pub 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 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 { .. } => {} }
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 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 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 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}