wgpu_core/
instance.rs

1use alloc::{
2    borrow::{Cow, ToOwned as _},
3    boxed::Box,
4    string::String,
5    sync::Arc,
6    vec,
7    vec::Vec,
8};
9
10use hashbrown::HashMap;
11use thiserror::Error;
12use wgt::error::{ErrorType, WebGpuError};
13
14use crate::{
15    api_log, api_log_debug,
16    device::{queue::Queue, resource::Device, DeviceDescriptor, DeviceError},
17    global::Global,
18    id::{markers, AdapterId, DeviceId, QueueId, SurfaceId},
19    lock::{rank, Mutex},
20    present::Presentation,
21    resource::ResourceType,
22    resource_log,
23    timestamp_normalization::TimestampNormalizerInitError,
24    DOWNLEVEL_WARNING_MESSAGE,
25};
26
27use wgt::{Backend, Backends, PowerPreference};
28
29pub type RequestAdapterOptions = wgt::RequestAdapterOptions<SurfaceId>;
30
31#[derive(Clone, Debug, Error)]
32#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
33#[error("Limit '{name}' value {requested} is better than allowed {allowed}")]
34pub struct FailedLimit {
35    name: Cow<'static, str>,
36    requested: u64,
37    allowed: u64,
38}
39
40impl WebGpuError for FailedLimit {
41    fn webgpu_error_type(&self) -> ErrorType {
42        ErrorType::Validation
43    }
44}
45
46fn check_limits(requested: &wgt::Limits, allowed: &wgt::Limits) -> Vec<FailedLimit> {
47    let mut failed = Vec::new();
48
49    requested.check_limits_with_fail_fn(allowed, false, |name, requested, allowed| {
50        failed.push(FailedLimit {
51            name: Cow::Borrowed(name),
52            requested,
53            allowed,
54        })
55    });
56
57    failed
58}
59
60#[test]
61fn downlevel_default_limits_less_than_default_limits() {
62    let res = check_limits(&wgt::Limits::downlevel_defaults(), &wgt::Limits::default());
63    assert!(
64        res.is_empty(),
65        "Downlevel limits are greater than default limits",
66    )
67}
68
69#[derive(Default)]
70pub struct Instance {
71    #[allow(dead_code)]
72    name: String,
73
74    /// List of instances per `wgpu-hal` backend.
75    ///
76    /// The ordering in this list implies prioritization and needs to be preserved.
77    instance_per_backend: Vec<(Backend, Box<dyn hal::DynInstance>)>,
78
79    /// The backends that were requested by the user.
80    requested_backends: Backends,
81
82    /// The backends that we could have attempted to obtain from `wgpu-hal` —
83    /// those for which support is compiled in, currently.
84    ///
85    /// The union of this and `requested_backends` is the set of backends that would be used,
86    /// independent of whether accessing the drivers/hardware for them succeeds.
87    /// To obtain the set of backends actually in use by this instance, check
88    /// `instance_per_backend` instead.
89    supported_backends: Backends,
90
91    pub flags: wgt::InstanceFlags,
92
93    /// Non-lifetimed [`raw_window_handle::DisplayHandle`], for keepalive and validation purposes in
94    /// [`Self::create_surface()`].
95    ///
96    /// When used with `winit`, callers are expected to pass its `OwnedDisplayHandle` (created from
97    /// the `EventLoop`) here.
98    display: Option<Box<dyn wgt::WgpuHasDisplayHandle>>,
99}
100
101impl Instance {
102    pub fn new(
103        name: &str,
104        mut instance_desc: wgt::InstanceDescriptor,
105        telemetry: Option<hal::Telemetry>,
106    ) -> Self {
107        let mut this = Self {
108            name: name.to_owned(),
109            instance_per_backend: Vec::new(),
110            requested_backends: instance_desc.backends,
111            supported_backends: Backends::empty(),
112            flags: instance_desc.flags,
113            // HACK: We must take ownership of the field here, without being able to pass it into
114            // try_add_hal(). Remove it from the mutable descriptor instead, while try_add_hal()
115            // borrows the handle from `this.display` instead.
116            display: instance_desc.display.take(),
117        };
118
119        #[cfg(vulkan)]
120        this.try_add_hal(hal::api::Vulkan, &instance_desc, telemetry);
121        #[cfg(metal)]
122        this.try_add_hal(hal::api::Metal, &instance_desc, telemetry);
123        #[cfg(dx12)]
124        this.try_add_hal(hal::api::Dx12, &instance_desc, telemetry);
125        #[cfg(gles)]
126        this.try_add_hal(hal::api::Gles, &instance_desc, telemetry);
127        #[cfg(feature = "noop")]
128        this.try_add_hal(hal::api::Noop, &instance_desc, telemetry);
129
130        this
131    }
132
133    /// Helper for `Instance::new()`; attempts to add a single `wgpu-hal` backend to this instance.
134    fn try_add_hal<A: hal::Api>(
135        &mut self,
136        _: A,
137        instance_desc: &wgt::InstanceDescriptor,
138        telemetry: Option<hal::Telemetry>,
139    ) {
140        // Whether or not the backend was requested, and whether or not it succeeds,
141        // note that we *could* try it.
142        self.supported_backends |= A::VARIANT.into();
143
144        if !instance_desc.backends.contains(A::VARIANT.into()) {
145            log::trace!("Instance::new: backend {:?} not requested", A::VARIANT);
146            return;
147        }
148
149        // If this was Some, it was moved into self
150        assert!(instance_desc.display.is_none());
151
152        let hal_desc = hal::InstanceDescriptor {
153            name: "wgpu",
154            flags: self.flags,
155            memory_budget_thresholds: instance_desc.memory_budget_thresholds,
156            backend_options: instance_desc.backend_options.clone(),
157            telemetry,
158            // Pass a borrow, the core instance here keeps the owned handle alive already
159            // WARNING: Using self here, not instance_desc!
160            display: self.display.as_ref().map(|hdh| {
161                hdh.display_handle()
162                    .expect("Implementation did not provide a DisplayHandle")
163            }),
164        };
165
166        use hal::Instance as _;
167        // SAFETY: ???
168        match unsafe { A::Instance::init(&hal_desc) } {
169            Ok(instance) => {
170                log::debug!("Instance::new: created {:?} backend", A::VARIANT);
171                self.instance_per_backend
172                    .push((A::VARIANT, Box::new(instance)));
173            }
174            Err(err) => {
175                log::debug!(
176                    "Instance::new: failed to create {:?} backend: {:?}",
177                    A::VARIANT,
178                    err
179                );
180            }
181        }
182    }
183
184    pub(crate) fn from_hal_instance<A: hal::Api>(
185        name: String,
186        hal_instance: <A as hal::Api>::Instance,
187    ) -> Self {
188        Self {
189            name,
190            instance_per_backend: vec![(A::VARIANT, Box::new(hal_instance))],
191            requested_backends: A::VARIANT.into(),
192            supported_backends: A::VARIANT.into(),
193            flags: wgt::InstanceFlags::default(),
194            display: None, // TODO: Extract display from HAL instance if available?
195        }
196    }
197
198    pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynInstance> {
199        self.instance_per_backend
200            .iter()
201            .find_map(|(instance_backend, instance)| {
202                (*instance_backend == backend).then(|| instance.as_ref())
203            })
204    }
205
206    /// # Safety
207    ///
208    /// - The raw instance handle returned must not be manually destroyed.
209    pub unsafe fn as_hal<A: hal::Api>(&self) -> Option<&A::Instance> {
210        self.raw(A::VARIANT).map(|instance| {
211            instance
212                .as_any()
213                .downcast_ref()
214                // This should be impossible. It would mean that backend instance and enum type are mismatching.
215                .expect("Stored instance is not of the correct type")
216        })
217    }
218
219    /// Creates a new surface targeting the given display/window handles.
220    ///
221    /// Internally attempts to create hal surfaces for all enabled backends.
222    ///
223    /// Fails only if creation for surfaces for all enabled backends fails in which case
224    /// the error for each enabled backend is listed.
225    /// Vice versa, if creation for any backend succeeds, success is returned.
226    /// Surface creation errors are logged to the debug log in any case.
227    ///
228    /// # Safety
229    ///
230    /// - `display_handle` must be a valid object to create a surface upon.
231    /// - `window_handle` must remain valid as long as the returned
232    ///   [`SurfaceId`] is being used.
233    pub unsafe fn create_surface(
234        &self,
235        display_handle: raw_window_handle::RawDisplayHandle,
236        window_handle: raw_window_handle::RawWindowHandle,
237    ) -> Result<Surface, CreateSurfaceError> {
238        profiling::scope!("Instance::create_surface");
239
240        if let Some(instance_display_handle) = &self.display {
241            if instance_display_handle
242                .display_handle()
243                .expect("Implementation did not provide a DisplayHandle")
244                .as_raw()
245                != display_handle
246            {
247                return Err(CreateSurfaceError::MismatchingDisplayHandle);
248            }
249        }
250
251        let mut errors = HashMap::default();
252        let mut surface_per_backend = HashMap::default();
253
254        for (backend, instance) in &self.instance_per_backend {
255            match unsafe {
256                instance
257                    .as_ref()
258                    .create_surface(display_handle, window_handle)
259            } {
260                Ok(raw) => {
261                    surface_per_backend.insert(*backend, raw);
262                }
263                Err(err) => {
264                    log::debug!(
265                        "Instance::create_surface: failed to create surface for {backend:?}: {err:?}"
266                    );
267                    errors.insert(*backend, err);
268                }
269            }
270        }
271
272        if surface_per_backend.is_empty() {
273            Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
274                errors,
275            ))
276        } else {
277            let surface = Surface {
278                presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
279                surface_per_backend,
280            };
281
282            Ok(surface)
283        }
284    }
285
286    /// Creates a new surface from the given drm configuration.
287    ///
288    /// # Safety
289    ///
290    /// - All parameters must point to valid DRM values.
291    ///
292    /// # Platform Support
293    ///
294    /// This function is only available on non-apple Unix-like platforms (Linux, FreeBSD) and
295    /// currently only works with the Vulkan backend.
296    #[cfg(all(unix, not(target_vendor = "apple"), not(target_family = "wasm")))]
297    #[cfg_attr(not(vulkan), expect(unused_variables))]
298    pub unsafe fn create_surface_from_drm(
299        &self,
300        fd: i32,
301        plane: u32,
302        connector_id: u32,
303        width: u32,
304        height: u32,
305        refresh_rate: u32,
306    ) -> Result<Surface, CreateSurfaceError> {
307        profiling::scope!("Instance::create_surface_from_drm");
308
309        let mut errors = HashMap::default();
310        let mut surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>> =
311            HashMap::default();
312
313        #[cfg(vulkan)]
314        {
315            let instance = unsafe { self.as_hal::<hal::api::Vulkan>() }
316                .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Vulkan))?;
317
318            // Safety must be upheld by the caller
319            match unsafe {
320                instance.create_surface_from_drm(
321                    fd,
322                    plane,
323                    connector_id,
324                    width,
325                    height,
326                    refresh_rate,
327                )
328            } {
329                Ok(surface) => {
330                    surface_per_backend.insert(Backend::Vulkan, Box::new(surface));
331                }
332                Err(err) => {
333                    errors.insert(Backend::Vulkan, err);
334                }
335            }
336        }
337
338        if surface_per_backend.is_empty() {
339            Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
340                errors,
341            ))
342        } else {
343            let surface = Surface {
344                presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
345                surface_per_backend,
346            };
347
348            Ok(surface)
349        }
350    }
351
352    /// # Safety
353    ///
354    /// `layer` must be a valid pointer.
355    #[cfg(metal)]
356    pub unsafe fn create_surface_metal(
357        &self,
358        layer: *mut core::ffi::c_void,
359    ) -> Result<Surface, CreateSurfaceError> {
360        profiling::scope!("Instance::create_surface_metal");
361
362        let instance = unsafe { self.as_hal::<hal::api::Metal>() }
363            .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Metal))?;
364
365        let layer = layer.cast();
366        // SAFETY: We do this cast and deref. (rather than using `metal` to get the
367        // object we want) to avoid direct coupling on the `metal` crate.
368        //
369        // To wit, this pointer…
370        //
371        // - …is properly aligned.
372        // - …is dereferenceable to a `MetalLayerRef` as an invariant of the `metal`
373        //   field.
374        // - …points to an _initialized_ `MetalLayerRef`.
375        // - …is only ever aliased via an immutable reference that lives within this
376        //   lexical scope.
377        let layer = unsafe { &*layer };
378        let raw_surface: Box<dyn hal::DynSurface> =
379            Box::new(instance.create_surface_from_layer(layer));
380
381        let surface = Surface {
382            presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
383            surface_per_backend: core::iter::once((Backend::Metal, raw_surface)).collect(),
384        };
385
386        Ok(surface)
387    }
388
389    #[cfg(dx12)]
390    fn create_surface_dx12(
391        &self,
392        create_surface_func: impl FnOnce(&hal::dx12::Instance) -> hal::dx12::Surface,
393    ) -> Result<Surface, CreateSurfaceError> {
394        let instance = unsafe { self.as_hal::<hal::api::Dx12>() }
395            .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Dx12))?;
396        let surface: Box<dyn hal::DynSurface> = Box::new(create_surface_func(instance));
397
398        let surface = Surface {
399            presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
400            surface_per_backend: core::iter::once((Backend::Dx12, surface)).collect(),
401        };
402
403        Ok(surface)
404    }
405
406    #[cfg(dx12)]
407    /// # Safety
408    ///
409    /// The visual must be valid and able to be used to make a swapchain with.
410    pub unsafe fn create_surface_from_visual(
411        &self,
412        visual: *mut core::ffi::c_void,
413    ) -> Result<Surface, CreateSurfaceError> {
414        profiling::scope!("Instance::instance_create_surface_from_visual");
415        self.create_surface_dx12(|inst| unsafe { inst.create_surface_from_visual(visual) })
416    }
417
418    #[cfg(dx12)]
419    /// # Safety
420    ///
421    /// The surface_handle must be valid and able to be used to make a swapchain with.
422    pub unsafe fn create_surface_from_surface_handle(
423        &self,
424        surface_handle: *mut core::ffi::c_void,
425    ) -> Result<Surface, CreateSurfaceError> {
426        profiling::scope!("Instance::instance_create_surface_from_surface_handle");
427        self.create_surface_dx12(|inst| unsafe {
428            inst.create_surface_from_surface_handle(surface_handle)
429        })
430    }
431
432    #[cfg(dx12)]
433    /// # Safety
434    ///
435    /// The swap_chain_panel must be valid and able to be used to make a swapchain with.
436    pub unsafe fn create_surface_from_swap_chain_panel(
437        &self,
438        swap_chain_panel: *mut core::ffi::c_void,
439    ) -> Result<Surface, CreateSurfaceError> {
440        profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel");
441        self.create_surface_dx12(|inst| unsafe {
442            inst.create_surface_from_swap_chain_panel(swap_chain_panel)
443        })
444    }
445
446    pub fn enumerate_adapters(&self, backends: Backends) -> Vec<Adapter> {
447        profiling::scope!("Instance::enumerate_adapters");
448        api_log!("Instance::enumerate_adapters");
449
450        let mut adapters = Vec::new();
451        for (_backend, instance) in self
452            .instance_per_backend
453            .iter()
454            .filter(|(backend, _)| backends.contains(Backends::from(*backend)))
455        {
456            // NOTE: We might be using `profiling` without any features. The empty backend of this
457            // macro emits no code, so unused code linting changes depending on the backend.
458            profiling::scope!("enumerating", &*alloc::format!("{_backend:?}"));
459
460            let hal_adapters = unsafe { instance.enumerate_adapters(None) };
461            for raw in hal_adapters {
462                let adapter = Adapter::new(raw);
463                api_log_debug!("Adapter {:?}", adapter.raw.info);
464                adapters.push(adapter);
465            }
466        }
467        adapters
468    }
469
470    pub fn request_adapter(
471        &self,
472        desc: &wgt::RequestAdapterOptions<&Surface>,
473        backends: Backends,
474    ) -> Result<Adapter, wgt::RequestAdapterError> {
475        profiling::scope!("Instance::request_adapter");
476        api_log!("Instance::request_adapter");
477
478        let mut adapters = Vec::new();
479        let mut incompatible_surface_backends = Backends::empty();
480        let mut no_fallback_backends = Backends::empty();
481        let mut no_adapter_backends = Backends::empty();
482
483        for &(backend, ref instance) in self
484            .instance_per_backend
485            .iter()
486            .filter(|&&(backend, _)| backends.contains(Backends::from(backend)))
487        {
488            let compatible_hal_surface = desc
489                .compatible_surface
490                .and_then(|surface| surface.raw(backend));
491
492            let mut backend_adapters =
493                unsafe { instance.enumerate_adapters(compatible_hal_surface) };
494            if backend_adapters.is_empty() {
495                log::debug!("enabled backend `{backend:?}` has no adapters");
496                no_adapter_backends |= Backends::from(backend);
497                // by continuing, we avoid setting the further error bits below
498                continue;
499            }
500
501            if desc.force_fallback_adapter {
502                log::debug!("Filtering `{backend:?}` for `force_fallback_adapter`");
503                backend_adapters.retain(|exposed| {
504                    let keep = exposed.info.device_type == wgt::DeviceType::Cpu;
505                    if !keep {
506                        log::debug!("* Eliminating adapter `{}`", exposed.info.name);
507                    }
508                    keep
509                });
510                if backend_adapters.is_empty() {
511                    log::debug!("* Backend `{backend:?}` has no fallback adapters");
512                    no_fallback_backends |= Backends::from(backend);
513                    continue;
514                }
515            }
516
517            if let Some(surface) = desc.compatible_surface {
518                backend_adapters.retain(|exposed| {
519                    let capabilities = surface.get_capabilities_with_raw(exposed);
520                    if let Err(err) = capabilities {
521                        log::debug!(
522                            "Adapter {:?} not compatible with surface: {}",
523                            exposed.info,
524                            err
525                        );
526                        incompatible_surface_backends |= Backends::from(backend);
527                        false
528                    } else {
529                        true
530                    }
531                });
532                if backend_adapters.is_empty() {
533                    incompatible_surface_backends |= Backends::from(backend);
534                    continue;
535                }
536            }
537            adapters.extend(backend_adapters);
538        }
539
540        match desc.power_preference {
541            PowerPreference::LowPower => {
542                sort(&mut adapters, true);
543            }
544            PowerPreference::HighPerformance => {
545                sort(&mut adapters, false);
546            }
547            PowerPreference::None => {}
548        };
549
550        fn sort(adapters: &mut [hal::DynExposedAdapter], prefer_integrated_gpu: bool) {
551            adapters
552                .sort_by_key(|adapter| get_order(adapter.info.device_type, prefer_integrated_gpu));
553        }
554
555        fn get_order(device_type: wgt::DeviceType, prefer_integrated_gpu: bool) -> u8 {
556            // Since devices of type "Other" might really be "Unknown" and come
557            // from APIs like OpenGL that don't specify device type, Prefer more
558            // Specific types over Other.
559            //
560            // This means that backends which do provide accurate device types
561            // will be preferred if their device type indicates an actual
562            // hardware GPU (integrated or discrete).
563            match device_type {
564                wgt::DeviceType::DiscreteGpu if prefer_integrated_gpu => 2,
565                wgt::DeviceType::IntegratedGpu if prefer_integrated_gpu => 1,
566                wgt::DeviceType::DiscreteGpu => 1,
567                wgt::DeviceType::IntegratedGpu => 2,
568                wgt::DeviceType::Other => 3,
569                wgt::DeviceType::VirtualGpu => 4,
570                wgt::DeviceType::Cpu => 5,
571            }
572        }
573
574        // `request_adapter` can be a bit of a black box.
575        // Shine some light on its decision in debug log.
576        if adapters.is_empty() {
577            log::debug!("Request adapter didn't find compatible adapters.");
578        } else {
579            log::debug!(
580                "Found {} compatible adapters. Sorted by preference:",
581                adapters.len()
582            );
583            for adapter in &adapters {
584                log::debug!("* {:?}", adapter.info);
585            }
586        }
587
588        if let Some(adapter) = adapters.into_iter().next() {
589            api_log_debug!("Request adapter result {:?}", adapter.info);
590            let adapter = Adapter::new(adapter);
591            Ok(adapter)
592        } else {
593            Err(wgt::RequestAdapterError::NotFound {
594                supported_backends: self.supported_backends,
595                requested_backends: self.requested_backends,
596                active_backends: self.active_backends(),
597                no_fallback_backends,
598                no_adapter_backends,
599                incompatible_surface_backends,
600            })
601        }
602    }
603
604    fn active_backends(&self) -> Backends {
605        self.instance_per_backend
606            .iter()
607            .map(|&(backend, _)| Backends::from(backend))
608            .collect()
609    }
610}
611
612pub struct Surface {
613    pub(crate) presentation: Mutex<Option<Presentation>>,
614    pub surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>>,
615}
616
617impl ResourceType for Surface {
618    const TYPE: &'static str = "Surface";
619}
620impl crate::storage::StorageItem for Surface {
621    type Marker = markers::Surface;
622}
623
624impl Surface {
625    pub fn get_capabilities(
626        &self,
627        adapter: &Adapter,
628    ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
629        self.get_capabilities_with_raw(&adapter.raw)
630    }
631
632    pub fn get_capabilities_with_raw(
633        &self,
634        adapter: &hal::DynExposedAdapter,
635    ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
636        let backend = adapter.backend();
637        let suf = self
638            .raw(backend)
639            .ok_or(GetSurfaceSupportError::NotSupportedByBackend(backend))?;
640        profiling::scope!("surface_capabilities");
641        let caps = unsafe { adapter.adapter.surface_capabilities(suf) }
642            .ok_or(GetSurfaceSupportError::FailedToRetrieveSurfaceCapabilitiesForAdapter)?;
643        Ok(caps)
644    }
645
646    pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynSurface> {
647        self.surface_per_backend
648            .get(&backend)
649            .map(|surface| surface.as_ref())
650    }
651}
652
653impl Drop for Surface {
654    fn drop(&mut self) {
655        if let Some(present) = self.presentation.lock().take() {
656            for (&backend, surface) in &self.surface_per_backend {
657                if backend == present.device.backend() {
658                    unsafe { surface.unconfigure(present.device.raw()) };
659                }
660            }
661        }
662    }
663}
664
665pub struct Adapter {
666    pub(crate) raw: hal::DynExposedAdapter,
667}
668
669impl Adapter {
670    pub fn new(mut raw: hal::DynExposedAdapter) -> Self {
671        // WebGPU requires this offset alignment as lower bound on all adapters.
672        const MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND: u32 = 32;
673
674        let limits = &mut raw.capabilities.limits;
675
676        limits.min_uniform_buffer_offset_alignment = limits
677            .min_uniform_buffer_offset_alignment
678            .max(MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND);
679        limits.min_storage_buffer_offset_alignment = limits
680            .min_storage_buffer_offset_alignment
681            .max(MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND);
682
683        Self { raw }
684    }
685
686    /// Returns the backend this adapter is using.
687    pub fn backend(&self) -> Backend {
688        self.raw.backend()
689    }
690
691    pub fn is_surface_supported(&self, surface: &Surface) -> bool {
692        // If get_capabilities returns Err, then the API does not advertise support for the surface.
693        //
694        // This could occur if the user is running their app on Wayland but Vulkan does not support
695        // VK_KHR_wayland_surface.
696        surface.get_capabilities(self).is_ok()
697    }
698
699    pub fn get_info(&self) -> wgt::AdapterInfo {
700        self.raw.info.clone()
701    }
702
703    pub fn features(&self) -> wgt::Features {
704        self.raw.features
705    }
706
707    pub fn limits(&self) -> wgt::Limits {
708        self.raw.capabilities.limits.clone()
709    }
710
711    pub fn downlevel_capabilities(&self) -> wgt::DownlevelCapabilities {
712        self.raw.capabilities.downlevel.clone()
713    }
714
715    pub fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
716        unsafe { self.raw.adapter.get_presentation_timestamp() }
717    }
718
719    pub fn cooperative_matrix_properties(&self) -> Vec<wgt::CooperativeMatrixProperties> {
720        self.raw.capabilities.cooperative_matrix_properties.clone()
721    }
722
723    pub fn get_texture_format_features(
724        &self,
725        format: wgt::TextureFormat,
726    ) -> wgt::TextureFormatFeatures {
727        use hal::TextureFormatCapabilities as Tfc;
728
729        let caps = unsafe { self.raw.adapter.texture_format_capabilities(format) };
730        let mut allowed_usages = wgt::TextureUsages::empty();
731
732        allowed_usages.set(wgt::TextureUsages::COPY_SRC, caps.contains(Tfc::COPY_SRC));
733        allowed_usages.set(wgt::TextureUsages::COPY_DST, caps.contains(Tfc::COPY_DST));
734        allowed_usages.set(
735            wgt::TextureUsages::TEXTURE_BINDING,
736            caps.contains(Tfc::SAMPLED),
737        );
738        allowed_usages.set(
739            wgt::TextureUsages::STORAGE_BINDING,
740            caps.intersects(
741                Tfc::STORAGE_WRITE_ONLY
742                    | Tfc::STORAGE_READ_ONLY
743                    | Tfc::STORAGE_READ_WRITE
744                    | Tfc::STORAGE_ATOMIC,
745            ),
746        );
747        allowed_usages.set(
748            wgt::TextureUsages::RENDER_ATTACHMENT | wgt::TextureUsages::TRANSIENT,
749            caps.intersects(Tfc::COLOR_ATTACHMENT | Tfc::DEPTH_STENCIL_ATTACHMENT),
750        );
751        allowed_usages.set(
752            wgt::TextureUsages::STORAGE_ATOMIC,
753            caps.contains(Tfc::STORAGE_ATOMIC),
754        );
755
756        let mut flags = wgt::TextureFormatFeatureFlags::empty();
757        flags.set(
758            wgt::TextureFormatFeatureFlags::STORAGE_READ_ONLY,
759            caps.contains(Tfc::STORAGE_READ_ONLY),
760        );
761        flags.set(
762            wgt::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY,
763            caps.contains(Tfc::STORAGE_WRITE_ONLY),
764        );
765        flags.set(
766            wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE,
767            caps.contains(Tfc::STORAGE_READ_WRITE),
768        );
769
770        flags.set(
771            wgt::TextureFormatFeatureFlags::STORAGE_ATOMIC,
772            caps.contains(Tfc::STORAGE_ATOMIC),
773        );
774
775        flags.set(
776            wgt::TextureFormatFeatureFlags::FILTERABLE,
777            caps.contains(Tfc::SAMPLED_LINEAR),
778        );
779
780        flags.set(
781            wgt::TextureFormatFeatureFlags::BLENDABLE,
782            caps.contains(Tfc::COLOR_ATTACHMENT_BLEND),
783        );
784
785        flags.set(
786            wgt::TextureFormatFeatureFlags::MULTISAMPLE_X2,
787            caps.contains(Tfc::MULTISAMPLE_X2),
788        );
789        flags.set(
790            wgt::TextureFormatFeatureFlags::MULTISAMPLE_X4,
791            caps.contains(Tfc::MULTISAMPLE_X4),
792        );
793        flags.set(
794            wgt::TextureFormatFeatureFlags::MULTISAMPLE_X8,
795            caps.contains(Tfc::MULTISAMPLE_X8),
796        );
797        flags.set(
798            wgt::TextureFormatFeatureFlags::MULTISAMPLE_X16,
799            caps.contains(Tfc::MULTISAMPLE_X16),
800        );
801
802        flags.set(
803            wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE,
804            caps.contains(Tfc::MULTISAMPLE_RESOLVE),
805        );
806
807        wgt::TextureFormatFeatures {
808            allowed_usages,
809            flags,
810        }
811    }
812
813    #[allow(clippy::type_complexity)]
814    fn create_device_and_queue_from_hal(
815        self: &Arc<Self>,
816        hal_device: hal::DynOpenDevice,
817        desc: &DeviceDescriptor,
818        instance_flags: wgt::InstanceFlags,
819    ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
820        api_log!("Adapter::create_device");
821
822        let device = Device::new(hal_device.device, self, desc, instance_flags)?;
823        let device = Arc::new(device);
824
825        let queue = Queue::new(device.clone(), hal_device.queue, instance_flags)?;
826        let queue = Arc::new(queue);
827
828        device.set_queue(&queue);
829        device.late_init_resources_with_queue()?;
830
831        Ok((device, queue))
832    }
833
834    pub fn create_device_and_queue(
835        self: &Arc<Self>,
836        desc: &DeviceDescriptor,
837        instance_flags: wgt::InstanceFlags,
838    ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
839        // Verify all features were exposed by the adapter
840        if !self.raw.features.contains(desc.required_features) {
841            return Err(RequestDeviceError::UnsupportedFeature(
842                desc.required_features - self.raw.features,
843            ));
844        }
845
846        // Check if experimental features are permitted to be enabled.
847        if desc
848            .required_features
849            .intersects(wgt::Features::all_experimental_mask())
850            && !desc.experimental_features.is_enabled()
851        {
852            return Err(RequestDeviceError::ExperimentalFeaturesNotEnabled(
853                desc.required_features
854                    .intersection(wgt::Features::all_experimental_mask()),
855            ));
856        }
857
858        let caps = &self.raw.capabilities;
859        if Backends::PRIMARY.contains(Backends::from(self.backend()))
860            && !caps.downlevel.is_webgpu_compliant()
861        {
862            let missing_flags = wgt::DownlevelFlags::compliant() - caps.downlevel.flags;
863            log::warn!("Missing downlevel flags: {missing_flags:?}\n{DOWNLEVEL_WARNING_MESSAGE}");
864            log::warn!("{:#?}", caps.downlevel);
865        }
866
867        // Verify feature preconditions
868        if desc
869            .required_features
870            .contains(wgt::Features::MAPPABLE_PRIMARY_BUFFERS)
871            && self.raw.info.device_type == wgt::DeviceType::DiscreteGpu
872        {
873            log::warn!(
874                "Feature MAPPABLE_PRIMARY_BUFFERS enabled on a discrete gpu. \
875                        This is a massive performance footgun and likely not what you wanted"
876            );
877        }
878
879        if let Some(failed) = check_limits(&desc.required_limits, &caps.limits).pop() {
880            return Err(RequestDeviceError::LimitsExceeded(failed));
881        }
882
883        let open = unsafe {
884            self.raw.adapter.open(
885                desc.required_features,
886                &desc.required_limits,
887                &desc.memory_hints,
888            )
889        }
890        .map_err(DeviceError::from_hal)?;
891
892        self.create_device_and_queue_from_hal(open, desc, instance_flags)
893    }
894}
895
896crate::impl_resource_type!(Adapter);
897crate::impl_storage_item!(Adapter);
898
899#[derive(Clone, Debug, Error)]
900#[non_exhaustive]
901pub enum GetSurfaceSupportError {
902    #[error("Surface is not supported for the specified backend {0}")]
903    NotSupportedByBackend(Backend),
904    #[error("Failed to retrieve surface capabilities for the specified adapter.")]
905    FailedToRetrieveSurfaceCapabilitiesForAdapter,
906}
907
908#[derive(Clone, Debug, Error)]
909/// Error when requesting a device from the adapter
910#[non_exhaustive]
911pub enum RequestDeviceError {
912    #[error(transparent)]
913    Device(#[from] DeviceError),
914    #[error(transparent)]
915    LimitsExceeded(#[from] FailedLimit),
916    #[error("Failed to initialize Timestamp Normalizer")]
917    TimestampNormalizerInitFailed(#[from] TimestampNormalizerInitError),
918    #[error("Unsupported features were requested: {0}")]
919    UnsupportedFeature(wgt::Features),
920    #[error(
921        "Some experimental features, {0}, were requested, but experimental features are not enabled"
922    )]
923    ExperimentalFeaturesNotEnabled(wgt::Features),
924}
925
926#[derive(Clone, Debug, Error)]
927#[non_exhaustive]
928pub enum CreateSurfaceError {
929    #[error("The backend {0} was not enabled on the instance.")]
930    BackendNotEnabled(Backend),
931    #[error("Failed to create surface for any enabled backend: {0:?}")]
932    FailedToCreateSurfaceForAnyBackend(HashMap<Backend, hal::InstanceError>),
933    #[error("The display handle used to create this Instance does not match the one used to create a surface on it")]
934    MismatchingDisplayHandle,
935}
936
937impl Global {
938    /// Creates a new surface targeting the given display/window handles.
939    ///
940    /// Internally attempts to create hal surfaces for all enabled backends.
941    ///
942    /// Fails only if creation for surfaces for all enabled backends fails in which case
943    /// the error for each enabled backend is listed.
944    /// Vice versa, if creation for any backend succeeds, success is returned.
945    /// Surface creation errors are logged to the debug log in any case.
946    ///
947    /// id_in:
948    /// - If `Some`, the id to assign to the surface. A new one will be generated otherwise.
949    ///
950    /// # Safety
951    ///
952    /// - `display_handle` must be a valid object to create a surface upon.
953    /// - `window_handle` must remain valid as long as the returned
954    ///   [`SurfaceId`] is being used.
955    pub unsafe fn instance_create_surface(
956        &self,
957        display_handle: raw_window_handle::RawDisplayHandle,
958        window_handle: raw_window_handle::RawWindowHandle,
959        id_in: Option<SurfaceId>,
960    ) -> Result<SurfaceId, CreateSurfaceError> {
961        let surface = unsafe { self.instance.create_surface(display_handle, window_handle) }?;
962        let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
963        Ok(id)
964    }
965
966    /// Creates a new surface from the given drm configuration.
967    ///
968    /// # Safety
969    ///
970    /// - All parameters must point to valid DRM values.
971    ///
972    /// # Platform Support
973    ///
974    /// This function is only available on non-apple Unix-like platforms (Linux, FreeBSD) and
975    /// currently only works with the Vulkan backend.
976    #[cfg(all(unix, not(target_vendor = "apple"), not(target_family = "wasm")))]
977    pub unsafe fn instance_create_surface_from_drm(
978        &self,
979        fd: i32,
980        plane: u32,
981        connector_id: u32,
982        width: u32,
983        height: u32,
984        refresh_rate: u32,
985        id_in: Option<SurfaceId>,
986    ) -> Result<SurfaceId, CreateSurfaceError> {
987        let surface = unsafe {
988            self.instance.create_surface_from_drm(
989                fd,
990                plane,
991                connector_id,
992                width,
993                height,
994                refresh_rate,
995            )
996        }?;
997        let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
998
999        Ok(id)
1000    }
1001
1002    /// # Safety
1003    ///
1004    /// `layer` must be a valid pointer.
1005    #[cfg(metal)]
1006    pub unsafe fn instance_create_surface_metal(
1007        &self,
1008        layer: *mut core::ffi::c_void,
1009        id_in: Option<SurfaceId>,
1010    ) -> Result<SurfaceId, CreateSurfaceError> {
1011        let surface = unsafe { self.instance.create_surface_metal(layer) }?;
1012        let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1013        Ok(id)
1014    }
1015
1016    #[cfg(dx12)]
1017    /// # Safety
1018    ///
1019    /// The visual must be valid and able to be used to make a swapchain with.
1020    pub unsafe fn instance_create_surface_from_visual(
1021        &self,
1022        visual: *mut core::ffi::c_void,
1023        id_in: Option<SurfaceId>,
1024    ) -> Result<SurfaceId, CreateSurfaceError> {
1025        let surface = unsafe { self.instance.create_surface_from_visual(visual) }?;
1026        let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1027        Ok(id)
1028    }
1029
1030    #[cfg(dx12)]
1031    /// # Safety
1032    ///
1033    /// The surface_handle must be valid and able to be used to make a swapchain with.
1034    pub unsafe fn instance_create_surface_from_surface_handle(
1035        &self,
1036        surface_handle: *mut core::ffi::c_void,
1037        id_in: Option<SurfaceId>,
1038    ) -> Result<SurfaceId, CreateSurfaceError> {
1039        let surface = unsafe {
1040            self.instance
1041                .create_surface_from_surface_handle(surface_handle)
1042        }?;
1043        let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1044        Ok(id)
1045    }
1046
1047    #[cfg(dx12)]
1048    /// # Safety
1049    ///
1050    /// The swap_chain_panel must be valid and able to be used to make a swapchain with.
1051    pub unsafe fn instance_create_surface_from_swap_chain_panel(
1052        &self,
1053        swap_chain_panel: *mut core::ffi::c_void,
1054        id_in: Option<SurfaceId>,
1055    ) -> Result<SurfaceId, CreateSurfaceError> {
1056        let surface = unsafe {
1057            self.instance
1058                .create_surface_from_swap_chain_panel(swap_chain_panel)
1059        }?;
1060        let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1061        Ok(id)
1062    }
1063
1064    pub fn surface_drop(&self, id: SurfaceId) {
1065        profiling::scope!("Surface::drop");
1066
1067        api_log!("Surface::drop {id:?}");
1068
1069        self.surfaces.remove(id);
1070    }
1071
1072    pub fn enumerate_adapters(&self, backends: Backends) -> Vec<AdapterId> {
1073        let adapters = self.instance.enumerate_adapters(backends);
1074        adapters
1075            .into_iter()
1076            .map(|adapter| self.hub.adapters.prepare(None).assign(Arc::new(adapter)))
1077            .collect()
1078    }
1079
1080    pub fn request_adapter(
1081        &self,
1082        desc: &RequestAdapterOptions,
1083        backends: Backends,
1084        id_in: Option<AdapterId>,
1085    ) -> Result<AdapterId, wgt::RequestAdapterError> {
1086        let compatible_surface = desc.compatible_surface.map(|id| self.surfaces.get(id));
1087        let desc = wgt::RequestAdapterOptions {
1088            power_preference: desc.power_preference,
1089            force_fallback_adapter: desc.force_fallback_adapter,
1090            compatible_surface: compatible_surface.as_deref(),
1091        };
1092        let adapter = self.instance.request_adapter(&desc, backends)?;
1093        let id = self.hub.adapters.prepare(id_in).assign(Arc::new(adapter));
1094        Ok(id)
1095    }
1096
1097    /// # Safety
1098    ///
1099    /// `hal_adapter` must be created from this global internal instance handle.
1100    pub unsafe fn create_adapter_from_hal(
1101        &self,
1102        hal_adapter: hal::DynExposedAdapter,
1103        input: Option<AdapterId>,
1104    ) -> AdapterId {
1105        profiling::scope!("Instance::create_adapter_from_hal");
1106
1107        let fid = self.hub.adapters.prepare(input);
1108        let id = fid.assign(Arc::new(Adapter::new(hal_adapter)));
1109
1110        resource_log!("Created Adapter {:?}", id);
1111        id
1112    }
1113
1114    pub fn adapter_get_info(&self, adapter_id: AdapterId) -> wgt::AdapterInfo {
1115        let adapter = self.hub.adapters.get(adapter_id);
1116        adapter.get_info()
1117    }
1118
1119    pub fn adapter_get_texture_format_features(
1120        &self,
1121        adapter_id: AdapterId,
1122        format: wgt::TextureFormat,
1123    ) -> wgt::TextureFormatFeatures {
1124        let adapter = self.hub.adapters.get(adapter_id);
1125        adapter.get_texture_format_features(format)
1126    }
1127
1128    pub fn adapter_features(&self, adapter_id: AdapterId) -> wgt::Features {
1129        let adapter = self.hub.adapters.get(adapter_id);
1130        adapter.features()
1131    }
1132
1133    pub fn adapter_limits(&self, adapter_id: AdapterId) -> wgt::Limits {
1134        let adapter = self.hub.adapters.get(adapter_id);
1135        adapter.limits()
1136    }
1137
1138    pub fn adapter_downlevel_capabilities(
1139        &self,
1140        adapter_id: AdapterId,
1141    ) -> wgt::DownlevelCapabilities {
1142        let adapter = self.hub.adapters.get(adapter_id);
1143        adapter.downlevel_capabilities()
1144    }
1145
1146    pub fn adapter_get_presentation_timestamp(
1147        &self,
1148        adapter_id: AdapterId,
1149    ) -> wgt::PresentationTimestamp {
1150        let adapter = self.hub.adapters.get(adapter_id);
1151        adapter.get_presentation_timestamp()
1152    }
1153
1154    pub fn adapter_cooperative_matrix_properties(
1155        &self,
1156        adapter_id: AdapterId,
1157    ) -> Vec<wgt::CooperativeMatrixProperties> {
1158        let adapter = self.hub.adapters.get(adapter_id);
1159        adapter.cooperative_matrix_properties()
1160    }
1161
1162    pub fn adapter_drop(&self, adapter_id: AdapterId) {
1163        profiling::scope!("Adapter::drop");
1164        api_log!("Adapter::drop {adapter_id:?}");
1165
1166        self.hub.adapters.remove(adapter_id);
1167    }
1168}
1169
1170impl Global {
1171    pub fn adapter_request_device(
1172        &self,
1173        adapter_id: AdapterId,
1174        desc: &DeviceDescriptor,
1175        device_id_in: Option<DeviceId>,
1176        queue_id_in: Option<QueueId>,
1177    ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1178        profiling::scope!("Adapter::request_device");
1179        api_log!("Adapter::request_device");
1180
1181        let device_fid = self.hub.devices.prepare(device_id_in);
1182        let queue_fid = self.hub.queues.prepare(queue_id_in);
1183
1184        let adapter = self.hub.adapters.get(adapter_id);
1185        let (device, queue) = adapter.create_device_and_queue(desc, self.instance.flags)?;
1186
1187        let device_id = device_fid.assign(device);
1188        resource_log!("Created Device {:?}", device_id);
1189
1190        let queue_id = queue_fid.assign(queue);
1191        resource_log!("Created Queue {:?}", queue_id);
1192
1193        Ok((device_id, queue_id))
1194    }
1195
1196    /// # Safety
1197    ///
1198    /// - `hal_device` must be created from `adapter_id` or its internal handle.
1199    /// - `desc` must be a subset of `hal_device` features and limits.
1200    pub unsafe fn create_device_from_hal(
1201        &self,
1202        adapter_id: AdapterId,
1203        hal_device: hal::DynOpenDevice,
1204        desc: &DeviceDescriptor,
1205        device_id_in: Option<DeviceId>,
1206        queue_id_in: Option<QueueId>,
1207    ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1208        profiling::scope!("Global::create_device_from_hal");
1209
1210        let devices_fid = self.hub.devices.prepare(device_id_in);
1211        let queues_fid = self.hub.queues.prepare(queue_id_in);
1212
1213        let adapter = self.hub.adapters.get(adapter_id);
1214        let (device, queue) =
1215            adapter.create_device_and_queue_from_hal(hal_device, desc, self.instance.flags)?;
1216
1217        let device_id = devices_fid.assign(device);
1218        resource_log!("Created Device {:?}", device_id);
1219
1220        let queue_id = queues_fid.assign(queue);
1221        resource_log!("Created Queue {:?}", queue_id);
1222
1223        Ok((device_id, queue_id))
1224    }
1225}