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