1use alloc::{borrow::ToOwned as _, boxed::Box, string::String, sync::Arc, vec, vec::Vec};
2use core::fmt;
3
4use hashbrown::HashMap;
5use thiserror::Error;
6
7use crate::{
8 api_log, api_log_debug,
9 device::{queue::Queue, resource::Device, DeviceDescriptor, DeviceError},
10 global::Global,
11 id::{markers, AdapterId, DeviceId, QueueId, SurfaceId},
12 limits::{self, check_limits, FailedLimit},
13 lock::{rank, Mutex},
14 present::Presentation,
15 resource::ResourceType,
16 resource_log,
17 timestamp_normalization::TimestampNormalizerInitError,
18 DOWNLEVEL_WARNING_MESSAGE,
19};
20
21use wgt::{Backend, Backends, InstanceFlags, PowerPreference};
22
23pub type RequestAdapterOptions = wgt::RequestAdapterOptions<SurfaceId>;
24
25#[test]
26fn downlevel_default_limits_less_than_default_limits() {
27 let res = check_limits(&wgt::Limits::downlevel_defaults(), &wgt::Limits::default());
28 assert!(
29 res.is_empty(),
30 "Downlevel limits are greater than default limits",
31 )
32}
33
34#[derive(Default)]
35pub struct Instance {
36 _name: String,
37
38 instance_per_backend: Vec<(Backend, Box<dyn hal::DynInstance>)>,
42
43 requested_backends: Backends,
45
46 supported_backends: Backends,
54
55 pub flags: InstanceFlags,
56
57 display: Option<Box<dyn wgt::WgpuHasDisplayHandle>>,
63}
64
65impl Instance {
66 pub fn new(
67 name: &str,
68 mut instance_desc: wgt::InstanceDescriptor,
69 telemetry: Option<hal::Telemetry>,
70 ) -> Self {
71 let mut this = Self {
72 _name: name.to_owned(),
73 instance_per_backend: Vec::new(),
74 requested_backends: instance_desc.backends,
75 supported_backends: Backends::empty(),
76 flags: instance_desc.flags,
77 display: instance_desc.display.take(),
81 };
82
83 #[cfg(all(vulkan, not(target_os = "netbsd")))]
84 this.try_add_hal(hal::api::Vulkan, &instance_desc, telemetry);
85 #[cfg(metal)]
86 this.try_add_hal(hal::api::Metal, &instance_desc, telemetry);
87 #[cfg(dx12)]
88 this.try_add_hal(hal::api::Dx12, &instance_desc, telemetry);
89 #[cfg(gles)]
90 this.try_add_hal(hal::api::Gles, &instance_desc, telemetry);
91 #[cfg(feature = "noop")]
92 this.try_add_hal(hal::api::Noop, &instance_desc, telemetry);
93
94 this
95 }
96
97 fn try_add_hal<A: hal::Api>(
99 &mut self,
100 _: A,
101 instance_desc: &wgt::InstanceDescriptor,
102 telemetry: Option<hal::Telemetry>,
103 ) {
104 self.supported_backends |= A::VARIANT.into();
107
108 if !instance_desc.backends.contains(A::VARIANT.into()) {
109 log::trace!("Instance::new: backend {:?} not requested", A::VARIANT);
110 return;
111 }
112
113 assert!(instance_desc.display.is_none());
115
116 let hal_desc = hal::InstanceDescriptor {
117 name: "wgpu",
118 flags: self.flags,
119 memory_budget_thresholds: instance_desc.memory_budget_thresholds,
120 backend_options: instance_desc.backend_options.clone(),
121 telemetry,
122 display: self.display.as_ref().map(|hdh| {
125 hdh.display_handle()
126 .expect("Implementation did not provide a DisplayHandle")
127 }),
128 };
129
130 use hal::Instance as _;
131 match unsafe { A::Instance::init(&hal_desc) } {
133 Ok(instance) => {
134 log::debug!("Instance::new: created {:?} backend", A::VARIANT);
135 self.instance_per_backend
136 .push((A::VARIANT, Box::new(instance)));
137 }
138 Err(err) => {
139 log::debug!(
140 "Instance::new: failed to create {:?} backend: {:?}",
141 A::VARIANT,
142 err
143 );
144 }
145 }
146 }
147
148 pub(crate) fn from_hal_instance<A: hal::Api>(
149 name: String,
150 hal_instance: <A as hal::Api>::Instance,
151 ) -> Self {
152 Self {
153 _name: name,
154 instance_per_backend: vec![(A::VARIANT, Box::new(hal_instance))],
155 requested_backends: A::VARIANT.into(),
156 supported_backends: A::VARIANT.into(),
157 flags: InstanceFlags::default(),
158 display: None, }
160 }
161
162 pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynInstance> {
163 self.instance_per_backend
164 .iter()
165 .find_map(|(instance_backend, instance)| {
166 (*instance_backend == backend).then(|| instance.as_ref())
167 })
168 }
169
170 pub unsafe fn as_hal<A: hal::Api>(&self) -> Option<&A::Instance> {
174 self.raw(A::VARIANT).map(|instance| {
175 instance
176 .as_any()
177 .downcast_ref()
178 .expect("Stored instance is not of the correct type")
180 })
181 }
182
183 pub unsafe fn create_surface(
199 &self,
200 display_handle: Option<raw_window_handle::RawDisplayHandle>,
201 window_handle: raw_window_handle::RawWindowHandle,
202 ) -> Result<Surface, CreateSurfaceError> {
203 profiling::scope!("Instance::create_surface");
204
205 let instance_display_handle = self.display.as_ref().map(|d| {
206 d.display_handle()
207 .expect("Implementation did not provide a DisplayHandle")
208 .as_raw()
209 });
210 let display_handle = match (instance_display_handle, display_handle) {
211 (Some(a), Some(b)) => {
212 if a != b {
213 return Err(CreateSurfaceError::MismatchingDisplayHandle);
214 }
215 a
216 }
217 (Some(hnd), None) => hnd,
218 (None, Some(hnd)) => hnd,
219 (None, None) => return Err(CreateSurfaceError::MissingDisplayHandle),
220 };
221
222 let mut errors = HashMap::default();
223 let mut surface_per_backend = HashMap::default();
224
225 for (backend, instance) in &self.instance_per_backend {
226 match unsafe {
227 instance
228 .as_ref()
229 .create_surface(display_handle, window_handle)
230 } {
231 Ok(raw) => {
232 surface_per_backend.insert(*backend, raw);
233 }
234 Err(err) => {
235 log::debug!(
236 "Instance::create_surface: failed to create surface for {backend:?}: {err:?}"
237 );
238 errors.insert(*backend, err);
239 }
240 }
241 }
242
243 if surface_per_backend.is_empty() {
244 Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
245 errors,
246 ))
247 } else {
248 let surface = Surface {
249 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
250 surface_per_backend,
251 };
252
253 Ok(surface)
254 }
255 }
256
257 #[cfg(drm)]
269 #[cfg_attr(not(vulkan), expect(unused_variables, unused_mut))]
270 pub unsafe fn create_surface_from_drm(
271 &self,
272 fd: i32,
273 plane: u32,
274 connector_id: u32,
275 width: u32,
276 height: u32,
277 refresh_rate: u32,
278 ) -> Result<Surface, CreateSurfaceError> {
279 profiling::scope!("Instance::create_surface_from_drm");
280
281 let mut errors = HashMap::default();
282 let mut surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>> =
283 HashMap::default();
284
285 #[cfg(vulkan)]
286 {
287 let instance = unsafe { self.as_hal::<hal::api::Vulkan>() }
288 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Vulkan))?;
289
290 match unsafe {
292 instance.create_surface_from_drm(
293 fd,
294 plane,
295 connector_id,
296 width,
297 height,
298 refresh_rate,
299 )
300 } {
301 Ok(surface) => {
302 surface_per_backend.insert(Backend::Vulkan, Box::new(surface));
303 }
304 Err(err) => {
305 errors.insert(Backend::Vulkan, err);
306 }
307 }
308 }
309
310 if surface_per_backend.is_empty() {
311 Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
312 errors,
313 ))
314 } else {
315 let surface = Surface {
316 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
317 surface_per_backend,
318 };
319
320 Ok(surface)
321 }
322 }
323
324 #[cfg(metal)]
328 pub unsafe fn create_surface_metal(
329 &self,
330 layer: *mut core::ffi::c_void,
331 ) -> Result<Surface, CreateSurfaceError> {
332 profiling::scope!("Instance::create_surface_metal");
333
334 let instance = unsafe { self.as_hal::<hal::api::Metal>() }
335 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Metal))?;
336
337 let layer = layer.cast();
338 let layer = unsafe { &*layer };
350 let raw_surface: Box<dyn hal::DynSurface> =
351 Box::new(instance.create_surface_from_layer(layer));
352
353 let surface = Surface {
354 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
355 surface_per_backend: core::iter::once((Backend::Metal, raw_surface)).collect(),
356 };
357
358 Ok(surface)
359 }
360
361 #[cfg(dx12)]
362 fn create_surface_dx12(
363 &self,
364 create_surface_func: impl FnOnce(&hal::dx12::Instance) -> hal::dx12::Surface,
365 ) -> Result<Surface, CreateSurfaceError> {
366 let instance = unsafe { self.as_hal::<hal::api::Dx12>() }
367 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Dx12))?;
368 let surface: Box<dyn hal::DynSurface> = Box::new(create_surface_func(instance));
369
370 let surface = Surface {
371 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
372 surface_per_backend: core::iter::once((Backend::Dx12, surface)).collect(),
373 };
374
375 Ok(surface)
376 }
377
378 #[cfg(dx12)]
379 pub unsafe fn create_surface_from_visual(
383 &self,
384 visual: *mut core::ffi::c_void,
385 ) -> Result<Surface, CreateSurfaceError> {
386 profiling::scope!("Instance::instance_create_surface_from_visual");
387 self.create_surface_dx12(|inst| unsafe { inst.create_surface_from_visual(visual) })
388 }
389
390 #[cfg(dx12)]
391 pub unsafe fn create_surface_from_surface_handle(
395 &self,
396 surface_handle: *mut core::ffi::c_void,
397 ) -> Result<Surface, CreateSurfaceError> {
398 profiling::scope!("Instance::instance_create_surface_from_surface_handle");
399 self.create_surface_dx12(|inst| unsafe {
400 inst.create_surface_from_surface_handle(surface_handle)
401 })
402 }
403
404 #[cfg(dx12)]
405 pub unsafe fn create_surface_from_swap_chain_panel(
409 &self,
410 swap_chain_panel: *mut core::ffi::c_void,
411 ) -> Result<Surface, CreateSurfaceError> {
412 profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel");
413 self.create_surface_dx12(|inst| unsafe {
414 inst.create_surface_from_swap_chain_panel(swap_chain_panel)
415 })
416 }
417
418 fn adapter_allowed(&self, raw: &hal::DynExposedAdapter) -> bool {
419 adapter_allowed(
420 self.flags,
421 &raw.info,
422 &raw.capabilities.limits,
423 &raw.capabilities.downlevel,
424 )
425 }
426
427 pub fn enumerate_adapters(
428 &self,
429 backends: Backends,
430 apply_limit_buckets: bool,
431 ) -> Vec<Adapter> {
432 profiling::scope!("Instance::enumerate_adapters");
433 api_log!("Instance::enumerate_adapters");
434
435 let mut adapters = Vec::new();
436 for (_backend, instance) in self
437 .instance_per_backend
438 .iter()
439 .filter(|(backend, _)| backends.contains(Backends::from(*backend)))
440 {
441 profiling::scope!("enumerating", &*alloc::format!("{_backend:?}"));
444
445 let hal_adapters = unsafe { instance.enumerate_adapters(None) };
446
447 adapters.extend(
448 hal_adapters
449 .into_iter()
450 .map(|mut raw| {
451 self.adjust_limits_for_indirect_validation(&mut raw.capabilities.limits);
452 raw
453 })
454 .filter(|raw| self.adapter_allowed(raw))
455 .filter_map(|raw| {
456 if apply_limit_buckets {
457 limits::apply_limit_buckets(raw)
458 } else {
459 Some(raw)
460 }
461 })
462 .map(|raw| {
463 let adapter = Adapter::new(raw);
464 api_log_debug!("Adapter {:?}", adapter.raw.info);
465 adapter
466 }),
467 );
468 }
469 adapters
470 }
471
472 pub fn request_adapter(
473 &self,
474 desc: &wgt::RequestAdapterOptions<&Surface>,
475 backends: Backends,
476 ) -> Result<Adapter, wgt::RequestAdapterError> {
477 profiling::scope!("Instance::request_adapter");
478 api_log!("Instance::request_adapter");
479
480 let mut adapters = Vec::new();
481 let mut incompatible_surface_backends = Backends::empty();
482 let mut no_fallback_backends = Backends::empty();
483 let mut no_adapter_backends = Backends::empty();
484
485 for &(backend, ref instance) in self
486 .instance_per_backend
487 .iter()
488 .filter(|&&(backend, _)| backends.contains(Backends::from(backend)))
489 {
490 let compatible_hal_surface = desc
491 .compatible_surface
492 .and_then(|surface| surface.raw(backend));
493
494 let mut backend_adapters =
495 unsafe { instance.enumerate_adapters(compatible_hal_surface) };
496 if backend_adapters.is_empty() {
497 log::debug!("enabled backend `{backend:?}` has no adapters");
498 no_adapter_backends |= Backends::from(backend);
499 continue;
501 }
502
503 if desc.force_fallback_adapter {
504 log::debug!("Filtering `{backend:?}` for `force_fallback_adapter`");
505 backend_adapters.retain(|exposed| {
506 let keep = exposed.info.device_type == wgt::DeviceType::Cpu;
507 if !keep {
508 log::debug!("* Eliminating adapter `{}`", exposed.info.name);
509 }
510 keep
511 });
512 if backend_adapters.is_empty() {
513 log::debug!("* Backend `{backend:?}` has no fallback adapters");
514 no_fallback_backends |= Backends::from(backend);
515 continue;
516 }
517 }
518
519 if let Some(surface) = desc.compatible_surface {
520 backend_adapters.retain(|exposed| {
521 let capabilities = surface.get_capabilities_with_raw(exposed);
522 if let Err(err) = capabilities {
523 log::debug!(
524 "Adapter {:?} not compatible with surface: {}",
525 exposed.info,
526 err
527 );
528 incompatible_surface_backends |= Backends::from(backend);
529 false
530 } else {
531 true
532 }
533 });
534 if backend_adapters.is_empty() {
535 incompatible_surface_backends |= Backends::from(backend);
536 continue;
537 }
538 }
539
540 let backend_adapters = backend_adapters
541 .into_iter()
542 .map(|mut raw| {
543 self.adjust_limits_for_indirect_validation(&mut raw.capabilities.limits);
544 raw
545 })
546 .filter(|raw| self.adapter_allowed(raw));
547
548 if desc.apply_limit_buckets {
549 adapters.extend(backend_adapters.filter_map(limits::apply_limit_buckets));
550 } else {
551 adapters.extend(backend_adapters);
552 }
553 }
554
555 match desc.power_preference {
556 PowerPreference::LowPower => {
557 sort(&mut adapters, true);
558 }
559 PowerPreference::HighPerformance => {
560 sort(&mut adapters, false);
561 }
562 PowerPreference::None => {}
563 };
564
565 fn sort(adapters: &mut [hal::DynExposedAdapter], prefer_integrated_gpu: bool) {
566 adapters
567 .sort_by_key(|adapter| get_order(adapter.info.device_type, prefer_integrated_gpu));
568 }
569
570 fn get_order(device_type: wgt::DeviceType, prefer_integrated_gpu: bool) -> u8 {
571 match device_type {
579 wgt::DeviceType::DiscreteGpu if prefer_integrated_gpu => 2,
580 wgt::DeviceType::IntegratedGpu if prefer_integrated_gpu => 1,
581 wgt::DeviceType::DiscreteGpu => 1,
582 wgt::DeviceType::IntegratedGpu => 2,
583 wgt::DeviceType::Other => 3,
584 wgt::DeviceType::VirtualGpu => 4,
585 wgt::DeviceType::Cpu => 5,
586 }
587 }
588
589 if adapters.is_empty() {
592 log::debug!("Request adapter didn't find compatible adapters.");
593 } else {
594 log::debug!(
595 "Found {} compatible adapters. Sorted by preference:",
596 adapters.len()
597 );
598 for adapter in &adapters {
599 log::debug!("* {:?}", adapter.info);
600 }
601 }
602
603 if let Some(adapter) = adapters.into_iter().next() {
604 api_log_debug!("Request adapter result {:?}", adapter.info);
605 let adapter = Adapter::new(adapter);
606 Ok(adapter)
607 } else {
608 Err(wgt::RequestAdapterError::NotFound {
609 supported_backends: self.supported_backends,
610 requested_backends: self.requested_backends,
611 active_backends: self.active_backends(),
612 no_fallback_backends,
613 no_adapter_backends,
614 incompatible_surface_backends,
615 })
616 }
617 }
618
619 fn adjust_limits_for_indirect_validation(&self, limits: &mut wgt::Limits) {
622 if self.flags.contains(InstanceFlags::VALIDATION_INDIRECT_CALL) {
625 limits.max_buffer_size = limits.max_buffer_size.min(u32::MAX as u64);
626 limits.max_uniform_buffer_binding_size =
627 limits.max_uniform_buffer_binding_size.min(u32::MAX as u64);
628 limits.max_storage_buffer_binding_size =
629 limits.max_storage_buffer_binding_size.min(u32::MAX as u64);
630 }
631 }
632
633 fn active_backends(&self) -> Backends {
634 self.instance_per_backend
635 .iter()
636 .map(|&(backend, _)| Backends::from(backend))
637 .collect()
638 }
639}
640
641pub struct Surface {
642 pub(crate) presentation: Mutex<Option<Presentation>>,
643 pub surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>>,
644}
645
646impl ResourceType for Surface {
647 const TYPE: &'static str = "Surface";
648}
649impl crate::storage::StorageItem for Surface {
650 type Marker = markers::Surface;
651}
652
653impl Surface {
654 pub fn get_capabilities(
655 &self,
656 adapter: &Adapter,
657 ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
658 self.get_capabilities_with_raw(&adapter.raw)
659 }
660
661 pub fn get_capabilities_with_raw(
662 &self,
663 adapter: &hal::DynExposedAdapter,
664 ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
665 let backend = adapter.backend();
666 let suf = self
667 .raw(backend)
668 .ok_or(GetSurfaceSupportError::NotSupportedByBackend(backend))?;
669 profiling::scope!("surface_capabilities");
670 let caps = unsafe { adapter.adapter.surface_capabilities(suf) }
671 .ok_or(GetSurfaceSupportError::FailedToRetrieveSurfaceCapabilitiesForAdapter)?;
672 Ok(caps)
673 }
674
675 pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynSurface> {
676 self.surface_per_backend
677 .get(&backend)
678 .map(|surface| surface.as_ref())
679 }
680}
681
682impl Drop for Surface {
683 fn drop(&mut self) {
684 if let Some(present) = self.presentation.lock().take() {
685 for (&backend, surface) in &self.surface_per_backend {
686 if backend == present.device.backend() {
687 unsafe { surface.unconfigure(present.device.raw()) };
688 }
689 }
690 }
691 }
692}
693
694pub struct Adapter {
695 pub(crate) raw: hal::DynExposedAdapter,
696}
697
698impl Adapter {
699 pub fn new(raw: hal::DynExposedAdapter) -> Self {
700 Self { raw }
701 }
702
703 pub fn backend(&self) -> Backend {
705 self.raw.backend()
706 }
707
708 pub fn is_surface_supported(&self, surface: &Surface) -> bool {
709 surface.get_capabilities(self).is_ok()
714 }
715
716 pub fn get_info(&self) -> wgt::AdapterInfo {
717 self.raw.info.clone()
718 }
719
720 pub fn features(&self) -> wgt::Features {
721 self.raw.features
722 }
723
724 pub fn limits(&self) -> wgt::Limits {
725 self.raw.capabilities.limits.clone()
726 }
727
728 pub fn downlevel_capabilities(&self) -> wgt::DownlevelCapabilities {
729 self.raw.capabilities.downlevel.clone()
730 }
731
732 pub fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
733 unsafe { self.raw.adapter.get_presentation_timestamp() }
734 }
735
736 pub fn cooperative_matrix_properties(&self) -> Vec<wgt::CooperativeMatrixProperties> {
737 self.raw.capabilities.cooperative_matrix_properties.clone()
738 }
739
740 pub fn get_texture_format_features(
741 &self,
742 format: wgt::TextureFormat,
743 ) -> wgt::TextureFormatFeatures {
744 use hal::TextureFormatCapabilities as Tfc;
745
746 let caps = unsafe { self.raw.adapter.texture_format_capabilities(format) };
747 let mut allowed_usages = wgt::TextureUsages::empty();
748
749 allowed_usages.set(wgt::TextureUsages::COPY_SRC, caps.contains(Tfc::COPY_SRC));
750 allowed_usages.set(wgt::TextureUsages::COPY_DST, caps.contains(Tfc::COPY_DST));
751 allowed_usages.set(
752 wgt::TextureUsages::TEXTURE_BINDING,
753 caps.contains(Tfc::SAMPLED),
754 );
755 allowed_usages.set(
756 wgt::TextureUsages::STORAGE_BINDING,
757 caps.intersects(
758 Tfc::STORAGE_WRITE_ONLY
759 | Tfc::STORAGE_READ_ONLY
760 | Tfc::STORAGE_READ_WRITE
761 | Tfc::STORAGE_ATOMIC,
762 ),
763 );
764 allowed_usages.set(
765 wgt::TextureUsages::RENDER_ATTACHMENT | wgt::TextureUsages::TRANSIENT,
766 caps.intersects(Tfc::COLOR_ATTACHMENT | Tfc::DEPTH_STENCIL_ATTACHMENT),
767 );
768 allowed_usages.set(
769 wgt::TextureUsages::STORAGE_ATOMIC,
770 caps.contains(Tfc::STORAGE_ATOMIC),
771 );
772
773 let mut flags = wgt::TextureFormatFeatureFlags::empty();
774 flags.set(
775 wgt::TextureFormatFeatureFlags::STORAGE_READ_ONLY,
776 caps.contains(Tfc::STORAGE_READ_ONLY),
777 );
778 flags.set(
779 wgt::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY,
780 caps.contains(Tfc::STORAGE_WRITE_ONLY),
781 );
782 flags.set(
783 wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE,
784 caps.contains(Tfc::STORAGE_READ_WRITE),
785 );
786
787 flags.set(
788 wgt::TextureFormatFeatureFlags::STORAGE_ATOMIC,
789 caps.contains(Tfc::STORAGE_ATOMIC),
790 );
791
792 flags.set(
793 wgt::TextureFormatFeatureFlags::FILTERABLE,
794 caps.contains(Tfc::SAMPLED_LINEAR),
795 );
796
797 flags.set(
798 wgt::TextureFormatFeatureFlags::BLENDABLE,
799 caps.contains(Tfc::COLOR_ATTACHMENT_BLEND),
800 );
801
802 flags.set(
803 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X2,
804 caps.contains(Tfc::MULTISAMPLE_X2),
805 );
806 flags.set(
807 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X4,
808 caps.contains(Tfc::MULTISAMPLE_X4),
809 );
810 flags.set(
811 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X8,
812 caps.contains(Tfc::MULTISAMPLE_X8),
813 );
814 flags.set(
815 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X16,
816 caps.contains(Tfc::MULTISAMPLE_X16),
817 );
818
819 flags.set(
820 wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE,
821 caps.contains(Tfc::MULTISAMPLE_RESOLVE),
822 );
823
824 wgt::TextureFormatFeatures {
825 allowed_usages,
826 flags,
827 }
828 }
829
830 fn create_device_and_queue_from_hal(
831 self: &Arc<Self>,
832 hal_device: hal::DynOpenDevice,
833 desc: &DeviceDescriptor,
834 instance_flags: InstanceFlags,
835 ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
836 api_log!("Adapter::create_device");
837
838 let device = Device::new(hal_device.device, self, desc, instance_flags)?;
839 let device = Arc::new(device);
840
841 let queue = Queue::new(device.clone(), hal_device.queue, instance_flags)?;
842 let queue = Arc::new(queue);
843
844 device.set_queue(&queue);
845 device.late_init_resources_with_queue()?;
846
847 Ok((device, queue))
848 }
849
850 pub fn create_device_and_queue(
851 self: &Arc<Self>,
852 desc: &DeviceDescriptor,
853 instance_flags: InstanceFlags,
854 ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
855 if !self.raw.features.contains(desc.required_features) {
857 return Err(RequestDeviceError::UnsupportedFeature(
858 desc.required_features - self.raw.features,
859 ));
860 }
861
862 if desc
864 .required_features
865 .intersects(wgt::Features::all_experimental_mask())
866 && !desc.experimental_features.is_enabled()
867 {
868 return Err(RequestDeviceError::ExperimentalFeaturesNotEnabled(
869 desc.required_features
870 .intersection(wgt::Features::all_experimental_mask()),
871 ));
872 }
873
874 let caps = &self.raw.capabilities;
875 if Backends::PRIMARY.contains(Backends::from(self.backend()))
876 && !caps.downlevel.is_webgpu_compliant()
877 {
878 let missing_flags = wgt::DownlevelFlags::compliant() - caps.downlevel.flags;
879 log::warn!("Missing downlevel flags: {missing_flags:?}\n{DOWNLEVEL_WARNING_MESSAGE}");
880 log::warn!("{:#?}", caps.downlevel);
881 }
882
883 if desc
885 .required_features
886 .contains(wgt::Features::MAPPABLE_PRIMARY_BUFFERS)
887 && self.raw.info.device_type == wgt::DeviceType::DiscreteGpu
888 {
889 log::warn!(
890 "Feature MAPPABLE_PRIMARY_BUFFERS enabled on a discrete gpu. \
891 This is a massive performance footgun and likely not what you wanted"
892 );
893 }
894
895 if let Some(failed) = check_limits(&desc.required_limits, &caps.limits).pop() {
896 return Err(RequestDeviceError::LimitsExceeded(failed));
897 }
898
899 let open = unsafe {
900 self.raw.adapter.open(
901 desc.required_features,
902 &desc.required_limits,
903 &desc.memory_hints,
904 )
905 }
906 .map_err(DeviceError::from_hal)?;
907
908 self.create_device_and_queue_from_hal(open, desc, instance_flags)
909 }
910}
911
912crate::impl_resource_type!(Adapter);
913crate::impl_storage_item!(Adapter);
914
915#[derive(Clone, Debug, Error)]
916#[non_exhaustive]
917pub enum GetSurfaceSupportError {
918 #[error("Surface is not supported for the specified backend {0}")]
919 NotSupportedByBackend(Backend),
920 #[error("Failed to retrieve surface capabilities for the specified adapter.")]
921 FailedToRetrieveSurfaceCapabilitiesForAdapter,
922}
923
924#[derive(Clone, Debug, Error)]
925#[non_exhaustive]
927pub enum RequestDeviceError {
928 #[error(transparent)]
929 Device(#[from] DeviceError),
930 #[error(transparent)]
931 LimitsExceeded(#[from] FailedLimit),
932 #[error("Failed to initialize Timestamp Normalizer")]
933 TimestampNormalizerInitFailed(#[from] TimestampNormalizerInitError),
934 #[error("Unsupported features were requested: {0}")]
935 UnsupportedFeature(wgt::Features),
936 #[error(
937 "Some experimental features, {0}, were requested, but experimental features are not enabled"
938 )]
939 ExperimentalFeaturesNotEnabled(wgt::Features),
940}
941
942#[derive(Clone, Debug, Error)]
943#[non_exhaustive]
944pub enum CreateSurfaceError {
945 #[error("The backend {0} was not enabled on the instance.")]
946 BackendNotEnabled(Backend),
947 #[error("Failed to create surface for any enabled backend: {0:?}")]
948 FailedToCreateSurfaceForAnyBackend(HashMap<Backend, hal::InstanceError>),
949 #[error("The display handle used to create this Instance does not match the one used to create a surface on it")]
950 MismatchingDisplayHandle,
951 #[error(
952 "No `DisplayHandle` is available to create this surface with. When creating a surface with `create_surface()` \
953 you must specify a display handle in `InstanceDescriptor::display`. \
954 Rarely, if you need to create surfaces from different `DisplayHandle`s (ex. different Wayland or X11 connections), \
955 you must use `create_surface_unsafe()`."
956 )]
957 MissingDisplayHandle,
958}
959
960impl Global {
961 pub unsafe fn instance_create_surface(
980 &self,
981 display_handle: Option<raw_window_handle::RawDisplayHandle>,
982 window_handle: raw_window_handle::RawWindowHandle,
983 id_in: Option<SurfaceId>,
984 ) -> Result<SurfaceId, CreateSurfaceError> {
985 let surface = unsafe { self.instance.create_surface(display_handle, window_handle) }?;
986 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
987 Ok(id)
988 }
989
990 #[cfg(drm)]
1002 pub unsafe fn instance_create_surface_from_drm(
1003 &self,
1004 fd: i32,
1005 plane: u32,
1006 connector_id: u32,
1007 width: u32,
1008 height: u32,
1009 refresh_rate: u32,
1010 id_in: Option<SurfaceId>,
1011 ) -> Result<SurfaceId, CreateSurfaceError> {
1012 let surface = unsafe {
1013 self.instance.create_surface_from_drm(
1014 fd,
1015 plane,
1016 connector_id,
1017 width,
1018 height,
1019 refresh_rate,
1020 )
1021 }?;
1022 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1023
1024 Ok(id)
1025 }
1026
1027 #[cfg(metal)]
1031 pub unsafe fn instance_create_surface_metal(
1032 &self,
1033 layer: *mut core::ffi::c_void,
1034 id_in: Option<SurfaceId>,
1035 ) -> Result<SurfaceId, CreateSurfaceError> {
1036 let surface = unsafe { self.instance.create_surface_metal(layer) }?;
1037 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1038 Ok(id)
1039 }
1040
1041 #[cfg(dx12)]
1042 pub unsafe fn instance_create_surface_from_visual(
1046 &self,
1047 visual: *mut core::ffi::c_void,
1048 id_in: Option<SurfaceId>,
1049 ) -> Result<SurfaceId, CreateSurfaceError> {
1050 let surface = unsafe { self.instance.create_surface_from_visual(visual) }?;
1051 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1052 Ok(id)
1053 }
1054
1055 #[cfg(dx12)]
1056 pub unsafe fn instance_create_surface_from_surface_handle(
1060 &self,
1061 surface_handle: *mut core::ffi::c_void,
1062 id_in: Option<SurfaceId>,
1063 ) -> Result<SurfaceId, CreateSurfaceError> {
1064 let surface = unsafe {
1065 self.instance
1066 .create_surface_from_surface_handle(surface_handle)
1067 }?;
1068 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1069 Ok(id)
1070 }
1071
1072 #[cfg(dx12)]
1073 pub unsafe fn instance_create_surface_from_swap_chain_panel(
1077 &self,
1078 swap_chain_panel: *mut core::ffi::c_void,
1079 id_in: Option<SurfaceId>,
1080 ) -> Result<SurfaceId, CreateSurfaceError> {
1081 let surface = unsafe {
1082 self.instance
1083 .create_surface_from_swap_chain_panel(swap_chain_panel)
1084 }?;
1085 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1086 Ok(id)
1087 }
1088
1089 pub fn surface_drop(&self, id: SurfaceId) {
1090 profiling::scope!("Surface::drop");
1091
1092 api_log!("Surface::drop {id:?}");
1093
1094 self.surfaces.remove(id);
1095 }
1096
1097 pub fn enumerate_adapters(
1098 &self,
1099 backends: Backends,
1100 apply_limit_buckets: bool,
1101 ) -> Vec<AdapterId> {
1102 let adapters = self
1103 .instance
1104 .enumerate_adapters(backends, apply_limit_buckets);
1105 adapters
1106 .into_iter()
1107 .map(|adapter| self.hub.adapters.prepare(None).assign(Arc::new(adapter)))
1108 .collect()
1109 }
1110
1111 pub fn request_adapter(
1112 &self,
1113 desc: &RequestAdapterOptions,
1114 backends: Backends,
1115 id_in: Option<AdapterId>,
1116 ) -> Result<AdapterId, wgt::RequestAdapterError> {
1117 let compatible_surface = desc.compatible_surface.map(|id| self.surfaces.get(id));
1118 let desc = wgt::RequestAdapterOptions {
1119 power_preference: desc.power_preference,
1120 force_fallback_adapter: desc.force_fallback_adapter,
1121 compatible_surface: compatible_surface.as_deref(),
1122 apply_limit_buckets: desc.apply_limit_buckets,
1123 };
1124 let adapter = self.instance.request_adapter(&desc, backends)?;
1125 let id = self.hub.adapters.prepare(id_in).assign(Arc::new(adapter));
1126 Ok(id)
1127 }
1128
1129 pub unsafe fn create_adapter_from_hal(
1143 &self,
1144 hal_adapter: hal::DynExposedAdapter,
1145 input: Option<AdapterId>,
1146 ) -> AdapterId {
1147 profiling::scope!("Instance::create_adapter_from_hal");
1148
1149 let fid = self.hub.adapters.prepare(input);
1150 let id = fid.assign(Arc::new(Adapter::new(hal_adapter)));
1151
1152 resource_log!("Created Adapter {:?}", id);
1153 id
1154 }
1155
1156 pub fn adapter_get_info(&self, adapter_id: AdapterId) -> wgt::AdapterInfo {
1157 let adapter = self.hub.adapters.get(adapter_id);
1158 adapter.get_info()
1159 }
1160
1161 pub fn adapter_get_texture_format_features(
1162 &self,
1163 adapter_id: AdapterId,
1164 format: wgt::TextureFormat,
1165 ) -> wgt::TextureFormatFeatures {
1166 let adapter = self.hub.adapters.get(adapter_id);
1167 adapter.get_texture_format_features(format)
1168 }
1169
1170 pub fn adapter_features(&self, adapter_id: AdapterId) -> wgt::Features {
1171 let adapter = self.hub.adapters.get(adapter_id);
1172 adapter.features()
1173 }
1174
1175 pub fn adapter_limits(&self, adapter_id: AdapterId) -> wgt::Limits {
1176 let adapter = self.hub.adapters.get(adapter_id);
1177 adapter.limits()
1178 }
1179
1180 pub fn adapter_downlevel_capabilities(
1181 &self,
1182 adapter_id: AdapterId,
1183 ) -> wgt::DownlevelCapabilities {
1184 let adapter = self.hub.adapters.get(adapter_id);
1185 adapter.downlevel_capabilities()
1186 }
1187
1188 pub fn adapter_get_presentation_timestamp(
1189 &self,
1190 adapter_id: AdapterId,
1191 ) -> wgt::PresentationTimestamp {
1192 let adapter = self.hub.adapters.get(adapter_id);
1193 adapter.get_presentation_timestamp()
1194 }
1195
1196 pub fn adapter_cooperative_matrix_properties(
1197 &self,
1198 adapter_id: AdapterId,
1199 ) -> Vec<wgt::CooperativeMatrixProperties> {
1200 let adapter = self.hub.adapters.get(adapter_id);
1201 adapter.cooperative_matrix_properties()
1202 }
1203
1204 pub fn adapter_drop(&self, adapter_id: AdapterId) {
1205 profiling::scope!("Adapter::drop");
1206 api_log!("Adapter::drop {adapter_id:?}");
1207
1208 self.hub.adapters.remove(adapter_id);
1209 }
1210}
1211
1212impl Global {
1213 pub fn adapter_request_device(
1214 &self,
1215 adapter_id: AdapterId,
1216 desc: &DeviceDescriptor,
1217 device_id_in: Option<DeviceId>,
1218 queue_id_in: Option<QueueId>,
1219 ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1220 profiling::scope!("Adapter::request_device");
1221 api_log!("Adapter::request_device");
1222
1223 let device_fid = self.hub.devices.prepare(device_id_in);
1224 let queue_fid = self.hub.queues.prepare(queue_id_in);
1225
1226 let adapter = self.hub.adapters.get(adapter_id);
1227 let (device, queue) = adapter.create_device_and_queue(desc, self.instance.flags)?;
1228
1229 let device_id = device_fid.assign(device);
1230 resource_log!("Created Device {:?}", device_id);
1231
1232 let queue_id = queue_fid.assign(queue);
1233 resource_log!("Created Queue {:?}", queue_id);
1234
1235 Ok((device_id, queue_id))
1236 }
1237
1238 pub unsafe fn create_device_from_hal(
1243 &self,
1244 adapter_id: AdapterId,
1245 hal_device: hal::DynOpenDevice,
1246 desc: &DeviceDescriptor,
1247 device_id_in: Option<DeviceId>,
1248 queue_id_in: Option<QueueId>,
1249 ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1250 profiling::scope!("Global::create_device_from_hal");
1251
1252 let devices_fid = self.hub.devices.prepare(device_id_in);
1253 let queues_fid = self.hub.queues.prepare(queue_id_in);
1254
1255 let adapter = self.hub.adapters.get(adapter_id);
1256 let (device, queue) =
1257 adapter.create_device_and_queue_from_hal(hal_device, desc, self.instance.flags)?;
1258
1259 let device_id = devices_fid.assign(device);
1260 resource_log!("Created Device {:?}", device_id);
1261
1262 let queue_id = queues_fid.assign(queue);
1263 resource_log!("Created Queue {:?}", queue_id);
1264
1265 Ok((device_id, queue_id))
1266 }
1267}
1268
1269fn adapter_allowed(
1274 flags: InstanceFlags,
1275 info: &impl fmt::Debug,
1276 limits: &wgt::Limits,
1277 downlevel: &wgt::DownlevelCapabilities,
1278) -> bool {
1279 let min_uniform_buffer_offset_alignment = limits.min_uniform_buffer_offset_alignment;
1285 if !min_uniform_buffer_offset_alignment.is_power_of_two() {
1286 log::error!(
1287 "Adapter {:?} min_uniform_buffer_offset_alignment limit is not a power of 2: {:?}",
1288 info,
1289 min_uniform_buffer_offset_alignment
1290 );
1291 return false;
1292 }
1293 let min_storage_buffer_offset_alignment = limits.min_storage_buffer_offset_alignment;
1294 if !min_storage_buffer_offset_alignment.is_power_of_two() {
1295 log::error!(
1296 "Adapter {:?} min_storage_buffer_offset_alignment limit is not a power of 2: {:?}",
1297 info,
1298 min_storage_buffer_offset_alignment
1299 );
1300 return false;
1301 }
1302
1303 if !flags.contains(InstanceFlags::STRICT_WEBGPU_COMPLIANCE) {
1305 return true;
1306 }
1307
1308 let failed_limits = check_limits(&wgt::Limits::defaults(), limits);
1310 if !failed_limits.is_empty() {
1311 log::debug!(
1312 "Adapter {:?} is not WebGPU compliant due to limits: {:?}",
1313 info,
1314 failed_limits
1315 );
1316 return false;
1317 }
1318
1319 if !downlevel.is_webgpu_compliant() {
1320 let missing_flags = wgt::DownlevelFlags::compliant() - downlevel.flags;
1321 log::debug!(
1322 "Adapter {:?} is not WebGPU compliant due to missing downlevel flags: {:?}",
1323 info,
1324 missing_flags
1325 );
1326 return false;
1327 }
1328
1329 true
1330}
1331
1332#[cfg(test)]
1333mod tests {
1334 use super::*;
1335
1336 fn compliant_downlevel() -> wgt::DownlevelCapabilities {
1337 wgt::DownlevelCapabilities {
1338 flags: wgt::DownlevelFlags::compliant(),
1339 ..Default::default()
1340 }
1341 }
1342
1343 #[test]
1344 fn non_power_of_two_uniform_alignment_always_rejected() {
1345 let limits = wgt::Limits {
1346 min_uniform_buffer_offset_alignment: 3,
1347 ..wgt::Limits::defaults()
1348 };
1349 assert!(!adapter_allowed(
1350 InstanceFlags::empty(),
1351 &"",
1352 &limits,
1353 &compliant_downlevel()
1354 ));
1355 assert!(!adapter_allowed(
1356 InstanceFlags::STRICT_WEBGPU_COMPLIANCE,
1357 &"",
1358 &limits,
1359 &compliant_downlevel()
1360 ));
1361 }
1362
1363 #[test]
1364 fn non_power_of_two_storage_alignment_always_rejected() {
1365 let limits = wgt::Limits {
1366 min_storage_buffer_offset_alignment: 96,
1367 ..wgt::Limits::defaults()
1368 };
1369 assert!(!adapter_allowed(
1370 InstanceFlags::empty(),
1371 &"",
1372 &limits,
1373 &compliant_downlevel()
1374 ));
1375 assert!(!adapter_allowed(
1376 InstanceFlags::STRICT_WEBGPU_COMPLIANCE,
1377 &"",
1378 &limits,
1379 &compliant_downlevel()
1380 ));
1381 }
1382
1383 #[test]
1384 fn low_limits_allowed_without_strict_compliance() {
1385 let limits = wgt::Limits {
1386 max_texture_dimension_1d: 1,
1387 ..wgt::Limits::defaults()
1388 };
1389 assert!(adapter_allowed(
1390 InstanceFlags::empty(),
1391 &"",
1392 &limits,
1393 &wgt::DownlevelCapabilities::default()
1394 ));
1395 }
1396
1397 #[test]
1398 fn low_limits_rejected_with_strict_compliance() {
1399 let limits = wgt::Limits {
1400 max_texture_dimension_1d: 1,
1401 ..wgt::Limits::defaults()
1402 };
1403 assert!(!adapter_allowed(
1404 InstanceFlags::STRICT_WEBGPU_COMPLIANCE,
1405 &"",
1406 &limits,
1407 &compliant_downlevel()
1408 ));
1409 }
1410
1411 #[test]
1412 fn missing_downlevel_flags_rejected_with_strict_compliance() {
1413 let downlevel = wgt::DownlevelCapabilities {
1414 flags: wgt::DownlevelFlags::empty(),
1415 ..Default::default()
1416 };
1417 assert!(!adapter_allowed(
1418 InstanceFlags::STRICT_WEBGPU_COMPLIANCE,
1419 &"",
1420 &wgt::Limits::defaults(),
1421 &downlevel
1422 ));
1423 }
1424
1425 #[test]
1426 fn fully_compliant_adapter_always_allowed() {
1427 assert!(adapter_allowed(
1428 InstanceFlags::STRICT_WEBGPU_COMPLIANCE,
1429 &"",
1430 &wgt::Limits::defaults(),
1431 &compliant_downlevel()
1432 ));
1433 }
1434}