wgpu_core/
instance.rs

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