1use alloc::{borrow::ToOwned as _, boxed::Box, string::String, sync::Arc, vec, vec::Vec};
2
3use hashbrown::HashMap;
4use thiserror::Error;
5
6use crate::{
7 api_log, api_log_debug,
8 device::{queue::Queue, resource::Device, DeviceDescriptor, DeviceError},
9 global::Global,
10 id::{markers, AdapterId, DeviceId, QueueId, SurfaceId},
11 limits::{self, check_limits, FailedLimit},
12 lock::{rank, Mutex},
13 present::Presentation,
14 resource::ResourceType,
15 resource_log,
16 timestamp_normalization::TimestampNormalizerInitError,
17 DOWNLEVEL_WARNING_MESSAGE,
18};
19
20use wgt::{Backend, Backends, PowerPreference};
21
22pub type RequestAdapterOptions = wgt::RequestAdapterOptions<SurfaceId>;
23
24#[test]
25fn downlevel_default_limits_less_than_default_limits() {
26 let res = check_limits(&wgt::Limits::downlevel_defaults(), &wgt::Limits::default());
27 assert!(
28 res.is_empty(),
29 "Downlevel limits are greater than default limits",
30 )
31}
32
33#[derive(Default)]
34pub struct Instance {
35 _name: String,
36
37 instance_per_backend: Vec<(Backend, Box<dyn hal::DynInstance>)>,
41
42 requested_backends: Backends,
44
45 supported_backends: Backends,
53
54 pub flags: wgt::InstanceFlags,
55
56 display: Option<Box<dyn wgt::WgpuHasDisplayHandle>>,
62}
63
64impl Instance {
65 pub fn new(
66 name: &str,
67 mut instance_desc: wgt::InstanceDescriptor,
68 telemetry: Option<hal::Telemetry>,
69 ) -> Self {
70 let mut this = Self {
71 _name: name.to_owned(),
72 instance_per_backend: Vec::new(),
73 requested_backends: instance_desc.backends,
74 supported_backends: Backends::empty(),
75 flags: instance_desc.flags,
76 display: instance_desc.display.take(),
80 };
81
82 #[cfg(all(vulkan, not(target_os = "netbsd")))]
83 this.try_add_hal(hal::api::Vulkan, &instance_desc, telemetry);
84 #[cfg(metal)]
85 this.try_add_hal(hal::api::Metal, &instance_desc, telemetry);
86 #[cfg(dx12)]
87 this.try_add_hal(hal::api::Dx12, &instance_desc, telemetry);
88 #[cfg(gles)]
89 this.try_add_hal(hal::api::Gles, &instance_desc, telemetry);
90 #[cfg(feature = "noop")]
91 this.try_add_hal(hal::api::Noop, &instance_desc, telemetry);
92
93 this
94 }
95
96 fn try_add_hal<A: hal::Api>(
98 &mut self,
99 _: A,
100 instance_desc: &wgt::InstanceDescriptor,
101 telemetry: Option<hal::Telemetry>,
102 ) {
103 self.supported_backends |= A::VARIANT.into();
106
107 if !instance_desc.backends.contains(A::VARIANT.into()) {
108 log::trace!("Instance::new: backend {:?} not requested", A::VARIANT);
109 return;
110 }
111
112 assert!(instance_desc.display.is_none());
114
115 let hal_desc = hal::InstanceDescriptor {
116 name: "wgpu",
117 flags: self.flags,
118 memory_budget_thresholds: instance_desc.memory_budget_thresholds,
119 backend_options: instance_desc.backend_options.clone(),
120 telemetry,
121 display: self.display.as_ref().map(|hdh| {
124 hdh.display_handle()
125 .expect("Implementation did not provide a DisplayHandle")
126 }),
127 };
128
129 use hal::Instance as _;
130 match unsafe { A::Instance::init(&hal_desc) } {
132 Ok(instance) => {
133 log::debug!("Instance::new: created {:?} backend", A::VARIANT);
134 self.instance_per_backend
135 .push((A::VARIANT, Box::new(instance)));
136 }
137 Err(err) => {
138 log::debug!(
139 "Instance::new: failed to create {:?} backend: {:?}",
140 A::VARIANT,
141 err
142 );
143 }
144 }
145 }
146
147 pub(crate) fn from_hal_instance<A: hal::Api>(
148 name: String,
149 hal_instance: <A as hal::Api>::Instance,
150 ) -> Self {
151 Self {
152 _name: name,
153 instance_per_backend: vec![(A::VARIANT, Box::new(hal_instance))],
154 requested_backends: A::VARIANT.into(),
155 supported_backends: A::VARIANT.into(),
156 flags: wgt::InstanceFlags::default(),
157 display: None, }
159 }
160
161 pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynInstance> {
162 self.instance_per_backend
163 .iter()
164 .find_map(|(instance_backend, instance)| {
165 (*instance_backend == backend).then(|| instance.as_ref())
166 })
167 }
168
169 pub unsafe fn as_hal<A: hal::Api>(&self) -> Option<&A::Instance> {
173 self.raw(A::VARIANT).map(|instance| {
174 instance
175 .as_any()
176 .downcast_ref()
177 .expect("Stored instance is not of the correct type")
179 })
180 }
181
182 pub unsafe fn create_surface(
198 &self,
199 display_handle: Option<raw_window_handle::RawDisplayHandle>,
200 window_handle: raw_window_handle::RawWindowHandle,
201 ) -> Result<Surface, CreateSurfaceError> {
202 profiling::scope!("Instance::create_surface");
203
204 let instance_display_handle = self.display.as_ref().map(|d| {
205 d.display_handle()
206 .expect("Implementation did not provide a DisplayHandle")
207 .as_raw()
208 });
209 let display_handle = match (instance_display_handle, display_handle) {
210 (Some(a), Some(b)) => {
211 if a != b {
212 return Err(CreateSurfaceError::MismatchingDisplayHandle);
213 }
214 a
215 }
216 (Some(hnd), None) => hnd,
217 (None, Some(hnd)) => hnd,
218 (None, None) => return Err(CreateSurfaceError::MissingDisplayHandle),
219 };
220
221 let mut errors = HashMap::default();
222 let mut surface_per_backend = HashMap::default();
223
224 for (backend, instance) in &self.instance_per_backend {
225 match unsafe {
226 instance
227 .as_ref()
228 .create_surface(display_handle, window_handle)
229 } {
230 Ok(raw) => {
231 surface_per_backend.insert(*backend, raw);
232 }
233 Err(err) => {
234 log::debug!(
235 "Instance::create_surface: failed to create surface for {backend:?}: {err:?}"
236 );
237 errors.insert(*backend, err);
238 }
239 }
240 }
241
242 if surface_per_backend.is_empty() {
243 Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
244 errors,
245 ))
246 } else {
247 let surface = Surface {
248 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
249 surface_per_backend,
250 };
251
252 Ok(surface)
253 }
254 }
255
256 #[cfg(all(
267 unix,
268 not(target_vendor = "apple"),
269 not(target_family = "wasm"),
270 not(target_os = "netbsd")
271 ))]
272 #[cfg_attr(not(vulkan), expect(unused_variables))]
273 pub unsafe fn create_surface_from_drm(
274 &self,
275 fd: i32,
276 plane: u32,
277 connector_id: u32,
278 width: u32,
279 height: u32,
280 refresh_rate: u32,
281 ) -> Result<Surface, CreateSurfaceError> {
282 profiling::scope!("Instance::create_surface_from_drm");
283
284 let mut errors = HashMap::default();
285 let mut surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>> =
286 HashMap::default();
287
288 #[cfg(all(vulkan, not(target_os = "netbsd")))]
289 {
290 let instance = unsafe { self.as_hal::<hal::api::Vulkan>() }
291 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Vulkan))?;
292
293 match unsafe {
295 instance.create_surface_from_drm(
296 fd,
297 plane,
298 connector_id,
299 width,
300 height,
301 refresh_rate,
302 )
303 } {
304 Ok(surface) => {
305 surface_per_backend.insert(Backend::Vulkan, Box::new(surface));
306 }
307 Err(err) => {
308 errors.insert(Backend::Vulkan, err);
309 }
310 }
311 }
312
313 if surface_per_backend.is_empty() {
314 Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
315 errors,
316 ))
317 } else {
318 let surface = Surface {
319 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
320 surface_per_backend,
321 };
322
323 Ok(surface)
324 }
325 }
326
327 #[cfg(metal)]
331 pub unsafe fn create_surface_metal(
332 &self,
333 layer: *mut core::ffi::c_void,
334 ) -> Result<Surface, CreateSurfaceError> {
335 profiling::scope!("Instance::create_surface_metal");
336
337 let instance = unsafe { self.as_hal::<hal::api::Metal>() }
338 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Metal))?;
339
340 let layer = layer.cast();
341 let layer = unsafe { &*layer };
353 let raw_surface: Box<dyn hal::DynSurface> =
354 Box::new(instance.create_surface_from_layer(layer));
355
356 let surface = Surface {
357 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
358 surface_per_backend: core::iter::once((Backend::Metal, raw_surface)).collect(),
359 };
360
361 Ok(surface)
362 }
363
364 #[cfg(dx12)]
365 fn create_surface_dx12(
366 &self,
367 create_surface_func: impl FnOnce(&hal::dx12::Instance) -> hal::dx12::Surface,
368 ) -> Result<Surface, CreateSurfaceError> {
369 let instance = unsafe { self.as_hal::<hal::api::Dx12>() }
370 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Dx12))?;
371 let surface: Box<dyn hal::DynSurface> = Box::new(create_surface_func(instance));
372
373 let surface = Surface {
374 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
375 surface_per_backend: core::iter::once((Backend::Dx12, surface)).collect(),
376 };
377
378 Ok(surface)
379 }
380
381 #[cfg(dx12)]
382 pub unsafe fn create_surface_from_visual(
386 &self,
387 visual: *mut core::ffi::c_void,
388 ) -> Result<Surface, CreateSurfaceError> {
389 profiling::scope!("Instance::instance_create_surface_from_visual");
390 self.create_surface_dx12(|inst| unsafe { inst.create_surface_from_visual(visual) })
391 }
392
393 #[cfg(dx12)]
394 pub unsafe fn create_surface_from_surface_handle(
398 &self,
399 surface_handle: *mut core::ffi::c_void,
400 ) -> Result<Surface, CreateSurfaceError> {
401 profiling::scope!("Instance::instance_create_surface_from_surface_handle");
402 self.create_surface_dx12(|inst| unsafe {
403 inst.create_surface_from_surface_handle(surface_handle)
404 })
405 }
406
407 #[cfg(dx12)]
408 pub unsafe fn create_surface_from_swap_chain_panel(
412 &self,
413 swap_chain_panel: *mut core::ffi::c_void,
414 ) -> Result<Surface, CreateSurfaceError> {
415 profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel");
416 self.create_surface_dx12(|inst| unsafe {
417 inst.create_surface_from_swap_chain_panel(swap_chain_panel)
418 })
419 }
420
421 pub fn enumerate_adapters(
422 &self,
423 backends: Backends,
424 apply_limit_buckets: bool,
425 ) -> Vec<Adapter> {
426 profiling::scope!("Instance::enumerate_adapters");
427 api_log!("Instance::enumerate_adapters");
428
429 let mut adapters = Vec::new();
430 for (_backend, instance) in self
431 .instance_per_backend
432 .iter()
433 .filter(|(backend, _)| backends.contains(Backends::from(*backend)))
434 {
435 profiling::scope!("enumerating", &*alloc::format!("{_backend:?}"));
438
439 let hal_adapters = unsafe { instance.enumerate_adapters(None) };
440
441 adapters.extend(
442 hal_adapters
443 .into_iter()
444 .filter_map(|raw| {
445 if apply_limit_buckets {
446 limits::apply_limit_buckets(raw)
447 } else {
448 Some(raw)
449 }
450 })
451 .map(|raw| {
452 let adapter = Adapter::new(raw);
453 api_log_debug!("Adapter {:?}", adapter.raw.info);
454 adapter
455 }),
456 );
457 }
458 adapters
459 }
460
461 pub fn request_adapter(
462 &self,
463 desc: &wgt::RequestAdapterOptions<&Surface>,
464 backends: Backends,
465 ) -> Result<Adapter, wgt::RequestAdapterError> {
466 profiling::scope!("Instance::request_adapter");
467 api_log!("Instance::request_adapter");
468
469 let mut adapters = Vec::new();
470 let mut incompatible_surface_backends = Backends::empty();
471 let mut no_fallback_backends = Backends::empty();
472 let mut no_adapter_backends = Backends::empty();
473
474 for &(backend, ref instance) in self
475 .instance_per_backend
476 .iter()
477 .filter(|&&(backend, _)| backends.contains(Backends::from(backend)))
478 {
479 let compatible_hal_surface = desc
480 .compatible_surface
481 .and_then(|surface| surface.raw(backend));
482
483 let mut backend_adapters =
484 unsafe { instance.enumerate_adapters(compatible_hal_surface) };
485 if backend_adapters.is_empty() {
486 log::debug!("enabled backend `{backend:?}` has no adapters");
487 no_adapter_backends |= Backends::from(backend);
488 continue;
490 }
491
492 if desc.force_fallback_adapter {
493 log::debug!("Filtering `{backend:?}` for `force_fallback_adapter`");
494 backend_adapters.retain(|exposed| {
495 let keep = exposed.info.device_type == wgt::DeviceType::Cpu;
496 if !keep {
497 log::debug!("* Eliminating adapter `{}`", exposed.info.name);
498 }
499 keep
500 });
501 if backend_adapters.is_empty() {
502 log::debug!("* Backend `{backend:?}` has no fallback adapters");
503 no_fallback_backends |= Backends::from(backend);
504 continue;
505 }
506 }
507
508 if let Some(surface) = desc.compatible_surface {
509 backend_adapters.retain(|exposed| {
510 let capabilities = surface.get_capabilities_with_raw(exposed);
511 if let Err(err) = capabilities {
512 log::debug!(
513 "Adapter {:?} not compatible with surface: {}",
514 exposed.info,
515 err
516 );
517 incompatible_surface_backends |= Backends::from(backend);
518 false
519 } else {
520 true
521 }
522 });
523 if backend_adapters.is_empty() {
524 incompatible_surface_backends |= Backends::from(backend);
525 continue;
526 }
527 }
528
529 if desc.apply_limit_buckets {
530 adapters.extend(
531 backend_adapters
532 .into_iter()
533 .filter_map(limits::apply_limit_buckets),
534 );
535 } else {
536 adapters.append(&mut backend_adapters);
537 }
538 }
539
540 match desc.power_preference {
541 PowerPreference::LowPower => {
542 sort(&mut adapters, true);
543 }
544 PowerPreference::HighPerformance => {
545 sort(&mut adapters, false);
546 }
547 PowerPreference::None => {}
548 };
549
550 fn sort(adapters: &mut [hal::DynExposedAdapter], prefer_integrated_gpu: bool) {
551 adapters
552 .sort_by_key(|adapter| get_order(adapter.info.device_type, prefer_integrated_gpu));
553 }
554
555 fn get_order(device_type: wgt::DeviceType, prefer_integrated_gpu: bool) -> u8 {
556 match device_type {
564 wgt::DeviceType::DiscreteGpu if prefer_integrated_gpu => 2,
565 wgt::DeviceType::IntegratedGpu if prefer_integrated_gpu => 1,
566 wgt::DeviceType::DiscreteGpu => 1,
567 wgt::DeviceType::IntegratedGpu => 2,
568 wgt::DeviceType::Other => 3,
569 wgt::DeviceType::VirtualGpu => 4,
570 wgt::DeviceType::Cpu => 5,
571 }
572 }
573
574 if adapters.is_empty() {
577 log::debug!("Request adapter didn't find compatible adapters.");
578 } else {
579 log::debug!(
580 "Found {} compatible adapters. Sorted by preference:",
581 adapters.len()
582 );
583 for adapter in &adapters {
584 log::debug!("* {:?}", adapter.info);
585 }
586 }
587
588 if let Some(adapter) = adapters.into_iter().next() {
589 api_log_debug!("Request adapter result {:?}", adapter.info);
590 let adapter = Adapter::new(adapter);
591 Ok(adapter)
592 } else {
593 Err(wgt::RequestAdapterError::NotFound {
594 supported_backends: self.supported_backends,
595 requested_backends: self.requested_backends,
596 active_backends: self.active_backends(),
597 no_fallback_backends,
598 no_adapter_backends,
599 incompatible_surface_backends,
600 })
601 }
602 }
603
604 fn active_backends(&self) -> Backends {
605 self.instance_per_backend
606 .iter()
607 .map(|&(backend, _)| Backends::from(backend))
608 .collect()
609 }
610}
611
612pub struct Surface {
613 pub(crate) presentation: Mutex<Option<Presentation>>,
614 pub surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>>,
615}
616
617impl ResourceType for Surface {
618 const TYPE: &'static str = "Surface";
619}
620impl crate::storage::StorageItem for Surface {
621 type Marker = markers::Surface;
622}
623
624impl Surface {
625 pub fn get_capabilities(
626 &self,
627 adapter: &Adapter,
628 ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
629 self.get_capabilities_with_raw(&adapter.raw)
630 }
631
632 pub fn get_capabilities_with_raw(
633 &self,
634 adapter: &hal::DynExposedAdapter,
635 ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
636 let backend = adapter.backend();
637 let suf = self
638 .raw(backend)
639 .ok_or(GetSurfaceSupportError::NotSupportedByBackend(backend))?;
640 profiling::scope!("surface_capabilities");
641 let caps = unsafe { adapter.adapter.surface_capabilities(suf) }
642 .ok_or(GetSurfaceSupportError::FailedToRetrieveSurfaceCapabilitiesForAdapter)?;
643 Ok(caps)
644 }
645
646 pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynSurface> {
647 self.surface_per_backend
648 .get(&backend)
649 .map(|surface| surface.as_ref())
650 }
651}
652
653impl Drop for Surface {
654 fn drop(&mut self) {
655 if let Some(present) = self.presentation.lock().take() {
656 for (&backend, surface) in &self.surface_per_backend {
657 if backend == present.device.backend() {
658 unsafe { surface.unconfigure(present.device.raw()) };
659 }
660 }
661 }
662 }
663}
664
665pub struct Adapter {
666 pub(crate) raw: hal::DynExposedAdapter,
667}
668
669impl Adapter {
670 pub fn new(raw: hal::DynExposedAdapter) -> Self {
671 Self { raw }
672 }
673
674 pub fn backend(&self) -> Backend {
676 self.raw.backend()
677 }
678
679 pub fn is_surface_supported(&self, surface: &Surface) -> bool {
680 surface.get_capabilities(self).is_ok()
685 }
686
687 pub fn get_info(&self) -> wgt::AdapterInfo {
688 self.raw.info.clone()
689 }
690
691 pub fn features(&self) -> wgt::Features {
692 self.raw.features
693 }
694
695 pub fn limits(&self) -> wgt::Limits {
696 self.raw.capabilities.limits.clone()
697 }
698
699 pub fn downlevel_capabilities(&self) -> wgt::DownlevelCapabilities {
700 self.raw.capabilities.downlevel.clone()
701 }
702
703 pub fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
704 unsafe { self.raw.adapter.get_presentation_timestamp() }
705 }
706
707 pub fn cooperative_matrix_properties(&self) -> Vec<wgt::CooperativeMatrixProperties> {
708 self.raw.capabilities.cooperative_matrix_properties.clone()
709 }
710
711 pub fn get_texture_format_features(
712 &self,
713 format: wgt::TextureFormat,
714 ) -> wgt::TextureFormatFeatures {
715 use hal::TextureFormatCapabilities as Tfc;
716
717 let caps = unsafe { self.raw.adapter.texture_format_capabilities(format) };
718 let mut allowed_usages = wgt::TextureUsages::empty();
719
720 allowed_usages.set(wgt::TextureUsages::COPY_SRC, caps.contains(Tfc::COPY_SRC));
721 allowed_usages.set(wgt::TextureUsages::COPY_DST, caps.contains(Tfc::COPY_DST));
722 allowed_usages.set(
723 wgt::TextureUsages::TEXTURE_BINDING,
724 caps.contains(Tfc::SAMPLED),
725 );
726 allowed_usages.set(
727 wgt::TextureUsages::STORAGE_BINDING,
728 caps.intersects(
729 Tfc::STORAGE_WRITE_ONLY
730 | Tfc::STORAGE_READ_ONLY
731 | Tfc::STORAGE_READ_WRITE
732 | Tfc::STORAGE_ATOMIC,
733 ),
734 );
735 allowed_usages.set(
736 wgt::TextureUsages::RENDER_ATTACHMENT | wgt::TextureUsages::TRANSIENT,
737 caps.intersects(Tfc::COLOR_ATTACHMENT | Tfc::DEPTH_STENCIL_ATTACHMENT),
738 );
739 allowed_usages.set(
740 wgt::TextureUsages::STORAGE_ATOMIC,
741 caps.contains(Tfc::STORAGE_ATOMIC),
742 );
743
744 let mut flags = wgt::TextureFormatFeatureFlags::empty();
745 flags.set(
746 wgt::TextureFormatFeatureFlags::STORAGE_READ_ONLY,
747 caps.contains(Tfc::STORAGE_READ_ONLY),
748 );
749 flags.set(
750 wgt::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY,
751 caps.contains(Tfc::STORAGE_WRITE_ONLY),
752 );
753 flags.set(
754 wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE,
755 caps.contains(Tfc::STORAGE_READ_WRITE),
756 );
757
758 flags.set(
759 wgt::TextureFormatFeatureFlags::STORAGE_ATOMIC,
760 caps.contains(Tfc::STORAGE_ATOMIC),
761 );
762
763 flags.set(
764 wgt::TextureFormatFeatureFlags::FILTERABLE,
765 caps.contains(Tfc::SAMPLED_LINEAR),
766 );
767
768 flags.set(
769 wgt::TextureFormatFeatureFlags::BLENDABLE,
770 caps.contains(Tfc::COLOR_ATTACHMENT_BLEND),
771 );
772
773 flags.set(
774 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X2,
775 caps.contains(Tfc::MULTISAMPLE_X2),
776 );
777 flags.set(
778 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X4,
779 caps.contains(Tfc::MULTISAMPLE_X4),
780 );
781 flags.set(
782 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X8,
783 caps.contains(Tfc::MULTISAMPLE_X8),
784 );
785 flags.set(
786 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X16,
787 caps.contains(Tfc::MULTISAMPLE_X16),
788 );
789
790 flags.set(
791 wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE,
792 caps.contains(Tfc::MULTISAMPLE_RESOLVE),
793 );
794
795 wgt::TextureFormatFeatures {
796 allowed_usages,
797 flags,
798 }
799 }
800
801 fn create_device_and_queue_from_hal(
802 self: &Arc<Self>,
803 hal_device: hal::DynOpenDevice,
804 desc: &DeviceDescriptor,
805 instance_flags: wgt::InstanceFlags,
806 ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
807 api_log!("Adapter::create_device");
808
809 let device = Device::new(hal_device.device, self, desc, instance_flags)?;
810 let device = Arc::new(device);
811
812 let queue = Queue::new(device.clone(), hal_device.queue, instance_flags)?;
813 let queue = Arc::new(queue);
814
815 device.set_queue(&queue);
816 device.late_init_resources_with_queue()?;
817
818 Ok((device, queue))
819 }
820
821 pub fn create_device_and_queue(
822 self: &Arc<Self>,
823 desc: &DeviceDescriptor,
824 instance_flags: wgt::InstanceFlags,
825 ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
826 if !self.raw.features.contains(desc.required_features) {
828 return Err(RequestDeviceError::UnsupportedFeature(
829 desc.required_features - self.raw.features,
830 ));
831 }
832
833 if desc
835 .required_features
836 .intersects(wgt::Features::all_experimental_mask())
837 && !desc.experimental_features.is_enabled()
838 {
839 return Err(RequestDeviceError::ExperimentalFeaturesNotEnabled(
840 desc.required_features
841 .intersection(wgt::Features::all_experimental_mask()),
842 ));
843 }
844
845 let caps = &self.raw.capabilities;
846 if Backends::PRIMARY.contains(Backends::from(self.backend()))
847 && !caps.downlevel.is_webgpu_compliant()
848 {
849 let missing_flags = wgt::DownlevelFlags::compliant() - caps.downlevel.flags;
850 log::warn!("Missing downlevel flags: {missing_flags:?}\n{DOWNLEVEL_WARNING_MESSAGE}");
851 log::warn!("{:#?}", caps.downlevel);
852 }
853
854 if desc
856 .required_features
857 .contains(wgt::Features::MAPPABLE_PRIMARY_BUFFERS)
858 && self.raw.info.device_type == wgt::DeviceType::DiscreteGpu
859 {
860 log::warn!(
861 "Feature MAPPABLE_PRIMARY_BUFFERS enabled on a discrete gpu. \
862 This is a massive performance footgun and likely not what you wanted"
863 );
864 }
865
866 if let Some(failed) = check_limits(&desc.required_limits, &caps.limits).pop() {
867 return Err(RequestDeviceError::LimitsExceeded(failed));
868 }
869
870 let open = unsafe {
871 self.raw.adapter.open(
872 desc.required_features,
873 &desc.required_limits,
874 &desc.memory_hints,
875 )
876 }
877 .map_err(DeviceError::from_hal)?;
878
879 self.create_device_and_queue_from_hal(open, desc, instance_flags)
880 }
881}
882
883crate::impl_resource_type!(Adapter);
884crate::impl_storage_item!(Adapter);
885
886#[derive(Clone, Debug, Error)]
887#[non_exhaustive]
888pub enum GetSurfaceSupportError {
889 #[error("Surface is not supported for the specified backend {0}")]
890 NotSupportedByBackend(Backend),
891 #[error("Failed to retrieve surface capabilities for the specified adapter.")]
892 FailedToRetrieveSurfaceCapabilitiesForAdapter,
893}
894
895#[derive(Clone, Debug, Error)]
896#[non_exhaustive]
898pub enum RequestDeviceError {
899 #[error(transparent)]
900 Device(#[from] DeviceError),
901 #[error(transparent)]
902 LimitsExceeded(#[from] FailedLimit),
903 #[error("Failed to initialize Timestamp Normalizer")]
904 TimestampNormalizerInitFailed(#[from] TimestampNormalizerInitError),
905 #[error("Unsupported features were requested: {0}")]
906 UnsupportedFeature(wgt::Features),
907 #[error(
908 "Some experimental features, {0}, were requested, but experimental features are not enabled"
909 )]
910 ExperimentalFeaturesNotEnabled(wgt::Features),
911}
912
913#[derive(Clone, Debug, Error)]
914#[non_exhaustive]
915pub enum CreateSurfaceError {
916 #[error("The backend {0} was not enabled on the instance.")]
917 BackendNotEnabled(Backend),
918 #[error("Failed to create surface for any enabled backend: {0:?}")]
919 FailedToCreateSurfaceForAnyBackend(HashMap<Backend, hal::InstanceError>),
920 #[error("The display handle used to create this Instance does not match the one used to create a surface on it")]
921 MismatchingDisplayHandle,
922 #[error(
923 "No `DisplayHandle` is available to create this surface with. When creating a surface with `create_surface()` \
924 you must specify a display handle in `InstanceDescriptor::display`. \
925 Rarely, if you need to create surfaces from different `DisplayHandle`s (ex. different Wayland or X11 connections), \
926 you must use `create_surface_unsafe()`."
927 )]
928 MissingDisplayHandle,
929}
930
931impl Global {
932 pub unsafe fn instance_create_surface(
951 &self,
952 display_handle: Option<raw_window_handle::RawDisplayHandle>,
953 window_handle: raw_window_handle::RawWindowHandle,
954 id_in: Option<SurfaceId>,
955 ) -> Result<SurfaceId, CreateSurfaceError> {
956 let surface = unsafe { self.instance.create_surface(display_handle, window_handle) }?;
957 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
958 Ok(id)
959 }
960
961 #[cfg(all(
972 unix,
973 not(target_vendor = "apple"),
974 not(target_family = "wasm"),
975 not(target_os = "netbsd")
976 ))]
977 pub unsafe fn instance_create_surface_from_drm(
978 &self,
979 fd: i32,
980 plane: u32,
981 connector_id: u32,
982 width: u32,
983 height: u32,
984 refresh_rate: u32,
985 id_in: Option<SurfaceId>,
986 ) -> Result<SurfaceId, CreateSurfaceError> {
987 let surface = unsafe {
988 self.instance.create_surface_from_drm(
989 fd,
990 plane,
991 connector_id,
992 width,
993 height,
994 refresh_rate,
995 )
996 }?;
997 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
998
999 Ok(id)
1000 }
1001
1002 #[cfg(metal)]
1006 pub unsafe fn instance_create_surface_metal(
1007 &self,
1008 layer: *mut core::ffi::c_void,
1009 id_in: Option<SurfaceId>,
1010 ) -> Result<SurfaceId, CreateSurfaceError> {
1011 let surface = unsafe { self.instance.create_surface_metal(layer) }?;
1012 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1013 Ok(id)
1014 }
1015
1016 #[cfg(dx12)]
1017 pub unsafe fn instance_create_surface_from_visual(
1021 &self,
1022 visual: *mut core::ffi::c_void,
1023 id_in: Option<SurfaceId>,
1024 ) -> Result<SurfaceId, CreateSurfaceError> {
1025 let surface = unsafe { self.instance.create_surface_from_visual(visual) }?;
1026 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1027 Ok(id)
1028 }
1029
1030 #[cfg(dx12)]
1031 pub unsafe fn instance_create_surface_from_surface_handle(
1035 &self,
1036 surface_handle: *mut core::ffi::c_void,
1037 id_in: Option<SurfaceId>,
1038 ) -> Result<SurfaceId, CreateSurfaceError> {
1039 let surface = unsafe {
1040 self.instance
1041 .create_surface_from_surface_handle(surface_handle)
1042 }?;
1043 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1044 Ok(id)
1045 }
1046
1047 #[cfg(dx12)]
1048 pub unsafe fn instance_create_surface_from_swap_chain_panel(
1052 &self,
1053 swap_chain_panel: *mut core::ffi::c_void,
1054 id_in: Option<SurfaceId>,
1055 ) -> Result<SurfaceId, CreateSurfaceError> {
1056 let surface = unsafe {
1057 self.instance
1058 .create_surface_from_swap_chain_panel(swap_chain_panel)
1059 }?;
1060 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1061 Ok(id)
1062 }
1063
1064 pub fn surface_drop(&self, id: SurfaceId) {
1065 profiling::scope!("Surface::drop");
1066
1067 api_log!("Surface::drop {id:?}");
1068
1069 self.surfaces.remove(id);
1070 }
1071
1072 pub fn enumerate_adapters(
1073 &self,
1074 backends: Backends,
1075 apply_limit_buckets: bool,
1076 ) -> Vec<AdapterId> {
1077 let adapters = self
1078 .instance
1079 .enumerate_adapters(backends, apply_limit_buckets);
1080 adapters
1081 .into_iter()
1082 .map(|adapter| self.hub.adapters.prepare(None).assign(Arc::new(adapter)))
1083 .collect()
1084 }
1085
1086 pub fn request_adapter(
1087 &self,
1088 desc: &RequestAdapterOptions,
1089 backends: Backends,
1090 id_in: Option<AdapterId>,
1091 ) -> Result<AdapterId, wgt::RequestAdapterError> {
1092 let compatible_surface = desc.compatible_surface.map(|id| self.surfaces.get(id));
1093 let desc = wgt::RequestAdapterOptions {
1094 power_preference: desc.power_preference,
1095 force_fallback_adapter: desc.force_fallback_adapter,
1096 compatible_surface: compatible_surface.as_deref(),
1097 apply_limit_buckets: desc.apply_limit_buckets,
1098 };
1099 let adapter = self.instance.request_adapter(&desc, backends)?;
1100 let id = self.hub.adapters.prepare(id_in).assign(Arc::new(adapter));
1101 Ok(id)
1102 }
1103
1104 pub unsafe fn create_adapter_from_hal(
1118 &self,
1119 hal_adapter: hal::DynExposedAdapter,
1120 input: Option<AdapterId>,
1121 ) -> AdapterId {
1122 profiling::scope!("Instance::create_adapter_from_hal");
1123
1124 let fid = self.hub.adapters.prepare(input);
1125 let id = fid.assign(Arc::new(Adapter::new(hal_adapter)));
1126
1127 resource_log!("Created Adapter {:?}", id);
1128 id
1129 }
1130
1131 pub fn adapter_get_info(&self, adapter_id: AdapterId) -> wgt::AdapterInfo {
1132 let adapter = self.hub.adapters.get(adapter_id);
1133 adapter.get_info()
1134 }
1135
1136 pub fn adapter_get_texture_format_features(
1137 &self,
1138 adapter_id: AdapterId,
1139 format: wgt::TextureFormat,
1140 ) -> wgt::TextureFormatFeatures {
1141 let adapter = self.hub.adapters.get(adapter_id);
1142 adapter.get_texture_format_features(format)
1143 }
1144
1145 pub fn adapter_features(&self, adapter_id: AdapterId) -> wgt::Features {
1146 let adapter = self.hub.adapters.get(adapter_id);
1147 adapter.features()
1148 }
1149
1150 pub fn adapter_limits(&self, adapter_id: AdapterId) -> wgt::Limits {
1151 let adapter = self.hub.adapters.get(adapter_id);
1152 adapter.limits()
1153 }
1154
1155 pub fn adapter_downlevel_capabilities(
1156 &self,
1157 adapter_id: AdapterId,
1158 ) -> wgt::DownlevelCapabilities {
1159 let adapter = self.hub.adapters.get(adapter_id);
1160 adapter.downlevel_capabilities()
1161 }
1162
1163 pub fn adapter_get_presentation_timestamp(
1164 &self,
1165 adapter_id: AdapterId,
1166 ) -> wgt::PresentationTimestamp {
1167 let adapter = self.hub.adapters.get(adapter_id);
1168 adapter.get_presentation_timestamp()
1169 }
1170
1171 pub fn adapter_cooperative_matrix_properties(
1172 &self,
1173 adapter_id: AdapterId,
1174 ) -> Vec<wgt::CooperativeMatrixProperties> {
1175 let adapter = self.hub.adapters.get(adapter_id);
1176 adapter.cooperative_matrix_properties()
1177 }
1178
1179 pub fn adapter_drop(&self, adapter_id: AdapterId) {
1180 profiling::scope!("Adapter::drop");
1181 api_log!("Adapter::drop {adapter_id:?}");
1182
1183 self.hub.adapters.remove(adapter_id);
1184 }
1185}
1186
1187impl Global {
1188 pub fn adapter_request_device(
1189 &self,
1190 adapter_id: AdapterId,
1191 desc: &DeviceDescriptor,
1192 device_id_in: Option<DeviceId>,
1193 queue_id_in: Option<QueueId>,
1194 ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1195 profiling::scope!("Adapter::request_device");
1196 api_log!("Adapter::request_device");
1197
1198 let device_fid = self.hub.devices.prepare(device_id_in);
1199 let queue_fid = self.hub.queues.prepare(queue_id_in);
1200
1201 let adapter = self.hub.adapters.get(adapter_id);
1202 let (device, queue) = adapter.create_device_and_queue(desc, self.instance.flags)?;
1203
1204 let device_id = device_fid.assign(device);
1205 resource_log!("Created Device {:?}", device_id);
1206
1207 let queue_id = queue_fid.assign(queue);
1208 resource_log!("Created Queue {:?}", queue_id);
1209
1210 Ok((device_id, queue_id))
1211 }
1212
1213 pub unsafe fn create_device_from_hal(
1218 &self,
1219 adapter_id: AdapterId,
1220 hal_device: hal::DynOpenDevice,
1221 desc: &DeviceDescriptor,
1222 device_id_in: Option<DeviceId>,
1223 queue_id_in: Option<QueueId>,
1224 ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1225 profiling::scope!("Global::create_device_from_hal");
1226
1227 let devices_fid = self.hub.devices.prepare(device_id_in);
1228 let queues_fid = self.hub.queues.prepare(queue_id_in);
1229
1230 let adapter = self.hub.adapters.get(adapter_id);
1231 let (device, queue) =
1232 adapter.create_device_and_queue_from_hal(hal_device, desc, self.instance.flags)?;
1233
1234 let device_id = devices_fid.assign(device);
1235 resource_log!("Created Device {:?}", device_id);
1236
1237 let queue_id = queues_fid.assign(queue);
1238 resource_log!("Created Queue {:?}", queue_id);
1239
1240 Ok((device_id, queue_id))
1241 }
1242}