cart_tmp_wgc/
instance.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    device::Device,
8    hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Input, Token},
9    id::{AdapterId, DeviceId, SurfaceId},
10    power, span, LifeGuard, PrivateFeatures, Stored, MAX_BIND_GROUPS,
11};
12
13use wgt::{Backend, BackendBit, DeviceDescriptor, PowerPreference, BIND_BUFFER_ALIGNMENT};
14
15#[cfg(feature = "replay")]
16use serde::Deserialize;
17#[cfg(feature = "trace")]
18use serde::Serialize;
19
20use hal::{
21    adapter::{AdapterInfo as HalAdapterInfo, DeviceType as HalDeviceType, PhysicalDevice as _},
22    queue::QueueFamily as _,
23    window::Surface as _,
24    Instance as _,
25};
26use std::fmt::Display;
27
28#[repr(C)]
29#[derive(Clone, Debug, PartialEq, Eq, Hash)]
30#[cfg_attr(feature = "trace", derive(Serialize))]
31#[cfg_attr(feature = "replay", derive(Deserialize))]
32pub struct RequestAdapterOptions {
33    pub power_preference: PowerPreference,
34    pub compatible_surface: Option<SurfaceId>,
35}
36
37impl Default for RequestAdapterOptions {
38    fn default() -> Self {
39        RequestAdapterOptions {
40            power_preference: PowerPreference::Default,
41            compatible_surface: None,
42        }
43    }
44}
45
46#[derive(Debug)]
47pub struct Instance {
48    #[cfg(any(
49        not(any(target_os = "ios", target_os = "macos")),
50        feature = "gfx-backend-vulkan"
51    ))]
52    pub vulkan: Option<gfx_backend_vulkan::Instance>,
53    #[cfg(any(target_os = "ios", target_os = "macos"))]
54    pub metal: Option<gfx_backend_metal::Instance>,
55    #[cfg(windows)]
56    pub dx12: Option<gfx_backend_dx12::Instance>,
57    #[cfg(windows)]
58    pub dx11: Option<gfx_backend_dx11::Instance>,
59}
60
61impl Instance {
62    pub fn new(name: &str, version: u32, backends: BackendBit) -> Self {
63        backends_map! {
64            let map = |(backend, backend_create)| {
65                if backends.contains(backend.into()) {
66                    backend_create(name, version).ok()
67                } else {
68                    None
69                }
70            };
71            Instance {
72                #[vulkan]
73                vulkan: map((Backend::Vulkan, gfx_backend_vulkan::Instance::create)),
74                #[metal]
75                metal: map((Backend::Metal, gfx_backend_metal::Instance::create)),
76                #[dx12]
77                dx12: map((Backend::Dx12, gfx_backend_dx12::Instance::create)),
78                #[dx11]
79                dx11: map((Backend::Dx11, gfx_backend_dx11::Instance::create)),
80            }
81        }
82    }
83
84    pub(crate) fn destroy_surface(&mut self, surface: Surface) {
85        backends_map! {
86            let map = |(surface_backend, self_backend)| {
87                unsafe {
88                    if let Some(suf) = surface_backend {
89                        self_backend.as_mut().unwrap().destroy_surface(suf);
90                    }
91                }
92            };
93
94            #[vulkan]
95            map((surface.vulkan, &mut self.vulkan)),
96            #[metal]
97            map((surface.metal, &mut self.metal)),
98            #[dx12]
99            map((surface.dx12, &mut self.dx12)),
100            #[dx11]
101            map((surface.dx11, &mut self.dx11)),
102        }
103    }
104}
105
106type GfxSurface<B> = <B as hal::Backend>::Surface;
107
108#[derive(Debug)]
109pub struct Surface {
110    #[cfg(any(
111        not(any(target_os = "ios", target_os = "macos")),
112        feature = "gfx-backend-vulkan"
113    ))]
114    pub vulkan: Option<GfxSurface<backend::Vulkan>>,
115    #[cfg(any(target_os = "ios", target_os = "macos"))]
116    pub metal: Option<GfxSurface<backend::Metal>>,
117    #[cfg(windows)]
118    pub dx12: Option<GfxSurface<backend::Dx12>>,
119    #[cfg(windows)]
120    pub dx11: Option<GfxSurface<backend::Dx11>>,
121}
122
123#[derive(Debug)]
124pub struct Adapter<B: hal::Backend> {
125    pub(crate) raw: hal::adapter::Adapter<B>,
126    features: wgt::Features,
127    limits: wgt::Limits,
128    life_guard: LifeGuard,
129}
130
131impl<B: hal::Backend> Adapter<B> {
132    fn new(raw: hal::adapter::Adapter<B>) -> Self {
133        span!(_guard, INFO, "Adapter::new");
134
135        let adapter_features = raw.physical_device.features();
136
137        let mut features = wgt::Features::default() | wgt::Features::MAPPABLE_PRIMARY_BUFFERS;
138        features.set(
139            wgt::Features::SAMPLED_TEXTURE_BINDING_ARRAY,
140            adapter_features.contains(hal::Features::TEXTURE_DESCRIPTOR_ARRAY),
141        );
142        features.set(
143            wgt::Features::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING,
144            adapter_features.contains(hal::Features::SHADER_SAMPLED_IMAGE_ARRAY_DYNAMIC_INDEXING),
145        );
146        features.set(
147            wgt::Features::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
148            adapter_features.contains(hal::Features::SAMPLED_TEXTURE_DESCRIPTOR_INDEXING),
149        );
150        features.set(
151            wgt::Features::UNSIZED_BINDING_ARRAY,
152            adapter_features.contains(hal::Features::UNSIZED_DESCRIPTOR_ARRAY),
153        );
154        features.set(
155            wgt::Features::MULTI_DRAW_INDIRECT,
156            adapter_features.contains(hal::Features::MULTI_DRAW_INDIRECT),
157        );
158        features.set(
159            wgt::Features::MULTI_DRAW_INDIRECT_COUNT,
160            adapter_features.contains(hal::Features::DRAW_INDIRECT_COUNT),
161        );
162
163        let adapter_limits = raw.physical_device.limits();
164
165        let limits = wgt::Limits {
166            max_bind_groups: (adapter_limits.max_bound_descriptor_sets as u32)
167                .min(MAX_BIND_GROUPS as u32),
168            _non_exhaustive: unsafe { wgt::NonExhaustive::new() },
169        };
170
171        Adapter {
172            raw,
173            features,
174            limits,
175            life_guard: LifeGuard::new(),
176        }
177    }
178}
179
180/// Metadata about a backend adapter.
181#[derive(Clone, Debug, PartialEq)]
182#[cfg_attr(feature = "trace", derive(Serialize))]
183#[cfg_attr(feature = "replay", derive(Deserialize))]
184pub struct AdapterInfo {
185    /// Adapter name
186    pub name: String,
187    /// Vendor PCI id of the adapter
188    pub vendor: usize,
189    /// PCI id of the adapter
190    pub device: usize,
191    /// Type of device
192    pub device_type: DeviceType,
193    /// Backend used for device
194    pub backend: Backend,
195}
196
197impl AdapterInfo {
198    fn from_gfx(adapter_info: HalAdapterInfo, backend: Backend) -> Self {
199        let HalAdapterInfo {
200            name,
201            vendor,
202            device,
203            device_type,
204        } = adapter_info;
205
206        AdapterInfo {
207            name,
208            vendor,
209            device,
210            device_type: device_type.into(),
211            backend,
212        }
213    }
214}
215
216#[derive(Clone, Debug, PartialEq)]
217/// Error when requesting a device from the adaptor
218pub enum RequestDeviceError {
219    /// Unsupported feature extension was requested
220    UnsupportedFeature(wgt::Features),
221    /// Requested device limits were exceeded
222    LimitsExceeded,
223}
224
225impl Display for RequestDeviceError {
226    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
227        match &self {
228            RequestDeviceError::UnsupportedFeature(features) => write!(
229                f,
230                "Cannot enable features that adapter doesn't support. Unsupported extensions: {:?}",
231                features
232            ),
233            RequestDeviceError::LimitsExceeded => {
234                write!(f, "Some of the requested limits are not supported",)
235            }
236        }
237    }
238}
239
240/// Supported physical device types.
241#[derive(Clone, Debug, PartialEq)]
242#[cfg_attr(feature = "trace", derive(Serialize))]
243#[cfg_attr(feature = "replay", derive(Deserialize))]
244pub enum DeviceType {
245    /// Other.
246    Other,
247    /// Integrated GPU with shared CPU/GPU memory.
248    IntegratedGpu,
249    /// Discrete GPU with separate CPU/GPU memory.
250    DiscreteGpu,
251    /// Virtual / Hosted.
252    VirtualGpu,
253    /// Cpu / Software Rendering.
254    Cpu,
255}
256
257impl From<HalDeviceType> for DeviceType {
258    fn from(device_type: HalDeviceType) -> Self {
259        match device_type {
260            HalDeviceType::Other => Self::Other,
261            HalDeviceType::IntegratedGpu => Self::IntegratedGpu,
262            HalDeviceType::DiscreteGpu => Self::DiscreteGpu,
263            HalDeviceType::VirtualGpu => Self::VirtualGpu,
264            HalDeviceType::Cpu => Self::Cpu,
265        }
266    }
267}
268
269pub enum AdapterInputs<'a, I> {
270    IdSet(&'a [I], fn(&I) -> Backend),
271    Mask(BackendBit, fn(Backend) -> I),
272}
273
274impl<I: Clone> AdapterInputs<'_, I> {
275    fn find(&self, b: Backend) -> Option<I> {
276        match *self {
277            AdapterInputs::IdSet(ids, ref fun) => ids.iter().find(|id| fun(id) == b).cloned(),
278            AdapterInputs::Mask(bits, ref fun) => {
279                if bits.contains(b.into()) {
280                    Some(fun(b))
281                } else {
282                    None
283                }
284            }
285        }
286    }
287}
288
289impl<G: GlobalIdentityHandlerFactory> Global<G> {
290    #[cfg(feature = "raw-window-handle")]
291    pub fn instance_create_surface(
292        &self,
293        handle: &impl raw_window_handle::HasRawWindowHandle,
294        id_in: Input<G, SurfaceId>,
295    ) -> SurfaceId {
296        span!(_guard, INFO, "Instance::create_surface");
297
298        let surface = unsafe {
299            backends_map! {
300                let map = |inst| {
301                    inst
302                    .as_ref()
303                    .and_then(|inst| inst.create_surface(handle).ok())
304                };
305
306                Surface {
307                    #[vulkan]
308                    vulkan: map(&self.instance.vulkan),
309                    #[metal]
310                    metal: map(&self.instance.metal),
311                    #[dx12]
312                    dx12: map(&self.instance.dx12),
313                    #[dx11]
314                    dx11: map(&self.instance.dx11),
315                }
316            }
317        };
318
319        let mut token = Token::root();
320        self.surfaces.register_identity(id_in, surface, &mut token)
321    }
322
323    pub fn enumerate_adapters(&self, inputs: AdapterInputs<Input<G, AdapterId>>) -> Vec<AdapterId> {
324        span!(_guard, INFO, "Instance::enumerate_adapters");
325
326        let instance = &self.instance;
327        let mut token = Token::root();
328        let mut adapters = Vec::new();
329
330        backends_map! {
331            let map = |(instance_field, backend, backend_info, backend_hub)| {
332                if let Some(inst) = instance_field {
333                    if let Some(id_backend) = inputs.find(backend) {
334                        for raw in inst.enumerate_adapters() {
335                            let adapter = Adapter::new(raw);
336                            log::info!("Adapter {} {:?}", backend_info, adapter.raw.info);
337                            adapters.push(backend_hub(self).adapters.register_identity(
338                                id_backend.clone(),
339                                adapter,
340                                &mut token,
341                            ));
342                        }
343                    }
344                }
345            };
346
347            #[vulkan]
348            map((&instance.vulkan, Backend::Vulkan, "Vulkan", backend::Vulkan::hub)),
349            #[metal]
350            map((&instance.metal, Backend::Metal, "Metal", backend::Metal::hub)),
351            #[dx12]
352            map((&instance.dx12, Backend::Dx12, "Dx12", backend::Dx12::hub)),
353            #[dx11]
354            map((&instance.dx11, Backend::Dx11, "Dx11", backend::Dx11::hub)),
355        }
356
357        adapters
358    }
359
360    pub fn pick_adapter(
361        &self,
362        desc: &RequestAdapterOptions,
363        inputs: AdapterInputs<Input<G, AdapterId>>,
364    ) -> Option<AdapterId> {
365        span!(_guard, INFO, "Instance::pick_adapter");
366
367        let instance = &self.instance;
368        let mut token = Token::root();
369        let (surface_guard, mut token) = self.surfaces.read(&mut token);
370        let compatible_surface = desc.compatible_surface.map(|id| &surface_guard[id]);
371        let mut device_types = Vec::new();
372
373        let mut id_vulkan = inputs.find(Backend::Vulkan);
374        let mut id_metal = inputs.find(Backend::Metal);
375        let mut id_dx12 = inputs.find(Backend::Dx12);
376        let mut id_dx11 = inputs.find(Backend::Dx11);
377
378        backends_map! {
379            let map = |(instance_backend, id_backend, surface_backend)| {
380                match instance_backend {
381                    Some(ref inst) if id_backend.is_some() => {
382                        let mut adapters = inst.enumerate_adapters();
383                        if let Some(surface_backend) = compatible_surface.and_then(surface_backend) {
384                            adapters.retain(|a| {
385                                a.queue_families
386                                    .iter()
387                                    .find(|qf| qf.queue_type().supports_graphics())
388                                    .map_or(false, |qf| surface_backend.supports_queue_family(qf))
389                            });
390                        }
391                        device_types.extend(adapters.iter().map(|ad| ad.info.device_type.clone()));
392                        adapters
393                    }
394                    _ => Vec::new(),
395                }
396            };
397
398            // NB: The internal function definitions are a workaround for Rust
399            // being weird with lifetimes for closure literals...
400            #[vulkan]
401            let adapters_vk = map((&instance.vulkan, &id_vulkan, {
402                fn surface_vulkan(surf: &Surface) -> Option<&GfxSurface<backend::Vulkan>> {
403                    surf.vulkan.as_ref()
404                }
405                surface_vulkan
406            }));
407            #[metal]
408            let adapters_mtl = map((&instance.metal, &id_metal, {
409                fn surface_metal(surf: &Surface) -> Option<&GfxSurface<backend::Metal>> {
410                    surf.metal.as_ref()
411                }
412                surface_metal
413            }));
414            #[dx12]
415            let adapters_dx12 = map((&instance.dx12, &id_dx12, {
416                fn surface_dx12(surf: &Surface) -> Option<&GfxSurface<backend::Dx12>> {
417                    surf.dx12.as_ref()
418                }
419                surface_dx12
420            }));
421            #[dx11]
422            let adapters_dx11 = map((&instance.dx11, &id_dx11, {
423                fn surface_dx11(surf: &Surface) -> Option<&GfxSurface<backend::Dx11>> {
424                    surf.dx11.as_ref()
425                }
426                surface_dx11
427            }));
428        }
429
430        if device_types.is_empty() {
431            log::warn!("No adapters are available!");
432            return None;
433        }
434
435        let (mut integrated, mut discrete, mut virt, mut other) = (None, None, None, None);
436
437        for (i, ty) in device_types.into_iter().enumerate() {
438            match ty {
439                hal::adapter::DeviceType::IntegratedGpu => {
440                    integrated = integrated.or(Some(i));
441                }
442                hal::adapter::DeviceType::DiscreteGpu => {
443                    discrete = discrete.or(Some(i));
444                }
445                hal::adapter::DeviceType::VirtualGpu => {
446                    virt = virt.or(Some(i));
447                }
448                _ => {
449                    other = other.or(Some(i));
450                }
451            }
452        }
453
454        let preferred_gpu = match desc.power_preference {
455            PowerPreference::Default => match power::is_battery_discharging() {
456                Ok(false) => discrete.or(integrated).or(other).or(virt),
457                Ok(true) => integrated.or(discrete).or(other).or(virt),
458                Err(err) => {
459                    log::debug!(
460                        "Power info unavailable, preferring integrated gpu ({})",
461                        err
462                    );
463                    integrated.or(discrete).or(other).or(virt)
464                }
465            },
466            PowerPreference::LowPower => integrated.or(other).or(discrete).or(virt),
467            PowerPreference::HighPerformance => discrete.or(other).or(integrated).or(virt),
468        };
469
470        let mut selected = preferred_gpu.unwrap_or(0);
471
472        backends_map! {
473            let map = |(info_adapter, id_backend, mut adapters_backend, backend_hub)| {
474                if selected < adapters_backend.len() {
475                    let adapter = Adapter::new(adapters_backend.swap_remove(selected));
476                    log::info!("Adapter {} {:?}", info_adapter, adapter.raw.info);
477                    let id = backend_hub(self).adapters.register_identity(
478                        id_backend.take().unwrap(),
479                        adapter,
480                        &mut token,
481                    );
482                    return Some(id);
483                }
484                selected -= adapters_backend.len();
485            };
486
487            #[vulkan]
488            map(("Vulkan", &mut id_vulkan, adapters_vk, backend::Vulkan::hub)),
489            #[metal]
490            map(("Metal", &mut id_metal, adapters_mtl, backend::Metal::hub)),
491            #[dx12]
492            map(("Dx12", &mut id_dx12, adapters_dx12, backend::Dx12::hub)),
493            #[dx11]
494            map(("Dx11", &mut id_dx11, adapters_dx11, backend::Dx11::hub)),
495        }
496
497        let _ = (
498            selected,
499            id_vulkan.take(),
500            id_metal.take(),
501            id_dx12.take(),
502            id_dx11.take(),
503        );
504        log::warn!("Some adapters are present, but enumerating them failed!");
505        None
506    }
507
508    pub fn adapter_get_info<B: GfxBackend>(&self, adapter_id: AdapterId) -> AdapterInfo {
509        span!(_guard, INFO, "Adapter::get_info");
510
511        let hub = B::hub(self);
512        let mut token = Token::root();
513        let (adapter_guard, _) = hub.adapters.read(&mut token);
514        let adapter = &adapter_guard[adapter_id];
515        AdapterInfo::from_gfx(adapter.raw.info.clone(), adapter_id.backend())
516    }
517
518    pub fn adapter_features<B: GfxBackend>(&self, adapter_id: AdapterId) -> wgt::Features {
519        span!(_guard, INFO, "Adapter::features");
520
521        let hub = B::hub(self);
522        let mut token = Token::root();
523        let (adapter_guard, _) = hub.adapters.read(&mut token);
524        let adapter = &adapter_guard[adapter_id];
525
526        adapter.features
527    }
528
529    pub fn adapter_limits<B: GfxBackend>(&self, adapter_id: AdapterId) -> wgt::Limits {
530        span!(_guard, INFO, "Adapter::limits");
531
532        let hub = B::hub(self);
533        let mut token = Token::root();
534        let (adapter_guard, _) = hub.adapters.read(&mut token);
535        let adapter = &adapter_guard[adapter_id];
536
537        adapter.limits.clone()
538    }
539
540    pub fn adapter_destroy<B: GfxBackend>(&self, adapter_id: AdapterId) {
541        span!(_guard, INFO, "Adapter::drop");
542
543        let hub = B::hub(self);
544        let mut token = Token::root();
545        let (mut guard, _) = hub.adapters.write(&mut token);
546
547        if guard[adapter_id]
548            .life_guard
549            .ref_count
550            .take()
551            .unwrap()
552            .load()
553            == 1
554        {
555            hub.adapters.free_id(adapter_id);
556            let _adapter = guard.remove(adapter_id).unwrap();
557        }
558    }
559}
560
561impl<G: GlobalIdentityHandlerFactory> Global<G> {
562    pub fn adapter_request_device<B: GfxBackend>(
563        &self,
564        adapter_id: AdapterId,
565        desc: &DeviceDescriptor,
566        trace_path: Option<&std::path::Path>,
567        id_in: Input<G, DeviceId>,
568    ) -> Result<DeviceId, RequestDeviceError> {
569        span!(_guard, INFO, "Adapter::request_device");
570
571        let hub = B::hub(self);
572        let mut token = Token::root();
573        let device = {
574            let (adapter_guard, _) = hub.adapters.read(&mut token);
575            let adapter = &adapter_guard[adapter_id];
576            let phd = &adapter.raw.physical_device;
577
578            // Verify all features were exposed by the adapter
579            if !adapter.features.contains(desc.features) {
580                return Err(RequestDeviceError::UnsupportedFeature(
581                    desc.features - adapter.features,
582                ));
583            }
584
585            // Verify feature preconditions
586            if desc
587                .features
588                .contains(wgt::Features::MAPPABLE_PRIMARY_BUFFERS)
589                && adapter.raw.info.device_type == hal::adapter::DeviceType::DiscreteGpu
590            {
591                log::warn!("Feature MAPPABLE_PRIMARY_BUFFERS enabled on a discrete gpu. This is a massive performance footgun and likely not what you wanted");
592            }
593
594            let available_features = adapter.raw.physical_device.features();
595
596            // Check features that are always needed
597            let wishful_features = hal::Features::VERTEX_STORES_AND_ATOMICS
598                | hal::Features::FRAGMENT_STORES_AND_ATOMICS
599                | hal::Features::NDC_Y_UP
600                | hal::Features::INDEPENDENT_BLENDING
601                | hal::Features::SAMPLER_ANISOTROPY;
602            let mut enabled_features = available_features & wishful_features;
603            if enabled_features != wishful_features {
604                log::warn!(
605                    "Missing features: {:?}",
606                    wishful_features - enabled_features
607                );
608            }
609
610            // Features
611            enabled_features.set(
612                hal::Features::TEXTURE_DESCRIPTOR_ARRAY,
613                adapter
614                    .features
615                    .contains(wgt::Features::SAMPLED_TEXTURE_BINDING_ARRAY),
616            );
617            enabled_features.set(
618                hal::Features::SHADER_SAMPLED_IMAGE_ARRAY_DYNAMIC_INDEXING,
619                adapter
620                    .features
621                    .contains(wgt::Features::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING),
622            );
623            enabled_features.set(
624                hal::Features::SHADER_SAMPLED_IMAGE_ARRAY_DYNAMIC_INDEXING,
625                adapter
626                    .features
627                    .contains(wgt::Features::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING),
628            );
629            enabled_features.set(
630                hal::Features::SAMPLED_TEXTURE_DESCRIPTOR_INDEXING,
631                adapter
632                    .features
633                    .contains(wgt::Features::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING),
634            );
635            enabled_features.set(
636                hal::Features::UNSIZED_DESCRIPTOR_ARRAY,
637                adapter
638                    .features
639                    .contains(wgt::Features::UNSIZED_BINDING_ARRAY),
640            );
641            enabled_features.set(
642                hal::Features::MULTI_DRAW_INDIRECT,
643                adapter
644                    .features
645                    .contains(wgt::Features::MULTI_DRAW_INDIRECT),
646            );
647            enabled_features.set(
648                hal::Features::DRAW_INDIRECT_COUNT,
649                adapter
650                    .features
651                    .contains(wgt::Features::MULTI_DRAW_INDIRECT_COUNT),
652            );
653
654            let family = adapter
655                .raw
656                .queue_families
657                .iter()
658                .find(|family| family.queue_type().supports_graphics())
659                .unwrap();
660            let mut gpu = unsafe { phd.open(&[(family, &[1.0])], enabled_features).unwrap() };
661
662            let limits = phd.limits();
663            assert_eq!(
664                0,
665                BIND_BUFFER_ALIGNMENT % limits.min_storage_buffer_offset_alignment,
666                "Adapter storage buffer offset alignment not compatible with WGPU"
667            );
668            assert_eq!(
669                0,
670                BIND_BUFFER_ALIGNMENT % limits.min_uniform_buffer_offset_alignment,
671                "Adapter uniform buffer offset alignment not compatible with WGPU"
672            );
673            if limits.max_bound_descriptor_sets == 0 {
674                log::warn!("max_bind_groups limit is missing");
675            } else {
676                if adapter.limits.max_bind_groups < desc.limits.max_bind_groups {
677                    return Err(RequestDeviceError::LimitsExceeded);
678                }
679            }
680
681            let mem_props = phd.memory_properties();
682            if !desc.shader_validation {
683                log::warn!("Shader validation is disabled");
684            }
685            let private_features = PrivateFeatures {
686                shader_validation: desc.shader_validation,
687                anisotropic_filtering: enabled_features.contains(hal::Features::SAMPLER_ANISOTROPY),
688                texture_d24_s8: phd
689                    .format_properties(Some(hal::format::Format::D24UnormS8Uint))
690                    .optimal_tiling
691                    .contains(hal::format::ImageFeature::DEPTH_STENCIL_ATTACHMENT),
692            };
693
694            Device::new(
695                gpu.device,
696                Stored {
697                    value: adapter_id,
698                    ref_count: adapter.life_guard.add_ref(),
699                },
700                gpu.queue_groups.swap_remove(0),
701                mem_props,
702                limits,
703                private_features,
704                desc,
705                trace_path,
706            )
707        };
708
709        Ok(hub.devices.register_identity(id_in, device, &mut token))
710    }
711}