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(all(vulkan, not(target_os = "netbsd")))]
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(
297        unix,
298        not(target_vendor = "apple"),
299        not(target_family = "wasm"),
300        not(target_os = "netbsd")
301    ))]
302    #[cfg_attr(not(vulkan), expect(unused_variables))]
303    pub unsafe fn create_surface_from_drm(
304        &self,
305        fd: i32,
306        plane: u32,
307        connector_id: u32,
308        width: u32,
309        height: u32,
310        refresh_rate: u32,
311    ) -> Result<Surface, CreateSurfaceError> {
312        profiling::scope!("Instance::create_surface_from_drm");
313
314        let mut errors = HashMap::default();
315        let mut surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>> =
316            HashMap::default();
317
318        #[cfg(all(vulkan, not(target_os = "netbsd")))]
319        {
320            let instance = unsafe { self.as_hal::<hal::api::Vulkan>() }
321                .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Vulkan))?;
322
323            // Safety must be upheld by the caller
324            match unsafe {
325                instance.create_surface_from_drm(
326                    fd,
327                    plane,
328                    connector_id,
329                    width,
330                    height,
331                    refresh_rate,
332                )
333            } {
334                Ok(surface) => {
335                    surface_per_backend.insert(Backend::Vulkan, Box::new(surface));
336                }
337                Err(err) => {
338                    errors.insert(Backend::Vulkan, err);
339                }
340            }
341        }
342
343        if surface_per_backend.is_empty() {
344            Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
345                errors,
346            ))
347        } else {
348            let surface = Surface {
349                presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
350                surface_per_backend,
351            };
352
353            Ok(surface)
354        }
355    }
356
357    /// # Safety
358    ///
359    /// `layer` must be a valid pointer.
360    #[cfg(metal)]
361    pub unsafe fn create_surface_metal(
362        &self,
363        layer: *mut core::ffi::c_void,
364    ) -> Result<Surface, CreateSurfaceError> {
365        profiling::scope!("Instance::create_surface_metal");
366
367        let instance = unsafe { self.as_hal::<hal::api::Metal>() }
368            .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Metal))?;
369
370        let layer = layer.cast();
371        // SAFETY: We do this cast and deref. (rather than using `metal` to get the
372        // object we want) to avoid direct coupling on the `metal` crate.
373        //
374        // To wit, this pointer…
375        //
376        // - …is properly aligned.
377        // - …is dereferenceable to a `MetalLayerRef` as an invariant of the `metal`
378        //   field.
379        // - …points to an _initialized_ `MetalLayerRef`.
380        // - …is only ever aliased via an immutable reference that lives within this
381        //   lexical scope.
382        let layer = unsafe { &*layer };
383        let raw_surface: Box<dyn hal::DynSurface> =
384            Box::new(instance.create_surface_from_layer(layer));
385
386        let surface = Surface {
387            presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
388            surface_per_backend: core::iter::once((Backend::Metal, raw_surface)).collect(),
389        };
390
391        Ok(surface)
392    }
393
394    #[cfg(dx12)]
395    fn create_surface_dx12(
396        &self,
397        create_surface_func: impl FnOnce(&hal::dx12::Instance) -> hal::dx12::Surface,
398    ) -> Result<Surface, CreateSurfaceError> {
399        let instance = unsafe { self.as_hal::<hal::api::Dx12>() }
400            .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Dx12))?;
401        let surface: Box<dyn hal::DynSurface> = Box::new(create_surface_func(instance));
402
403        let surface = Surface {
404            presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
405            surface_per_backend: core::iter::once((Backend::Dx12, surface)).collect(),
406        };
407
408        Ok(surface)
409    }
410
411    #[cfg(dx12)]
412    /// # Safety
413    ///
414    /// The visual must be valid and able to be used to make a swapchain with.
415    pub unsafe fn create_surface_from_visual(
416        &self,
417        visual: *mut core::ffi::c_void,
418    ) -> Result<Surface, CreateSurfaceError> {
419        profiling::scope!("Instance::instance_create_surface_from_visual");
420        self.create_surface_dx12(|inst| unsafe { inst.create_surface_from_visual(visual) })
421    }
422
423    #[cfg(dx12)]
424    /// # Safety
425    ///
426    /// The surface_handle must be valid and able to be used to make a swapchain with.
427    pub unsafe fn create_surface_from_surface_handle(
428        &self,
429        surface_handle: *mut core::ffi::c_void,
430    ) -> Result<Surface, CreateSurfaceError> {
431        profiling::scope!("Instance::instance_create_surface_from_surface_handle");
432        self.create_surface_dx12(|inst| unsafe {
433            inst.create_surface_from_surface_handle(surface_handle)
434        })
435    }
436
437    #[cfg(dx12)]
438    /// # Safety
439    ///
440    /// The swap_chain_panel must be valid and able to be used to make a swapchain with.
441    pub unsafe fn create_surface_from_swap_chain_panel(
442        &self,
443        swap_chain_panel: *mut core::ffi::c_void,
444    ) -> Result<Surface, CreateSurfaceError> {
445        profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel");
446        self.create_surface_dx12(|inst| unsafe {
447            inst.create_surface_from_swap_chain_panel(swap_chain_panel)
448        })
449    }
450
451    pub fn enumerate_adapters(&self, backends: Backends) -> Vec<Adapter> {
452        profiling::scope!("Instance::enumerate_adapters");
453        api_log!("Instance::enumerate_adapters");
454
455        let mut adapters = Vec::new();
456        for (_backend, instance) in self
457            .instance_per_backend
458            .iter()
459            .filter(|(backend, _)| backends.contains(Backends::from(*backend)))
460        {
461            // NOTE: We might be using `profiling` without any features. The empty backend of this
462            // macro emits no code, so unused code linting changes depending on the backend.
463            profiling::scope!("enumerating", &*alloc::format!("{_backend:?}"));
464
465            let hal_adapters = unsafe { instance.enumerate_adapters(None) };
466            for raw in hal_adapters {
467                let adapter = Adapter::new(raw);
468                api_log_debug!("Adapter {:?}", adapter.raw.info);
469                adapters.push(adapter);
470            }
471        }
472        adapters
473    }
474
475    pub fn request_adapter(
476        &self,
477        desc: &wgt::RequestAdapterOptions<&Surface>,
478        backends: Backends,
479    ) -> Result<Adapter, wgt::RequestAdapterError> {
480        profiling::scope!("Instance::request_adapter");
481        api_log!("Instance::request_adapter");
482
483        let mut adapters = Vec::new();
484        let mut incompatible_surface_backends = Backends::empty();
485        let mut no_fallback_backends = Backends::empty();
486        let mut no_adapter_backends = Backends::empty();
487
488        for &(backend, ref instance) in self
489            .instance_per_backend
490            .iter()
491            .filter(|&&(backend, _)| backends.contains(Backends::from(backend)))
492        {
493            let compatible_hal_surface = desc
494                .compatible_surface
495                .and_then(|surface| surface.raw(backend));
496
497            let mut backend_adapters =
498                unsafe { instance.enumerate_adapters(compatible_hal_surface) };
499            if backend_adapters.is_empty() {
500                log::debug!("enabled backend `{backend:?}` has no adapters");
501                no_adapter_backends |= Backends::from(backend);
502                // by continuing, we avoid setting the further error bits below
503                continue;
504            }
505
506            if desc.force_fallback_adapter {
507                log::debug!("Filtering `{backend:?}` for `force_fallback_adapter`");
508                backend_adapters.retain(|exposed| {
509                    let keep = exposed.info.device_type == wgt::DeviceType::Cpu;
510                    if !keep {
511                        log::debug!("* Eliminating adapter `{}`", exposed.info.name);
512                    }
513                    keep
514                });
515                if backend_adapters.is_empty() {
516                    log::debug!("* Backend `{backend:?}` has no fallback adapters");
517                    no_fallback_backends |= Backends::from(backend);
518                    continue;
519                }
520            }
521
522            if let Some(surface) = desc.compatible_surface {
523                backend_adapters.retain(|exposed| {
524                    let capabilities = surface.get_capabilities_with_raw(exposed);
525                    if let Err(err) = capabilities {
526                        log::debug!(
527                            "Adapter {:?} not compatible with surface: {}",
528                            exposed.info,
529                            err
530                        );
531                        incompatible_surface_backends |= Backends::from(backend);
532                        false
533                    } else {
534                        true
535                    }
536                });
537                if backend_adapters.is_empty() {
538                    incompatible_surface_backends |= Backends::from(backend);
539                    continue;
540                }
541            }
542            adapters.extend(backend_adapters);
543        }
544
545        match desc.power_preference {
546            PowerPreference::LowPower => {
547                sort(&mut adapters, true);
548            }
549            PowerPreference::HighPerformance => {
550                sort(&mut adapters, false);
551            }
552            PowerPreference::None => {}
553        };
554
555        fn sort(adapters: &mut [hal::DynExposedAdapter], prefer_integrated_gpu: bool) {
556            adapters
557                .sort_by_key(|adapter| get_order(adapter.info.device_type, prefer_integrated_gpu));
558        }
559
560        fn get_order(device_type: wgt::DeviceType, prefer_integrated_gpu: bool) -> u8 {
561            // Since devices of type "Other" might really be "Unknown" and come
562            // from APIs like OpenGL that don't specify device type, Prefer more
563            // Specific types over Other.
564            //
565            // This means that backends which do provide accurate device types
566            // will be preferred if their device type indicates an actual
567            // hardware GPU (integrated or discrete).
568            match device_type {
569                wgt::DeviceType::DiscreteGpu if prefer_integrated_gpu => 2,
570                wgt::DeviceType::IntegratedGpu if prefer_integrated_gpu => 1,
571                wgt::DeviceType::DiscreteGpu => 1,
572                wgt::DeviceType::IntegratedGpu => 2,
573                wgt::DeviceType::Other => 3,
574                wgt::DeviceType::VirtualGpu => 4,
575                wgt::DeviceType::Cpu => 5,
576            }
577        }
578
579        // `request_adapter` can be a bit of a black box.
580        // Shine some light on its decision in debug log.
581        if adapters.is_empty() {
582            log::debug!("Request adapter didn't find compatible adapters.");
583        } else {
584            log::debug!(
585                "Found {} compatible adapters. Sorted by preference:",
586                adapters.len()
587            );
588            for adapter in &adapters {
589                log::debug!("* {:?}", adapter.info);
590            }
591        }
592
593        if let Some(adapter) = adapters.into_iter().next() {
594            api_log_debug!("Request adapter result {:?}", adapter.info);
595            let adapter = Adapter::new(adapter);
596            Ok(adapter)
597        } else {
598            Err(wgt::RequestAdapterError::NotFound {
599                supported_backends: self.supported_backends,
600                requested_backends: self.requested_backends,
601                active_backends: self.active_backends(),
602                no_fallback_backends,
603                no_adapter_backends,
604                incompatible_surface_backends,
605            })
606        }
607    }
608
609    fn active_backends(&self) -> Backends {
610        self.instance_per_backend
611            .iter()
612            .map(|&(backend, _)| Backends::from(backend))
613            .collect()
614    }
615}
616
617pub struct Surface {
618    pub(crate) presentation: Mutex<Option<Presentation>>,
619    pub surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>>,
620}
621
622impl ResourceType for Surface {
623    const TYPE: &'static str = "Surface";
624}
625impl crate::storage::StorageItem for Surface {
626    type Marker = markers::Surface;
627}
628
629impl Surface {
630    pub fn get_capabilities(
631        &self,
632        adapter: &Adapter,
633    ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
634        self.get_capabilities_with_raw(&adapter.raw)
635    }
636
637    pub fn get_capabilities_with_raw(
638        &self,
639        adapter: &hal::DynExposedAdapter,
640    ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
641        let backend = adapter.backend();
642        let suf = self
643            .raw(backend)
644            .ok_or(GetSurfaceSupportError::NotSupportedByBackend(backend))?;
645        profiling::scope!("surface_capabilities");
646        let caps = unsafe { adapter.adapter.surface_capabilities(suf) }
647            .ok_or(GetSurfaceSupportError::FailedToRetrieveSurfaceCapabilitiesForAdapter)?;
648        Ok(caps)
649    }
650
651    pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynSurface> {
652        self.surface_per_backend
653            .get(&backend)
654            .map(|surface| surface.as_ref())
655    }
656}
657
658impl Drop for Surface {
659    fn drop(&mut self) {
660        if let Some(present) = self.presentation.lock().take() {
661            for (&backend, surface) in &self.surface_per_backend {
662                if backend == present.device.backend() {
663                    unsafe { surface.unconfigure(present.device.raw()) };
664                }
665            }
666        }
667    }
668}
669
670pub struct Adapter {
671    pub(crate) raw: hal::DynExposedAdapter,
672}
673
674impl Adapter {
675    pub fn new(mut raw: hal::DynExposedAdapter) -> Self {
676        // WebGPU requires this offset alignment as lower bound on all adapters.
677        const MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND: u32 = 32;
678
679        let limits = &mut raw.capabilities.limits;
680
681        limits.min_uniform_buffer_offset_alignment = limits
682            .min_uniform_buffer_offset_alignment
683            .max(MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND);
684        limits.min_storage_buffer_offset_alignment = limits
685            .min_storage_buffer_offset_alignment
686            .max(MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND);
687
688        Self { raw }
689    }
690
691    /// Returns the backend this adapter is using.
692    pub fn backend(&self) -> Backend {
693        self.raw.backend()
694    }
695
696    pub fn is_surface_supported(&self, surface: &Surface) -> bool {
697        // If get_capabilities returns Err, then the API does not advertise support for the surface.
698        //
699        // This could occur if the user is running their app on Wayland but Vulkan does not support
700        // VK_KHR_wayland_surface.
701        surface.get_capabilities(self).is_ok()
702    }
703
704    pub fn get_info(&self) -> wgt::AdapterInfo {
705        self.raw.info.clone()
706    }
707
708    pub fn features(&self) -> wgt::Features {
709        self.raw.features
710    }
711
712    pub fn limits(&self) -> wgt::Limits {
713        self.raw.capabilities.limits.clone()
714    }
715
716    pub fn downlevel_capabilities(&self) -> wgt::DownlevelCapabilities {
717        self.raw.capabilities.downlevel.clone()
718    }
719
720    pub fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
721        unsafe { self.raw.adapter.get_presentation_timestamp() }
722    }
723
724    pub fn cooperative_matrix_properties(&self) -> Vec<wgt::CooperativeMatrixProperties> {
725        self.raw.capabilities.cooperative_matrix_properties.clone()
726    }
727
728    pub fn get_texture_format_features(
729        &self,
730        format: wgt::TextureFormat,
731    ) -> wgt::TextureFormatFeatures {
732        use hal::TextureFormatCapabilities as Tfc;
733
734        let caps = unsafe { self.raw.adapter.texture_format_capabilities(format) };
735        let mut allowed_usages = wgt::TextureUsages::empty();
736
737        allowed_usages.set(wgt::TextureUsages::COPY_SRC, caps.contains(Tfc::COPY_SRC));
738        allowed_usages.set(wgt::TextureUsages::COPY_DST, caps.contains(Tfc::COPY_DST));
739        allowed_usages.set(
740            wgt::TextureUsages::TEXTURE_BINDING,
741            caps.contains(Tfc::SAMPLED),
742        );
743        allowed_usages.set(
744            wgt::TextureUsages::STORAGE_BINDING,
745            caps.intersects(
746                Tfc::STORAGE_WRITE_ONLY
747                    | Tfc::STORAGE_READ_ONLY
748                    | Tfc::STORAGE_READ_WRITE
749                    | Tfc::STORAGE_ATOMIC,
750            ),
751        );
752        allowed_usages.set(
753            wgt::TextureUsages::RENDER_ATTACHMENT | wgt::TextureUsages::TRANSIENT,
754            caps.intersects(Tfc::COLOR_ATTACHMENT | Tfc::DEPTH_STENCIL_ATTACHMENT),
755        );
756        allowed_usages.set(
757            wgt::TextureUsages::STORAGE_ATOMIC,
758            caps.contains(Tfc::STORAGE_ATOMIC),
759        );
760
761        let mut flags = wgt::TextureFormatFeatureFlags::empty();
762        flags.set(
763            wgt::TextureFormatFeatureFlags::STORAGE_READ_ONLY,
764            caps.contains(Tfc::STORAGE_READ_ONLY),
765        );
766        flags.set(
767            wgt::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY,
768            caps.contains(Tfc::STORAGE_WRITE_ONLY),
769        );
770        flags.set(
771            wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE,
772            caps.contains(Tfc::STORAGE_READ_WRITE),
773        );
774
775        flags.set(
776            wgt::TextureFormatFeatureFlags::STORAGE_ATOMIC,
777            caps.contains(Tfc::STORAGE_ATOMIC),
778        );
779
780        flags.set(
781            wgt::TextureFormatFeatureFlags::FILTERABLE,
782            caps.contains(Tfc::SAMPLED_LINEAR),
783        );
784
785        flags.set(
786            wgt::TextureFormatFeatureFlags::BLENDABLE,
787            caps.contains(Tfc::COLOR_ATTACHMENT_BLEND),
788        );
789
790        flags.set(
791            wgt::TextureFormatFeatureFlags::MULTISAMPLE_X2,
792            caps.contains(Tfc::MULTISAMPLE_X2),
793        );
794        flags.set(
795            wgt::TextureFormatFeatureFlags::MULTISAMPLE_X4,
796            caps.contains(Tfc::MULTISAMPLE_X4),
797        );
798        flags.set(
799            wgt::TextureFormatFeatureFlags::MULTISAMPLE_X8,
800            caps.contains(Tfc::MULTISAMPLE_X8),
801        );
802        flags.set(
803            wgt::TextureFormatFeatureFlags::MULTISAMPLE_X16,
804            caps.contains(Tfc::MULTISAMPLE_X16),
805        );
806
807        flags.set(
808            wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE,
809            caps.contains(Tfc::MULTISAMPLE_RESOLVE),
810        );
811
812        wgt::TextureFormatFeatures {
813            allowed_usages,
814            flags,
815        }
816    }
817
818    fn create_device_and_queue_from_hal(
819        self: &Arc<Self>,
820        hal_device: hal::DynOpenDevice,
821        desc: &DeviceDescriptor,
822        instance_flags: wgt::InstanceFlags,
823    ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
824        api_log!("Adapter::create_device");
825
826        let device = Device::new(hal_device.device, self, desc, instance_flags)?;
827        let device = Arc::new(device);
828
829        let queue = Queue::new(device.clone(), hal_device.queue, instance_flags)?;
830        let queue = Arc::new(queue);
831
832        device.set_queue(&queue);
833        device.late_init_resources_with_queue()?;
834
835        Ok((device, queue))
836    }
837
838    pub fn create_device_and_queue(
839        self: &Arc<Self>,
840        desc: &DeviceDescriptor,
841        instance_flags: wgt::InstanceFlags,
842    ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
843        // Verify all features were exposed by the adapter
844        if !self.raw.features.contains(desc.required_features) {
845            return Err(RequestDeviceError::UnsupportedFeature(
846                desc.required_features - self.raw.features,
847            ));
848        }
849
850        // Check if experimental features are permitted to be enabled.
851        if desc
852            .required_features
853            .intersects(wgt::Features::all_experimental_mask())
854            && !desc.experimental_features.is_enabled()
855        {
856            return Err(RequestDeviceError::ExperimentalFeaturesNotEnabled(
857                desc.required_features
858                    .intersection(wgt::Features::all_experimental_mask()),
859            ));
860        }
861
862        let caps = &self.raw.capabilities;
863        if Backends::PRIMARY.contains(Backends::from(self.backend()))
864            && !caps.downlevel.is_webgpu_compliant()
865        {
866            let missing_flags = wgt::DownlevelFlags::compliant() - caps.downlevel.flags;
867            log::warn!("Missing downlevel flags: {missing_flags:?}\n{DOWNLEVEL_WARNING_MESSAGE}");
868            log::warn!("{:#?}", caps.downlevel);
869        }
870
871        // Verify feature preconditions
872        if desc
873            .required_features
874            .contains(wgt::Features::MAPPABLE_PRIMARY_BUFFERS)
875            && self.raw.info.device_type == wgt::DeviceType::DiscreteGpu
876        {
877            log::warn!(
878                "Feature MAPPABLE_PRIMARY_BUFFERS enabled on a discrete gpu. \
879                        This is a massive performance footgun and likely not what you wanted"
880            );
881        }
882
883        if let Some(failed) = check_limits(&desc.required_limits, &caps.limits).pop() {
884            return Err(RequestDeviceError::LimitsExceeded(failed));
885        }
886
887        let open = unsafe {
888            self.raw.adapter.open(
889                desc.required_features,
890                &desc.required_limits,
891                &desc.memory_hints,
892            )
893        }
894        .map_err(DeviceError::from_hal)?;
895
896        self.create_device_and_queue_from_hal(open, desc, instance_flags)
897    }
898}
899
900crate::impl_resource_type!(Adapter);
901crate::impl_storage_item!(Adapter);
902
903#[derive(Clone, Debug, Error)]
904#[non_exhaustive]
905pub enum GetSurfaceSupportError {
906    #[error("Surface is not supported for the specified backend {0}")]
907    NotSupportedByBackend(Backend),
908    #[error("Failed to retrieve surface capabilities for the specified adapter.")]
909    FailedToRetrieveSurfaceCapabilitiesForAdapter,
910}
911
912#[derive(Clone, Debug, Error)]
913/// Error when requesting a device from the adapter
914#[non_exhaustive]
915pub enum RequestDeviceError {
916    #[error(transparent)]
917    Device(#[from] DeviceError),
918    #[error(transparent)]
919    LimitsExceeded(#[from] FailedLimit),
920    #[error("Failed to initialize Timestamp Normalizer")]
921    TimestampNormalizerInitFailed(#[from] TimestampNormalizerInitError),
922    #[error("Unsupported features were requested: {0}")]
923    UnsupportedFeature(wgt::Features),
924    #[error(
925        "Some experimental features, {0}, were requested, but experimental features are not enabled"
926    )]
927    ExperimentalFeaturesNotEnabled(wgt::Features),
928}
929
930#[derive(Clone, Debug, Error)]
931#[non_exhaustive]
932pub enum CreateSurfaceError {
933    #[error("The backend {0} was not enabled on the instance.")]
934    BackendNotEnabled(Backend),
935    #[error("Failed to create surface for any enabled backend: {0:?}")]
936    FailedToCreateSurfaceForAnyBackend(HashMap<Backend, hal::InstanceError>),
937    #[error("The display handle used to create this Instance does not match the one used to create a surface on it")]
938    MismatchingDisplayHandle,
939}
940
941impl Global {
942    /// Creates a new surface targeting the given display/window handles.
943    ///
944    /// Internally attempts to create hal surfaces for all enabled backends.
945    ///
946    /// Fails only if creation for surfaces for all enabled backends fails in which case
947    /// the error for each enabled backend is listed.
948    /// Vice versa, if creation for any backend succeeds, success is returned.
949    /// Surface creation errors are logged to the debug log in any case.
950    ///
951    /// id_in:
952    /// - If `Some`, the id to assign to the surface. A new one will be generated otherwise.
953    ///
954    /// # Safety
955    ///
956    /// - `display_handle` must be a valid object to create a surface upon.
957    /// - `window_handle` must remain valid as long as the returned
958    ///   [`SurfaceId`] is being used.
959    pub unsafe fn instance_create_surface(
960        &self,
961        display_handle: raw_window_handle::RawDisplayHandle,
962        window_handle: raw_window_handle::RawWindowHandle,
963        id_in: Option<SurfaceId>,
964    ) -> Result<SurfaceId, CreateSurfaceError> {
965        let surface = unsafe { self.instance.create_surface(display_handle, window_handle) }?;
966        let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
967        Ok(id)
968    }
969
970    /// Creates a new surface from the given drm configuration.
971    ///
972    /// # Safety
973    ///
974    /// - All parameters must point to valid DRM values.
975    ///
976    /// # Platform Support
977    ///
978    /// This function is only available on non-apple Unix-like platforms (Linux, FreeBSD) and
979    /// currently only works with the Vulkan backend.
980    #[cfg(all(
981        unix,
982        not(target_vendor = "apple"),
983        not(target_family = "wasm"),
984        not(target_os = "netbsd")
985    ))]
986    pub unsafe fn instance_create_surface_from_drm(
987        &self,
988        fd: i32,
989        plane: u32,
990        connector_id: u32,
991        width: u32,
992        height: u32,
993        refresh_rate: u32,
994        id_in: Option<SurfaceId>,
995    ) -> Result<SurfaceId, CreateSurfaceError> {
996        let surface = unsafe {
997            self.instance.create_surface_from_drm(
998                fd,
999                plane,
1000                connector_id,
1001                width,
1002                height,
1003                refresh_rate,
1004            )
1005        }?;
1006        let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1007
1008        Ok(id)
1009    }
1010
1011    /// # Safety
1012    ///
1013    /// `layer` must be a valid pointer.
1014    #[cfg(metal)]
1015    pub unsafe fn instance_create_surface_metal(
1016        &self,
1017        layer: *mut core::ffi::c_void,
1018        id_in: Option<SurfaceId>,
1019    ) -> Result<SurfaceId, CreateSurfaceError> {
1020        let surface = unsafe { self.instance.create_surface_metal(layer) }?;
1021        let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1022        Ok(id)
1023    }
1024
1025    #[cfg(dx12)]
1026    /// # Safety
1027    ///
1028    /// The visual must be valid and able to be used to make a swapchain with.
1029    pub unsafe fn instance_create_surface_from_visual(
1030        &self,
1031        visual: *mut core::ffi::c_void,
1032        id_in: Option<SurfaceId>,
1033    ) -> Result<SurfaceId, CreateSurfaceError> {
1034        let surface = unsafe { self.instance.create_surface_from_visual(visual) }?;
1035        let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1036        Ok(id)
1037    }
1038
1039    #[cfg(dx12)]
1040    /// # Safety
1041    ///
1042    /// The surface_handle must be valid and able to be used to make a swapchain with.
1043    pub unsafe fn instance_create_surface_from_surface_handle(
1044        &self,
1045        surface_handle: *mut core::ffi::c_void,
1046        id_in: Option<SurfaceId>,
1047    ) -> Result<SurfaceId, CreateSurfaceError> {
1048        let surface = unsafe {
1049            self.instance
1050                .create_surface_from_surface_handle(surface_handle)
1051        }?;
1052        let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1053        Ok(id)
1054    }
1055
1056    #[cfg(dx12)]
1057    /// # Safety
1058    ///
1059    /// The swap_chain_panel must be valid and able to be used to make a swapchain with.
1060    pub unsafe fn instance_create_surface_from_swap_chain_panel(
1061        &self,
1062        swap_chain_panel: *mut core::ffi::c_void,
1063        id_in: Option<SurfaceId>,
1064    ) -> Result<SurfaceId, CreateSurfaceError> {
1065        let surface = unsafe {
1066            self.instance
1067                .create_surface_from_swap_chain_panel(swap_chain_panel)
1068        }?;
1069        let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1070        Ok(id)
1071    }
1072
1073    pub fn surface_drop(&self, id: SurfaceId) {
1074        profiling::scope!("Surface::drop");
1075
1076        api_log!("Surface::drop {id:?}");
1077
1078        self.surfaces.remove(id);
1079    }
1080
1081    pub fn enumerate_adapters(&self, backends: Backends) -> Vec<AdapterId> {
1082        let adapters = self.instance.enumerate_adapters(backends);
1083        adapters
1084            .into_iter()
1085            .map(|adapter| self.hub.adapters.prepare(None).assign(Arc::new(adapter)))
1086            .collect()
1087    }
1088
1089    pub fn request_adapter(
1090        &self,
1091        desc: &RequestAdapterOptions,
1092        backends: Backends,
1093        id_in: Option<AdapterId>,
1094    ) -> Result<AdapterId, wgt::RequestAdapterError> {
1095        let compatible_surface = desc.compatible_surface.map(|id| self.surfaces.get(id));
1096        let desc = wgt::RequestAdapterOptions {
1097            power_preference: desc.power_preference,
1098            force_fallback_adapter: desc.force_fallback_adapter,
1099            compatible_surface: compatible_surface.as_deref(),
1100        };
1101        let adapter = self.instance.request_adapter(&desc, backends)?;
1102        let id = self.hub.adapters.prepare(id_in).assign(Arc::new(adapter));
1103        Ok(id)
1104    }
1105
1106    /// # Safety
1107    ///
1108    /// `hal_adapter` must be created from this global internal instance handle.
1109    pub unsafe fn create_adapter_from_hal(
1110        &self,
1111        hal_adapter: hal::DynExposedAdapter,
1112        input: Option<AdapterId>,
1113    ) -> AdapterId {
1114        profiling::scope!("Instance::create_adapter_from_hal");
1115
1116        let fid = self.hub.adapters.prepare(input);
1117        let id = fid.assign(Arc::new(Adapter::new(hal_adapter)));
1118
1119        resource_log!("Created Adapter {:?}", id);
1120        id
1121    }
1122
1123    pub fn adapter_get_info(&self, adapter_id: AdapterId) -> wgt::AdapterInfo {
1124        let adapter = self.hub.adapters.get(adapter_id);
1125        adapter.get_info()
1126    }
1127
1128    pub fn adapter_get_texture_format_features(
1129        &self,
1130        adapter_id: AdapterId,
1131        format: wgt::TextureFormat,
1132    ) -> wgt::TextureFormatFeatures {
1133        let adapter = self.hub.adapters.get(adapter_id);
1134        adapter.get_texture_format_features(format)
1135    }
1136
1137    pub fn adapter_features(&self, adapter_id: AdapterId) -> wgt::Features {
1138        let adapter = self.hub.adapters.get(adapter_id);
1139        adapter.features()
1140    }
1141
1142    pub fn adapter_limits(&self, adapter_id: AdapterId) -> wgt::Limits {
1143        let adapter = self.hub.adapters.get(adapter_id);
1144        adapter.limits()
1145    }
1146
1147    pub fn adapter_downlevel_capabilities(
1148        &self,
1149        adapter_id: AdapterId,
1150    ) -> wgt::DownlevelCapabilities {
1151        let adapter = self.hub.adapters.get(adapter_id);
1152        adapter.downlevel_capabilities()
1153    }
1154
1155    pub fn adapter_get_presentation_timestamp(
1156        &self,
1157        adapter_id: AdapterId,
1158    ) -> wgt::PresentationTimestamp {
1159        let adapter = self.hub.adapters.get(adapter_id);
1160        adapter.get_presentation_timestamp()
1161    }
1162
1163    pub fn adapter_cooperative_matrix_properties(
1164        &self,
1165        adapter_id: AdapterId,
1166    ) -> Vec<wgt::CooperativeMatrixProperties> {
1167        let adapter = self.hub.adapters.get(adapter_id);
1168        adapter.cooperative_matrix_properties()
1169    }
1170
1171    pub fn adapter_drop(&self, adapter_id: AdapterId) {
1172        profiling::scope!("Adapter::drop");
1173        api_log!("Adapter::drop {adapter_id:?}");
1174
1175        self.hub.adapters.remove(adapter_id);
1176    }
1177}
1178
1179impl Global {
1180    pub fn adapter_request_device(
1181        &self,
1182        adapter_id: AdapterId,
1183        desc: &DeviceDescriptor,
1184        device_id_in: Option<DeviceId>,
1185        queue_id_in: Option<QueueId>,
1186    ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1187        profiling::scope!("Adapter::request_device");
1188        api_log!("Adapter::request_device");
1189
1190        let device_fid = self.hub.devices.prepare(device_id_in);
1191        let queue_fid = self.hub.queues.prepare(queue_id_in);
1192
1193        let adapter = self.hub.adapters.get(adapter_id);
1194        let (device, queue) = adapter.create_device_and_queue(desc, self.instance.flags)?;
1195
1196        let device_id = device_fid.assign(device);
1197        resource_log!("Created Device {:?}", device_id);
1198
1199        let queue_id = queue_fid.assign(queue);
1200        resource_log!("Created Queue {:?}", queue_id);
1201
1202        Ok((device_id, queue_id))
1203    }
1204
1205    /// # Safety
1206    ///
1207    /// - `hal_device` must be created from `adapter_id` or its internal handle.
1208    /// - `desc` must be a subset of `hal_device` features and limits.
1209    pub unsafe fn create_device_from_hal(
1210        &self,
1211        adapter_id: AdapterId,
1212        hal_device: hal::DynOpenDevice,
1213        desc: &DeviceDescriptor,
1214        device_id_in: Option<DeviceId>,
1215        queue_id_in: Option<QueueId>,
1216    ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1217        profiling::scope!("Global::create_device_from_hal");
1218
1219        let devices_fid = self.hub.devices.prepare(device_id_in);
1220        let queues_fid = self.hub.queues.prepare(queue_id_in);
1221
1222        let adapter = self.hub.adapters.get(adapter_id);
1223        let (device, queue) =
1224            adapter.create_device_and_queue_from_hal(hal_device, desc, self.instance.flags)?;
1225
1226        let device_id = devices_fid.assign(device);
1227        resource_log!("Created Device {:?}", device_id);
1228
1229        let queue_id = queues_fid.assign(queue);
1230        resource_log!("Created Queue {:?}", queue_id);
1231
1232        Ok((device_id, queue_id))
1233    }
1234}