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 .map(|mut raw| {
455 filter_features_and_limits(
456 self.flags,
457 &mut raw.features,
458 &mut raw.capabilities.limits,
459 );
460 raw
461 })
462 .filter(|raw| self.adapter_allowed(raw))
463 .filter_map(|raw| {
464 if apply_limit_buckets {
465 limits::apply_limit_buckets(raw)
466 } else {
467 Some(raw)
468 }
469 })
470 .map(|raw| {
471 let adapter = Adapter::new(raw);
472 api_log_debug!("Adapter {:?}", adapter.raw.info);
473 adapter
474 }),
475 );
476 }
477 adapters
478 }
479
480 pub fn request_adapter(
481 &self,
482 desc: &wgt::RequestAdapterOptions<&Surface>,
483 backends: Backends,
484 ) -> Result<Adapter, wgt::RequestAdapterError> {
485 profiling::scope!("Instance::request_adapter");
486 api_log!("Instance::request_adapter");
487
488 let mut adapters = Vec::new();
489 let mut incompatible_surface_backends = Backends::empty();
490 let mut no_fallback_backends = Backends::empty();
491 let mut no_adapter_backends = Backends::empty();
492
493 for &(backend, ref instance) in self
494 .instance_per_backend
495 .iter()
496 .filter(|&&(backend, _)| backends.contains(Backends::from(backend)))
497 {
498 let compatible_hal_surface = desc
499 .compatible_surface
500 .and_then(|surface| surface.raw(backend));
501
502 let mut backend_adapters =
503 unsafe { instance.enumerate_adapters(compatible_hal_surface) };
504 if backend_adapters.is_empty() {
505 log::debug!("enabled backend `{backend:?}` has no adapters");
506 no_adapter_backends |= Backends::from(backend);
507 continue;
509 }
510
511 if desc.force_fallback_adapter {
512 log::debug!("Filtering `{backend:?}` for `force_fallback_adapter`");
513 backend_adapters.retain(|exposed| {
514 let keep = exposed.info.device_type == wgt::DeviceType::Cpu;
515 if !keep {
516 log::debug!("* Eliminating adapter `{}`", exposed.info.name);
517 }
518 keep
519 });
520 if backend_adapters.is_empty() {
521 log::debug!("* Backend `{backend:?}` has no fallback adapters");
522 no_fallback_backends |= Backends::from(backend);
523 continue;
524 }
525 }
526
527 if let Some(surface) = desc.compatible_surface {
528 backend_adapters.retain(|exposed| {
529 let capabilities = surface.get_capabilities_with_raw(exposed);
530 if let Err(err) = capabilities {
531 log::debug!(
532 "Adapter {:?} not compatible with surface: {}",
533 exposed.info,
534 err
535 );
536 incompatible_surface_backends |= Backends::from(backend);
537 false
538 } else {
539 true
540 }
541 });
542 if backend_adapters.is_empty() {
543 incompatible_surface_backends |= Backends::from(backend);
544 continue;
545 }
546 }
547
548 let backend_adapters = backend_adapters
549 .into_iter()
550 .map(|mut raw| {
551 self.adjust_limits_for_indirect_validation(&mut raw.capabilities.limits);
552 raw
553 })
554 .map(|mut raw| {
555 filter_features_and_limits(
556 self.flags,
557 &mut raw.features,
558 &mut raw.capabilities.limits,
559 );
560 raw
561 })
562 .filter(|raw| self.adapter_allowed(raw));
563
564 if desc.apply_limit_buckets {
565 adapters.extend(backend_adapters.filter_map(limits::apply_limit_buckets));
566 } else {
567 adapters.extend(backend_adapters);
568 }
569 }
570
571 match desc.power_preference {
572 PowerPreference::LowPower => {
573 sort(&mut adapters, true);
574 }
575 PowerPreference::HighPerformance => {
576 sort(&mut adapters, false);
577 }
578 PowerPreference::None => {}
579 };
580
581 fn sort(adapters: &mut [hal::DynExposedAdapter], prefer_integrated_gpu: bool) {
582 adapters
583 .sort_by_key(|adapter| get_order(adapter.info.device_type, prefer_integrated_gpu));
584 }
585
586 fn get_order(device_type: wgt::DeviceType, prefer_integrated_gpu: bool) -> u8 {
587 match device_type {
595 wgt::DeviceType::DiscreteGpu if prefer_integrated_gpu => 2,
596 wgt::DeviceType::IntegratedGpu if prefer_integrated_gpu => 1,
597 wgt::DeviceType::DiscreteGpu => 1,
598 wgt::DeviceType::IntegratedGpu => 2,
599 wgt::DeviceType::Other => 3,
600 wgt::DeviceType::VirtualGpu => 4,
601 wgt::DeviceType::Cpu => 5,
602 }
603 }
604
605 if adapters.is_empty() {
608 log::debug!("Request adapter didn't find compatible adapters.");
609 } else {
610 log::debug!(
611 "Found {} compatible adapters. Sorted by preference:",
612 adapters.len()
613 );
614 for adapter in &adapters {
615 log::debug!("* {:?}", adapter.info);
616 }
617 }
618
619 if let Some(adapter) = adapters.into_iter().next() {
620 api_log_debug!("Request adapter result {:?}", adapter.info);
621 let adapter = Adapter::new(adapter);
622 Ok(adapter)
623 } else {
624 Err(wgt::RequestAdapterError::NotFound {
625 supported_backends: self.supported_backends,
626 requested_backends: self.requested_backends,
627 active_backends: self.active_backends(),
628 no_fallback_backends,
629 no_adapter_backends,
630 incompatible_surface_backends,
631 })
632 }
633 }
634
635 fn adjust_limits_for_indirect_validation(&self, limits: &mut wgt::Limits) {
638 if self.flags.contains(InstanceFlags::VALIDATION_INDIRECT_CALL) {
641 limits.max_buffer_size = limits.max_buffer_size.min(u32::MAX as u64);
642 limits.max_uniform_buffer_binding_size =
643 limits.max_uniform_buffer_binding_size.min(u32::MAX as u64);
644 limits.max_storage_buffer_binding_size = limits
645 .max_storage_buffer_binding_size
646 .min(u32::MAX as u64 & !(wgt::STORAGE_BINDING_SIZE_ALIGNMENT as u64 - 1));
647 }
648 }
649
650 fn active_backends(&self) -> Backends {
651 self.instance_per_backend
652 .iter()
653 .map(|&(backend, _)| Backends::from(backend))
654 .collect()
655 }
656}
657
658pub struct Surface {
659 pub(crate) presentation: Mutex<Option<Presentation>>,
660 pub surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>>,
661}
662
663impl ResourceType for Surface {
664 const TYPE: &'static str = "Surface";
665}
666impl crate::storage::StorageItem for Surface {
667 type Marker = markers::Surface;
668}
669
670impl Surface {
671 pub fn get_capabilities(
672 &self,
673 adapter: &Adapter,
674 ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
675 self.get_capabilities_with_raw(&adapter.raw)
676 }
677
678 pub fn get_capabilities_with_raw(
679 &self,
680 adapter: &hal::DynExposedAdapter,
681 ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
682 let backend = adapter.backend();
683 let suf = self
684 .raw(backend)
685 .ok_or(GetSurfaceSupportError::NotSupportedByBackend(backend))?;
686 profiling::scope!("surface_capabilities");
687 let caps = unsafe { adapter.adapter.surface_capabilities(suf) }
688 .ok_or(GetSurfaceSupportError::FailedToRetrieveSurfaceCapabilitiesForAdapter)?;
689 Ok(caps)
690 }
691
692 pub fn display_hdr_info(&self, adapter: &Adapter) -> wgt::DisplayHdrInfo {
698 self.display_hdr_info_with_raw(&adapter.raw)
699 }
700
701 pub fn display_hdr_info_with_raw(
702 &self,
703 adapter: &hal::DynExposedAdapter,
704 ) -> wgt::DisplayHdrInfo {
705 let backend = adapter.backend();
706 let Some(suf) = self.raw(backend) else {
707 return wgt::DisplayHdrInfo::default();
708 };
709 profiling::scope!("surface_display_hdr_info");
710 unsafe { adapter.adapter.surface_display_hdr_info(suf) }.unwrap_or_default()
711 }
712
713 pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynSurface> {
714 self.surface_per_backend
715 .get(&backend)
716 .map(|surface| surface.as_ref())
717 }
718}
719
720impl Drop for Surface {
721 fn drop(&mut self) {
722 if let Some(present) = self.presentation.lock().take() {
723 for (&backend, surface) in &self.surface_per_backend {
724 if backend == present.device.backend() {
725 unsafe { surface.unconfigure(present.device.raw()) };
726 }
727 }
728 }
729 }
730}
731
732pub struct Adapter {
733 pub(crate) raw: hal::DynExposedAdapter,
734}
735
736impl Adapter {
737 pub fn new(raw: hal::DynExposedAdapter) -> Self {
738 Self { raw }
739 }
740
741 pub fn backend(&self) -> Backend {
743 self.raw.backend()
744 }
745
746 pub fn is_surface_supported(&self, surface: &Surface) -> bool {
747 surface.get_capabilities(self).is_ok()
752 }
753
754 pub fn get_info(&self) -> wgt::AdapterInfo {
755 self.raw.info.clone()
756 }
757
758 pub fn features(&self) -> wgt::Features {
759 self.raw.features
760 }
761
762 pub fn limits(&self) -> wgt::Limits {
763 self.raw.capabilities.limits.clone()
764 }
765
766 pub fn downlevel_capabilities(&self) -> wgt::DownlevelCapabilities {
767 self.raw.capabilities.downlevel.clone()
768 }
769
770 pub fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
771 unsafe { self.raw.adapter.get_presentation_timestamp() }
772 }
773
774 pub fn cooperative_matrix_properties(&self) -> Vec<wgt::CooperativeMatrixProperties> {
775 self.raw.capabilities.cooperative_matrix_properties.clone()
776 }
777
778 pub fn get_texture_format_features(
779 &self,
780 format: wgt::TextureFormat,
781 ) -> wgt::TextureFormatFeatures {
782 use hal::TextureFormatCapabilities as Tfc;
783
784 let caps = unsafe { self.raw.adapter.texture_format_capabilities(format) };
785 let mut allowed_usages = wgt::TextureUsages::empty();
786
787 allowed_usages.set(wgt::TextureUsages::COPY_SRC, caps.contains(Tfc::COPY_SRC));
788 allowed_usages.set(wgt::TextureUsages::COPY_DST, caps.contains(Tfc::COPY_DST));
789 allowed_usages.set(
790 wgt::TextureUsages::TEXTURE_BINDING,
791 caps.contains(Tfc::SAMPLED),
792 );
793 allowed_usages.set(
794 wgt::TextureUsages::STORAGE_BINDING,
795 caps.intersects(
796 Tfc::STORAGE_WRITE_ONLY
797 | Tfc::STORAGE_READ_ONLY
798 | Tfc::STORAGE_READ_WRITE
799 | Tfc::STORAGE_ATOMIC,
800 ),
801 );
802 allowed_usages.set(
803 wgt::TextureUsages::RENDER_ATTACHMENT | wgt::TextureUsages::TRANSIENT_ATTACHMENT,
804 caps.intersects(Tfc::COLOR_ATTACHMENT | Tfc::DEPTH_STENCIL_ATTACHMENT),
805 );
806 allowed_usages.set(
807 wgt::TextureUsages::STORAGE_ATOMIC,
808 caps.contains(Tfc::STORAGE_ATOMIC),
809 );
810
811 let mut flags = wgt::TextureFormatFeatureFlags::empty();
812 flags.set(
813 wgt::TextureFormatFeatureFlags::STORAGE_READ_ONLY,
814 caps.contains(Tfc::STORAGE_READ_ONLY),
815 );
816 flags.set(
817 wgt::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY,
818 caps.contains(Tfc::STORAGE_WRITE_ONLY),
819 );
820 flags.set(
821 wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE,
822 caps.contains(Tfc::STORAGE_READ_WRITE),
823 );
824
825 flags.set(
826 wgt::TextureFormatFeatureFlags::STORAGE_ATOMIC,
827 caps.contains(Tfc::STORAGE_ATOMIC),
828 );
829
830 flags.set(
831 wgt::TextureFormatFeatureFlags::FILTERABLE,
832 caps.contains(Tfc::SAMPLED_LINEAR),
833 );
834
835 flags.set(
836 wgt::TextureFormatFeatureFlags::BLENDABLE,
837 caps.contains(Tfc::COLOR_ATTACHMENT_BLEND),
838 );
839
840 flags.set(
841 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X2,
842 caps.contains(Tfc::MULTISAMPLE_X2),
843 );
844 flags.set(
845 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X4,
846 caps.contains(Tfc::MULTISAMPLE_X4),
847 );
848 flags.set(
849 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X8,
850 caps.contains(Tfc::MULTISAMPLE_X8),
851 );
852 flags.set(
853 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X16,
854 caps.contains(Tfc::MULTISAMPLE_X16),
855 );
856
857 flags.set(
858 wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE,
859 caps.contains(Tfc::MULTISAMPLE_RESOLVE),
860 );
861
862 wgt::TextureFormatFeatures {
863 allowed_usages,
864 flags,
865 }
866 }
867
868 fn create_device_and_queue_from_hal(
869 self: &Arc<Self>,
870 hal_device: hal::DynOpenDevice,
871 desc: &DeviceDescriptor,
872 instance_flags: InstanceFlags,
873 ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
874 api_log!("Adapter::create_device");
875
876 let device = Device::new(hal_device.device, self, desc, instance_flags)?;
877 let device = Arc::new(device);
878
879 let queue = Queue::new(device.clone(), hal_device.queue, instance_flags)?;
880 let queue = Arc::new(queue);
881
882 device.set_queue(&queue);
883 device.late_init_resources_with_queue()?;
884
885 Ok((device, queue))
886 }
887
888 pub fn create_device_and_queue(
889 self: &Arc<Self>,
890 desc: &DeviceDescriptor,
891 instance_flags: InstanceFlags,
892 ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
893 let mut desc = desc.clone();
894 filter_features_and_limits(
895 instance_flags,
896 &mut desc.required_features,
897 &mut desc.required_limits,
898 );
899
900 if !self.raw.features.contains(desc.required_features) {
902 return Err(RequestDeviceError::UnsupportedFeature(
903 desc.required_features - self.raw.features,
904 ));
905 }
906
907 if desc
909 .required_features
910 .intersects(wgt::Features::all_experimental_mask())
911 && !desc.experimental_features.is_enabled()
912 {
913 return Err(RequestDeviceError::ExperimentalFeaturesNotEnabled(
914 desc.required_features
915 .intersection(wgt::Features::all_experimental_mask()),
916 ));
917 }
918
919 let caps = &self.raw.capabilities;
920 if Backends::PRIMARY.contains(Backends::from(self.backend()))
921 && !caps.downlevel.is_webgpu_compliant()
922 {
923 let missing_flags = wgt::DownlevelFlags::compliant() - caps.downlevel.flags;
924 log::warn!("Missing downlevel flags: {missing_flags:?}\n{DOWNLEVEL_WARNING_MESSAGE}");
925 log::warn!("{:#?}", caps.downlevel);
926 }
927
928 if desc
930 .required_features
931 .contains(wgt::Features::MAPPABLE_PRIMARY_BUFFERS)
932 && self.raw.info.device_type == wgt::DeviceType::DiscreteGpu
933 {
934 log::warn!(
935 "Feature MAPPABLE_PRIMARY_BUFFERS enabled on a discrete gpu. \
936 This is a massive performance footgun and likely not what you wanted"
937 );
938 }
939
940 if let Some(failed) = check_limits(&desc.required_limits, &caps.limits).pop() {
941 return Err(RequestDeviceError::LimitsExceeded(failed));
942 }
943
944 let open = unsafe {
945 self.raw.adapter.open(
946 desc.required_features,
947 &desc.required_limits,
948 &desc.memory_hints,
949 )
950 }
951 .map_err(DeviceError::from_hal)?;
952
953 self.create_device_and_queue_from_hal(open, &desc, instance_flags)
954 }
955}
956
957crate::impl_resource_type!(Adapter);
958crate::impl_storage_item!(Adapter);
959
960#[derive(Clone, Debug, Error)]
961#[non_exhaustive]
962pub enum GetSurfaceSupportError {
963 #[error("Surface is not supported for the specified backend {0}")]
964 NotSupportedByBackend(Backend),
965 #[error("Failed to retrieve surface capabilities for the specified adapter.")]
966 FailedToRetrieveSurfaceCapabilitiesForAdapter,
967}
968
969#[derive(Clone, Debug, Error)]
970#[non_exhaustive]
972pub enum RequestDeviceError {
973 #[error(transparent)]
974 Device(#[from] DeviceError),
975 #[error(transparent)]
976 LimitsExceeded(#[from] FailedLimit),
977 #[error("Failed to initialize Timestamp Normalizer")]
978 TimestampNormalizerInitFailed(#[from] TimestampNormalizerInitError),
979 #[error("Unsupported features were requested: {0}")]
980 UnsupportedFeature(wgt::Features),
981 #[error(
982 "Some experimental features, {0}, were requested, but experimental features are not enabled"
983 )]
984 ExperimentalFeaturesNotEnabled(wgt::Features),
985}
986
987#[derive(Clone, Debug, Error)]
988#[non_exhaustive]
989pub enum CreateSurfaceError {
990 #[error("The backend {0} was not enabled on the instance.")]
991 BackendNotEnabled(Backend),
992 #[error("Failed to create surface for any enabled backend: {0:?}")]
993 FailedToCreateSurfaceForAnyBackend(HashMap<Backend, hal::InstanceError>),
994 #[error("The display handle used to create this Instance does not match the one used to create a surface on it")]
995 MismatchingDisplayHandle,
996 #[error(
997 "No `DisplayHandle` is available to create this surface with. When creating a surface with `create_surface()` \
998 you must specify a display handle in `InstanceDescriptor::display`. \
999 Rarely, if you need to create surfaces from different `DisplayHandle`s (ex. different Wayland or X11 connections), \
1000 you must use `create_surface_unsafe()`."
1001 )]
1002 MissingDisplayHandle,
1003}
1004
1005impl Global {
1006 pub unsafe fn instance_create_surface(
1025 &self,
1026 display_handle: Option<raw_window_handle::RawDisplayHandle>,
1027 window_handle: raw_window_handle::RawWindowHandle,
1028 id_in: Option<SurfaceId>,
1029 ) -> Result<SurfaceId, CreateSurfaceError> {
1030 let surface = unsafe { self.instance.create_surface(display_handle, window_handle) }?;
1031 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1032 Ok(id)
1033 }
1034
1035 #[cfg(drm)]
1047 pub unsafe fn instance_create_surface_from_drm(
1048 &self,
1049 fd: i32,
1050 plane: u32,
1051 connector_id: u32,
1052 width: u32,
1053 height: u32,
1054 refresh_rate: u32,
1055 id_in: Option<SurfaceId>,
1056 ) -> Result<SurfaceId, CreateSurfaceError> {
1057 let surface = unsafe {
1058 self.instance.create_surface_from_drm(
1059 fd,
1060 plane,
1061 connector_id,
1062 width,
1063 height,
1064 refresh_rate,
1065 )
1066 }?;
1067 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1068
1069 Ok(id)
1070 }
1071
1072 #[cfg(metal)]
1076 pub unsafe fn instance_create_surface_metal(
1077 &self,
1078 layer: *mut core::ffi::c_void,
1079 id_in: Option<SurfaceId>,
1080 ) -> Result<SurfaceId, CreateSurfaceError> {
1081 let surface = unsafe { self.instance.create_surface_metal(layer) }?;
1082 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1083 Ok(id)
1084 }
1085
1086 #[cfg(dx12)]
1087 pub unsafe fn instance_create_surface_from_visual(
1091 &self,
1092 visual: *mut core::ffi::c_void,
1093 id_in: Option<SurfaceId>,
1094 ) -> Result<SurfaceId, CreateSurfaceError> {
1095 let surface = unsafe { self.instance.create_surface_from_visual(visual) }?;
1096 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1097 Ok(id)
1098 }
1099
1100 #[cfg(dx12)]
1101 pub unsafe fn instance_create_surface_from_surface_handle(
1105 &self,
1106 surface_handle: *mut core::ffi::c_void,
1107 id_in: Option<SurfaceId>,
1108 ) -> Result<SurfaceId, CreateSurfaceError> {
1109 let surface = unsafe {
1110 self.instance
1111 .create_surface_from_surface_handle(surface_handle)
1112 }?;
1113 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1114 Ok(id)
1115 }
1116
1117 #[cfg(dx12)]
1118 pub unsafe fn instance_create_surface_from_swap_chain_panel(
1122 &self,
1123 swap_chain_panel: *mut core::ffi::c_void,
1124 id_in: Option<SurfaceId>,
1125 ) -> Result<SurfaceId, CreateSurfaceError> {
1126 let surface = unsafe {
1127 self.instance
1128 .create_surface_from_swap_chain_panel(swap_chain_panel)
1129 }?;
1130 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1131 Ok(id)
1132 }
1133
1134 pub fn surface_drop(&self, id: SurfaceId) {
1135 profiling::scope!("Surface::drop");
1136
1137 api_log!("Surface::drop {id:?}");
1138
1139 self.surfaces.remove(id);
1140 }
1141
1142 pub fn enumerate_adapters(
1143 &self,
1144 backends: Backends,
1145 apply_limit_buckets: bool,
1146 ) -> Vec<AdapterId> {
1147 let adapters = self
1148 .instance
1149 .enumerate_adapters(backends, apply_limit_buckets);
1150 adapters
1151 .into_iter()
1152 .map(|adapter| self.hub.adapters.prepare(None).assign(Arc::new(adapter)))
1153 .collect()
1154 }
1155
1156 pub fn request_adapter(
1157 &self,
1158 desc: &RequestAdapterOptions,
1159 backends: Backends,
1160 id_in: Option<AdapterId>,
1161 ) -> Result<AdapterId, wgt::RequestAdapterError> {
1162 let compatible_surface = desc.compatible_surface.map(|id| self.surfaces.get(id));
1163 let desc = wgt::RequestAdapterOptions {
1164 power_preference: desc.power_preference,
1165 force_fallback_adapter: desc.force_fallback_adapter,
1166 compatible_surface: compatible_surface.as_deref(),
1167 apply_limit_buckets: desc.apply_limit_buckets,
1168 };
1169 let adapter = self.instance.request_adapter(&desc, backends)?;
1170 let id = self.hub.adapters.prepare(id_in).assign(Arc::new(adapter));
1171 Ok(id)
1172 }
1173
1174 pub unsafe fn create_adapter_from_hal(
1188 &self,
1189 hal_adapter: hal::DynExposedAdapter,
1190 input: Option<AdapterId>,
1191 ) -> AdapterId {
1192 profiling::scope!("Instance::create_adapter_from_hal");
1193
1194 let fid = self.hub.adapters.prepare(input);
1195 let id = fid.assign(Arc::new(Adapter::new(hal_adapter)));
1196
1197 resource_log!("Created Adapter {:?}", id);
1198 id
1199 }
1200
1201 pub fn adapter_get_info(&self, adapter_id: AdapterId) -> wgt::AdapterInfo {
1202 let adapter = self.hub.adapters.get(adapter_id);
1203 adapter.get_info()
1204 }
1205
1206 pub fn adapter_get_texture_format_features(
1207 &self,
1208 adapter_id: AdapterId,
1209 format: wgt::TextureFormat,
1210 ) -> wgt::TextureFormatFeatures {
1211 let adapter = self.hub.adapters.get(adapter_id);
1212 adapter.get_texture_format_features(format)
1213 }
1214
1215 pub fn adapter_features(&self, adapter_id: AdapterId) -> wgt::Features {
1216 let adapter = self.hub.adapters.get(adapter_id);
1217 adapter.features()
1218 }
1219
1220 pub fn adapter_limits(&self, adapter_id: AdapterId) -> wgt::Limits {
1221 let adapter = self.hub.adapters.get(adapter_id);
1222 adapter.limits()
1223 }
1224
1225 pub fn adapter_downlevel_capabilities(
1226 &self,
1227 adapter_id: AdapterId,
1228 ) -> wgt::DownlevelCapabilities {
1229 let adapter = self.hub.adapters.get(adapter_id);
1230 adapter.downlevel_capabilities()
1231 }
1232
1233 pub fn adapter_get_presentation_timestamp(
1234 &self,
1235 adapter_id: AdapterId,
1236 ) -> wgt::PresentationTimestamp {
1237 let adapter = self.hub.adapters.get(adapter_id);
1238 adapter.get_presentation_timestamp()
1239 }
1240
1241 pub fn adapter_cooperative_matrix_properties(
1242 &self,
1243 adapter_id: AdapterId,
1244 ) -> Vec<wgt::CooperativeMatrixProperties> {
1245 let adapter = self.hub.adapters.get(adapter_id);
1246 adapter.cooperative_matrix_properties()
1247 }
1248
1249 pub fn adapter_drop(&self, adapter_id: AdapterId) {
1250 profiling::scope!("Adapter::drop");
1251 api_log!("Adapter::drop {adapter_id:?}");
1252
1253 self.hub.adapters.remove(adapter_id);
1254 }
1255}
1256
1257impl Global {
1258 pub fn adapter_request_device(
1259 &self,
1260 adapter_id: AdapterId,
1261 desc: &DeviceDescriptor,
1262 device_id_in: Option<DeviceId>,
1263 queue_id_in: Option<QueueId>,
1264 ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1265 profiling::scope!("Adapter::request_device");
1266 api_log!("Adapter::request_device");
1267
1268 let device_fid = self.hub.devices.prepare(device_id_in);
1269 let queue_fid = self.hub.queues.prepare(queue_id_in);
1270
1271 let adapter = self.hub.adapters.get(adapter_id);
1272 let (device, queue) = adapter.create_device_and_queue(desc, self.instance.flags)?;
1273
1274 let device_id = device_fid.assign(device);
1275 resource_log!("Created Device {:?}", device_id);
1276
1277 let queue_id = queue_fid.assign(queue);
1278 resource_log!("Created Queue {:?}", queue_id);
1279
1280 Ok((device_id, queue_id))
1281 }
1282
1283 pub unsafe fn create_device_from_hal(
1288 &self,
1289 adapter_id: AdapterId,
1290 hal_device: hal::DynOpenDevice,
1291 desc: &DeviceDescriptor,
1292 device_id_in: Option<DeviceId>,
1293 queue_id_in: Option<QueueId>,
1294 ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1295 profiling::scope!("Global::create_device_from_hal");
1296
1297 let devices_fid = self.hub.devices.prepare(device_id_in);
1298 let queues_fid = self.hub.queues.prepare(queue_id_in);
1299
1300 let adapter = self.hub.adapters.get(adapter_id);
1301 let (device, queue) =
1302 adapter.create_device_and_queue_from_hal(hal_device, desc, self.instance.flags)?;
1303
1304 let device_id = devices_fid.assign(device);
1305 resource_log!("Created Device {:?}", device_id);
1306
1307 let queue_id = queues_fid.assign(queue);
1308 resource_log!("Created Queue {:?}", queue_id);
1309
1310 Ok((device_id, queue_id))
1311 }
1312}
1313
1314fn adapter_allowed(
1319 flags: InstanceFlags,
1320 info: &impl fmt::Debug,
1321 limits: &wgt::Limits,
1322 downlevel: &wgt::DownlevelCapabilities,
1323) -> bool {
1324 let min_uniform_buffer_offset_alignment = limits.min_uniform_buffer_offset_alignment;
1330 if !min_uniform_buffer_offset_alignment.is_power_of_two() {
1331 log::error!(
1332 "Adapter {:?} min_uniform_buffer_offset_alignment limit is not a power of 2: {:?}",
1333 info,
1334 min_uniform_buffer_offset_alignment
1335 );
1336 return false;
1337 }
1338 let min_storage_buffer_offset_alignment = limits.min_storage_buffer_offset_alignment;
1339 if !min_storage_buffer_offset_alignment.is_power_of_two() {
1340 log::error!(
1341 "Adapter {:?} min_storage_buffer_offset_alignment limit is not a power of 2: {:?}",
1342 info,
1343 min_storage_buffer_offset_alignment
1344 );
1345 return false;
1346 }
1347
1348 if !flags.contains(InstanceFlags::STRICT_WEBGPU_COMPLIANCE) {
1350 return true;
1351 }
1352
1353 let mut min_limits = wgt::Limits::defaults();
1355 min_limits.zero_native_only();
1356 let failed_limits = check_limits(&min_limits, limits);
1357 if !failed_limits.is_empty() {
1358 log::debug!(
1359 "Adapter {:?} is not WebGPU compliant due to limits: {:?}",
1360 info,
1361 failed_limits
1362 );
1363 return false;
1364 }
1365
1366 if !downlevel.is_webgpu_compliant() {
1367 let missing_flags = wgt::DownlevelFlags::compliant() - downlevel.flags;
1368 log::debug!(
1369 "Adapter {:?} is not WebGPU compliant due to missing downlevel flags: {:?}",
1370 info,
1371 missing_flags
1372 );
1373 return false;
1374 }
1375
1376 true
1377}
1378
1379fn filter_features_and_limits(
1380 flags: InstanceFlags,
1381 features: &mut wgt::Features,
1382 limits: &mut wgt::Limits,
1383) {
1384 if flags.contains(InstanceFlags::STRICT_WEBGPU_COMPLIANCE) {
1385 *features &= wgt::Features::all_webgpu_mask() | limits::EXEMPT_FEATURES;
1386 limits.zero_native_only();
1387 }
1388}
1389
1390#[cfg(test)]
1391mod tests {
1392 use super::*;
1393
1394 fn compliant_downlevel() -> wgt::DownlevelCapabilities {
1395 wgt::DownlevelCapabilities {
1396 flags: wgt::DownlevelFlags::compliant(),
1397 ..Default::default()
1398 }
1399 }
1400
1401 #[test]
1402 fn non_power_of_two_uniform_alignment_always_rejected() {
1403 let limits = wgt::Limits {
1404 min_uniform_buffer_offset_alignment: 3,
1405 ..wgt::Limits::defaults()
1406 };
1407 assert!(!adapter_allowed(
1408 InstanceFlags::empty(),
1409 &"",
1410 &limits,
1411 &compliant_downlevel()
1412 ));
1413 assert!(!adapter_allowed(
1414 InstanceFlags::STRICT_WEBGPU_COMPLIANCE,
1415 &"",
1416 &limits,
1417 &compliant_downlevel()
1418 ));
1419 }
1420
1421 #[test]
1422 fn non_power_of_two_storage_alignment_always_rejected() {
1423 let limits = wgt::Limits {
1424 min_storage_buffer_offset_alignment: 96,
1425 ..wgt::Limits::defaults()
1426 };
1427 assert!(!adapter_allowed(
1428 InstanceFlags::empty(),
1429 &"",
1430 &limits,
1431 &compliant_downlevel()
1432 ));
1433 assert!(!adapter_allowed(
1434 InstanceFlags::STRICT_WEBGPU_COMPLIANCE,
1435 &"",
1436 &limits,
1437 &compliant_downlevel()
1438 ));
1439 }
1440
1441 #[test]
1442 fn low_limits_allowed_without_strict_compliance() {
1443 let limits = wgt::Limits {
1444 max_texture_dimension_1d: 1,
1445 ..wgt::Limits::defaults()
1446 };
1447 assert!(adapter_allowed(
1448 InstanceFlags::empty(),
1449 &"",
1450 &limits,
1451 &wgt::DownlevelCapabilities::default()
1452 ));
1453 }
1454
1455 #[test]
1456 fn low_limits_rejected_with_strict_compliance() {
1457 let limits = wgt::Limits {
1458 max_texture_dimension_1d: 1,
1459 ..wgt::Limits::defaults()
1460 };
1461 assert!(!adapter_allowed(
1462 InstanceFlags::STRICT_WEBGPU_COMPLIANCE,
1463 &"",
1464 &limits,
1465 &compliant_downlevel()
1466 ));
1467 }
1468
1469 #[test]
1470 fn missing_downlevel_flags_rejected_with_strict_compliance() {
1471 let downlevel = wgt::DownlevelCapabilities {
1472 flags: wgt::DownlevelFlags::empty(),
1473 ..Default::default()
1474 };
1475 assert!(!adapter_allowed(
1476 InstanceFlags::STRICT_WEBGPU_COMPLIANCE,
1477 &"",
1478 &wgt::Limits::defaults(),
1479 &downlevel
1480 ));
1481 }
1482
1483 #[test]
1484 fn fully_compliant_adapter_always_allowed() {
1485 assert!(adapter_allowed(
1486 InstanceFlags::STRICT_WEBGPU_COMPLIANCE,
1487 &"",
1488 &wgt::Limits::defaults(),
1489 &compliant_downlevel()
1490 ));
1491 }
1492}