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::{
10 queue::Queue, resource::Device, DeviceDescriptor, DeviceError, UserClosures, WaitIdleError,
11 },
12 global::Global,
13 id::{markers, AdapterId, DeviceId, QueueId, SurfaceId},
14 limits::{self, check_limits, FailedLimit},
15 lock::{rank, Mutex},
16 present::{ConfigureSurfaceError, Presentation},
17 resource::ResourceType,
18 resource_log,
19 timestamp_normalization::TimestampNormalizerInitError,
20 weak_vec::WeakVec,
21 DOWNLEVEL_WARNING_MESSAGE,
22};
23
24use wgt::{Backend, Backends, InstanceFlags, PowerPreference};
25
26pub type RequestAdapterOptions = wgt::RequestAdapterOptions<SurfaceId>;
27
28#[test]
29fn downlevel_default_limits_less_than_default_limits() {
30 let res = check_limits(&wgt::Limits::downlevel_defaults(), &wgt::Limits::default());
31 assert!(
32 res.is_empty(),
33 "Downlevel limits are greater than default limits",
34 )
35}
36
37#[derive(Debug, Clone)]
38pub(crate) struct InstanceDevices(Arc<Mutex<WeakVec<Device>>>);
39
40impl Default for InstanceDevices {
41 fn default() -> Self {
42 Self::new()
43 }
44}
45
46impl InstanceDevices {
47 pub(crate) fn new() -> Self {
48 Self(Arc::new(Mutex::new(rank::HUB_OTHER, WeakVec::new())))
49 }
50
51 pub(crate) fn push(&self, device: &Arc<Device>) {
52 self.0.lock().push(Arc::downgrade(device));
53 }
54
55 fn poll_all_devices(
62 &self,
63 force_wait: bool,
64 closure_list: &mut UserClosures,
65 ) -> Result<bool, WaitIdleError> {
66 let mut all_queue_empty = true;
67 {
68 let device_guard = self.0.lock();
69
70 for device in device_guard.iter().filter_map(|device| device.upgrade()) {
71 let poll_type = if force_wait {
72 wgt::PollType::wait_indefinitely()
74 } else {
75 wgt::PollType::Poll
76 };
77
78 let (closures, result) = device.poll_and_return_closures(poll_type);
79
80 let is_queue_empty = matches!(result, Ok(wgt::PollStatus::QueueEmpty));
81
82 all_queue_empty &= is_queue_empty;
83
84 closure_list.extend(closures);
85 }
86 }
87
88 Ok(all_queue_empty)
89 }
90}
91
92#[derive(Default)]
93pub struct Instance {
94 _name: String,
95
96 instance_per_backend: Vec<(Backend, Box<dyn hal::DynInstance>)>,
100
101 requested_backends: Backends,
103
104 supported_backends: Backends,
112
113 pub flags: InstanceFlags,
114
115 display: Option<Box<dyn wgt::WgpuHasDisplayHandle>>,
121
122 devices: InstanceDevices,
124}
125
126impl Instance {
127 pub fn new(
128 name: &str,
129 mut instance_desc: wgt::InstanceDescriptor,
130 telemetry: Option<hal::Telemetry>,
131 ) -> Self {
132 let mut this = Self {
133 _name: name.to_owned(),
134 instance_per_backend: Vec::new(),
135 requested_backends: instance_desc.backends,
136 supported_backends: Backends::empty(),
137 flags: instance_desc.flags,
138 display: instance_desc.display.take(),
142 devices: InstanceDevices::new(),
143 };
144
145 #[cfg(all(vulkan, not(target_os = "netbsd")))]
146 this.try_add_hal(hal::api::Vulkan, &instance_desc, telemetry);
147 #[cfg(metal)]
148 this.try_add_hal(hal::api::Metal, &instance_desc, telemetry);
149 #[cfg(dx12)]
150 this.try_add_hal(hal::api::Dx12, &instance_desc, telemetry);
151 #[cfg(gles)]
152 this.try_add_hal(hal::api::Gles, &instance_desc, telemetry);
153 #[cfg(feature = "noop")]
154 this.try_add_hal(hal::api::Noop, &instance_desc, telemetry);
155
156 this
157 }
158
159 fn try_add_hal<A: hal::Api>(
161 &mut self,
162 _: A,
163 instance_desc: &wgt::InstanceDescriptor,
164 telemetry: Option<hal::Telemetry>,
165 ) {
166 self.supported_backends |= A::VARIANT.into();
169
170 if !instance_desc.backends.contains(A::VARIANT.into()) {
171 log::trace!("Instance::new: backend {:?} not requested", A::VARIANT);
172 return;
173 }
174
175 assert!(instance_desc.display.is_none());
177
178 let hal_desc = hal::InstanceDescriptor {
179 name: "wgpu",
180 flags: self.flags,
181 memory_budget_thresholds: instance_desc.memory_budget_thresholds,
182 backend_options: instance_desc.backend_options.clone(),
183 telemetry,
184 display: self.display.as_ref().map(|hdh| {
187 hdh.display_handle()
188 .expect("Implementation did not provide a DisplayHandle")
189 }),
190 };
191
192 use hal::Instance as _;
193 match unsafe { A::Instance::init(&hal_desc) } {
195 Ok(instance) => {
196 log::debug!("Instance::new: created {:?} backend", A::VARIANT);
197 self.instance_per_backend
198 .push((A::VARIANT, Box::new(instance)));
199 }
200 Err(err) => {
201 log::debug!(
202 "Instance::new: failed to create {:?} backend: {:?}",
203 A::VARIANT,
204 err
205 );
206 }
207 }
208 }
209
210 pub(crate) fn from_hal_instance<A: hal::Api>(
211 name: String,
212 hal_instance: <A as hal::Api>::Instance,
213 ) -> Self {
214 Self {
215 _name: name,
216 instance_per_backend: vec![(A::VARIANT, Box::new(hal_instance))],
217 requested_backends: A::VARIANT.into(),
218 supported_backends: A::VARIANT.into(),
219 flags: InstanceFlags::default(),
220 display: None, devices: InstanceDevices::new(),
222 }
223 }
224
225 pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynInstance> {
226 self.instance_per_backend
227 .iter()
228 .find_map(|(instance_backend, instance)| {
229 (*instance_backend == backend).then(|| instance.as_ref())
230 })
231 }
232
233 pub unsafe fn as_hal<A: hal::Api>(&self) -> Option<&A::Instance> {
237 self.raw(A::VARIANT).map(|instance| {
238 instance
239 .as_any()
240 .downcast_ref()
241 .expect("Stored instance is not of the correct type")
243 })
244 }
245
246 pub unsafe fn create_surface(
262 &self,
263 display_handle: Option<raw_window_handle::RawDisplayHandle>,
264 window_handle: raw_window_handle::RawWindowHandle,
265 ) -> Result<Surface, CreateSurfaceError> {
266 profiling::scope!("Instance::create_surface");
267
268 let instance_display_handle = self.display.as_ref().map(|d| {
269 d.display_handle()
270 .expect("Implementation did not provide a DisplayHandle")
271 .as_raw()
272 });
273 let display_handle = match (instance_display_handle, display_handle) {
274 (Some(a), Some(b)) => {
275 if a != b {
276 return Err(CreateSurfaceError::MismatchingDisplayHandle);
277 }
278 a
279 }
280 (Some(hnd), None) => hnd,
281 (None, Some(hnd)) => hnd,
282 (None, None) => return Err(CreateSurfaceError::MissingDisplayHandle),
283 };
284
285 let mut errors = HashMap::default();
286 let mut surface_per_backend = HashMap::default();
287
288 for (backend, instance) in &self.instance_per_backend {
289 match unsafe {
290 instance
291 .as_ref()
292 .create_surface(display_handle, window_handle)
293 } {
294 Ok(raw) => {
295 surface_per_backend.insert(*backend, raw);
296 }
297 Err(err) => {
298 log::debug!(
299 "Instance::create_surface: failed to create surface for {backend:?}: {err:?}"
300 );
301 errors.insert(*backend, err);
302 }
303 }
304 }
305
306 if surface_per_backend.is_empty() {
307 Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
308 errors,
309 ))
310 } else {
311 let surface = Surface {
312 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
313 surface_per_backend,
314 };
315
316 Ok(surface)
317 }
318 }
319
320 #[cfg(drm)]
332 #[cfg_attr(not(vulkan), expect(unused_variables, unused_mut))]
333 pub unsafe fn create_surface_from_drm(
334 &self,
335 fd: i32,
336 plane: u32,
337 connector_id: u32,
338 width: u32,
339 height: u32,
340 refresh_rate: u32,
341 ) -> Result<Surface, CreateSurfaceError> {
342 profiling::scope!("Instance::create_surface_from_drm");
343
344 let mut errors = HashMap::default();
345 let mut surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>> =
346 HashMap::default();
347
348 #[cfg(vulkan)]
349 {
350 let instance = unsafe { self.as_hal::<hal::api::Vulkan>() }
351 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Vulkan))?;
352
353 match unsafe {
355 instance.create_surface_from_drm(
356 fd,
357 plane,
358 connector_id,
359 width,
360 height,
361 refresh_rate,
362 )
363 } {
364 Ok(surface) => {
365 surface_per_backend.insert(Backend::Vulkan, Box::new(surface));
366 }
367 Err(err) => {
368 errors.insert(Backend::Vulkan, err);
369 }
370 }
371 }
372
373 if surface_per_backend.is_empty() {
374 Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
375 errors,
376 ))
377 } else {
378 let surface = Surface {
379 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
380 surface_per_backend,
381 };
382
383 Ok(surface)
384 }
385 }
386
387 #[cfg(metal)]
391 pub unsafe fn create_surface_metal(
392 &self,
393 layer: *mut core::ffi::c_void,
394 ) -> Result<Surface, CreateSurfaceError> {
395 profiling::scope!("Instance::create_surface_metal");
396
397 let instance = unsafe { self.as_hal::<hal::api::Metal>() }
398 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Metal))?;
399
400 let layer = layer.cast();
401 let layer = unsafe { &*layer };
413 let raw_surface: Box<dyn hal::DynSurface> =
414 Box::new(instance.create_surface_from_layer(layer));
415
416 let surface = Surface {
417 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
418 surface_per_backend: core::iter::once((Backend::Metal, raw_surface)).collect(),
419 };
420
421 Ok(surface)
422 }
423
424 #[cfg(dx12)]
425 fn create_surface_dx12(
426 &self,
427 create_surface_func: impl FnOnce(&hal::dx12::Instance) -> hal::dx12::Surface,
428 ) -> Result<Surface, CreateSurfaceError> {
429 let instance = unsafe { self.as_hal::<hal::api::Dx12>() }
430 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Dx12))?;
431 let surface: Box<dyn hal::DynSurface> = Box::new(create_surface_func(instance));
432
433 let surface = Surface {
434 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
435 surface_per_backend: core::iter::once((Backend::Dx12, surface)).collect(),
436 };
437
438 Ok(surface)
439 }
440
441 #[cfg(dx12)]
442 pub unsafe fn create_surface_from_visual(
446 &self,
447 visual: *mut core::ffi::c_void,
448 ) -> Result<Surface, CreateSurfaceError> {
449 profiling::scope!("Instance::instance_create_surface_from_visual");
450 self.create_surface_dx12(|inst| unsafe { inst.create_surface_from_visual(visual) })
451 }
452
453 #[cfg(dx12)]
454 pub unsafe fn create_surface_from_surface_handle(
458 &self,
459 surface_handle: *mut core::ffi::c_void,
460 ) -> Result<Surface, CreateSurfaceError> {
461 profiling::scope!("Instance::instance_create_surface_from_surface_handle");
462 self.create_surface_dx12(|inst| unsafe {
463 inst.create_surface_from_surface_handle(surface_handle)
464 })
465 }
466
467 #[cfg(dx12)]
468 pub unsafe fn create_surface_from_swap_chain_panel(
472 &self,
473 swap_chain_panel: *mut core::ffi::c_void,
474 ) -> Result<Surface, CreateSurfaceError> {
475 profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel");
476 self.create_surface_dx12(|inst| unsafe {
477 inst.create_surface_from_swap_chain_panel(swap_chain_panel)
478 })
479 }
480
481 fn adapter_allowed(&self, raw: &hal::DynExposedAdapter) -> bool {
482 adapter_allowed(
483 self.flags,
484 &raw.info,
485 &raw.capabilities.limits,
486 &raw.capabilities.downlevel,
487 )
488 }
489
490 pub fn enumerate_adapters(
491 &self,
492 backends: Backends,
493 apply_limit_buckets: bool,
494 ) -> Vec<Arc<Adapter>> {
495 profiling::scope!("Instance::enumerate_adapters");
496 api_log!("Instance::enumerate_adapters");
497
498 let mut adapters = Vec::new();
499 for (_backend, instance) in self
500 .instance_per_backend
501 .iter()
502 .filter(|(backend, _)| backends.contains(Backends::from(*backend)))
503 {
504 profiling::scope!("enumerating", &*alloc::format!("{_backend:?}"));
507
508 let hal_adapters = unsafe { instance.enumerate_adapters(None) };
509
510 adapters.extend(
511 hal_adapters
512 .into_iter()
513 .map(|mut raw| {
514 self.adjust_limits_for_indirect_validation(&mut raw.capabilities.limits);
515 raw
516 })
517 .map(|mut raw| {
518 filter_features_and_limits(
519 self.flags,
520 &mut raw.features,
521 &mut raw.capabilities.limits,
522 );
523 raw
524 })
525 .filter(|raw| self.adapter_allowed(raw))
526 .filter_map(|raw| {
527 if apply_limit_buckets {
528 limits::apply_limit_buckets(raw)
529 } else {
530 Some(raw)
531 }
532 })
533 .map(|raw| {
534 let adapter = Adapter::new(raw, self.devices.clone());
535 api_log_debug!("Adapter {:?}", adapter.raw.info);
536 adapter
537 }),
538 );
539 }
540 adapters
541 }
542
543 pub fn request_adapter(
544 &self,
545 desc: &wgt::RequestAdapterOptions<&Surface>,
546 backends: Backends,
547 ) -> Result<Arc<Adapter>, wgt::RequestAdapterError> {
548 profiling::scope!("Instance::request_adapter");
549 api_log!("Instance::request_adapter");
550
551 let mut adapters = Vec::new();
552 let mut incompatible_surface_backends = Backends::empty();
553 let mut no_fallback_backends = Backends::empty();
554 let mut no_adapter_backends = Backends::empty();
555
556 for &(backend, ref instance) in self
557 .instance_per_backend
558 .iter()
559 .filter(|&&(backend, _)| backends.contains(Backends::from(backend)))
560 {
561 let compatible_hal_surface = desc
562 .compatible_surface
563 .and_then(|surface| surface.raw(backend));
564
565 let mut backend_adapters =
566 unsafe { instance.enumerate_adapters(compatible_hal_surface) };
567 if backend_adapters.is_empty() {
568 log::debug!("enabled backend `{backend:?}` has no adapters");
569 no_adapter_backends |= Backends::from(backend);
570 continue;
572 }
573
574 if desc.force_fallback_adapter {
575 log::debug!("Filtering `{backend:?}` for `force_fallback_adapter`");
576 backend_adapters.retain(|exposed| {
577 let keep = exposed.info.device_type == wgt::DeviceType::Cpu;
578 if !keep {
579 log::debug!("* Eliminating adapter `{}`", exposed.info.name);
580 }
581 keep
582 });
583 if backend_adapters.is_empty() {
584 log::debug!("* Backend `{backend:?}` has no fallback adapters");
585 no_fallback_backends |= Backends::from(backend);
586 continue;
587 }
588 }
589
590 if let Some(surface) = desc.compatible_surface {
591 backend_adapters.retain(|exposed| {
592 let capabilities = surface.get_capabilities_with_raw(exposed);
593 if let Err(err) = capabilities {
594 log::debug!(
595 "Adapter {:?} not compatible with surface: {}",
596 exposed.info,
597 err
598 );
599 incompatible_surface_backends |= Backends::from(backend);
600 false
601 } else {
602 true
603 }
604 });
605 if backend_adapters.is_empty() {
606 incompatible_surface_backends |= Backends::from(backend);
607 continue;
608 }
609 }
610
611 let backend_adapters = backend_adapters
612 .into_iter()
613 .map(|mut raw| {
614 self.adjust_limits_for_indirect_validation(&mut raw.capabilities.limits);
615 raw
616 })
617 .map(|mut raw| {
618 filter_features_and_limits(
619 self.flags,
620 &mut raw.features,
621 &mut raw.capabilities.limits,
622 );
623 raw
624 })
625 .filter(|raw| self.adapter_allowed(raw));
626
627 if desc.apply_limit_buckets {
628 adapters.extend(backend_adapters.filter_map(limits::apply_limit_buckets));
629 } else {
630 adapters.extend(backend_adapters);
631 }
632 }
633
634 match desc.power_preference {
635 PowerPreference::LowPower => {
636 sort(&mut adapters, true);
637 }
638 PowerPreference::HighPerformance => {
639 sort(&mut adapters, false);
640 }
641 PowerPreference::None => {}
642 };
643
644 fn sort(adapters: &mut [hal::DynExposedAdapter], prefer_integrated_gpu: bool) {
645 adapters
646 .sort_by_key(|adapter| get_order(adapter.info.device_type, prefer_integrated_gpu));
647 }
648
649 fn get_order(device_type: wgt::DeviceType, prefer_integrated_gpu: bool) -> u8 {
650 match device_type {
658 wgt::DeviceType::DiscreteGpu if prefer_integrated_gpu => 2,
659 wgt::DeviceType::IntegratedGpu if prefer_integrated_gpu => 1,
660 wgt::DeviceType::DiscreteGpu => 1,
661 wgt::DeviceType::IntegratedGpu => 2,
662 wgt::DeviceType::Other => 3,
663 wgt::DeviceType::VirtualGpu => 4,
664 wgt::DeviceType::Cpu => 5,
665 }
666 }
667
668 if adapters.is_empty() {
671 log::debug!("Request adapter didn't find compatible adapters.");
672 } else {
673 log::debug!(
674 "Found {} compatible adapters. Sorted by preference:",
675 adapters.len()
676 );
677 for adapter in &adapters {
678 log::debug!("* {:?}", adapter.info);
679 }
680 }
681
682 if let Some(adapter) = adapters.into_iter().next() {
683 api_log_debug!("Request adapter result {:?}", adapter.info);
684 let adapter = Adapter::new(adapter, self.devices.clone());
685 Ok(adapter)
686 } else {
687 Err(wgt::RequestAdapterError::NotFound {
688 supported_backends: self.supported_backends,
689 requested_backends: self.requested_backends,
690 active_backends: self.active_backends(),
691 no_fallback_backends,
692 no_adapter_backends,
693 incompatible_surface_backends,
694 })
695 }
696 }
697
698 fn adjust_limits_for_indirect_validation(&self, limits: &mut wgt::Limits) {
701 if self.flags.contains(InstanceFlags::VALIDATION_INDIRECT_CALL) {
704 limits.max_buffer_size = limits.max_buffer_size.min(u32::MAX as u64);
705 limits.max_uniform_buffer_binding_size =
706 limits.max_uniform_buffer_binding_size.min(u32::MAX as u64);
707 limits.max_storage_buffer_binding_size = limits
708 .max_storage_buffer_binding_size
709 .min(u32::MAX as u64 & !(wgt::STORAGE_BINDING_SIZE_ALIGNMENT as u64 - 1));
710 }
711 }
712
713 fn active_backends(&self) -> Backends {
714 self.instance_per_backend
715 .iter()
716 .map(|&(backend, _)| Backends::from(backend))
717 .collect()
718 }
719
720 pub unsafe fn create_adapter_from_hal(
734 &self,
735 hal_adapter: hal::DynExposedAdapter,
736 ) -> Arc<Adapter> {
737 profiling::scope!("Instance::create_adapter_from_hal");
738
739 let adapter = Adapter::new(hal_adapter, self.devices.clone());
740
741 resource_log!("Created Adapter {:?}", Arc::as_ptr(&adapter));
742 adapter
743 }
744
745 pub fn poll_all_devices(&self, force_wait: bool) -> Result<bool, WaitIdleError> {
752 api_log!("poll_all_devices");
753 let mut closures = UserClosures::default();
754 let all_queue_empty = self.devices.poll_all_devices(force_wait, &mut closures)?;
755
756 closures.fire();
757
758 Ok(all_queue_empty)
759 }
760}
761
762pub struct Surface {
763 pub(crate) presentation: Mutex<Option<Presentation>>,
764 pub surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>>,
765}
766
767impl ResourceType for Surface {
768 const TYPE: &'static str = "Surface";
769}
770impl crate::storage::StorageItem for Surface {
771 type Marker = markers::Surface;
772}
773
774impl Surface {
775 pub fn get_capabilities(
776 &self,
777 adapter: &Adapter,
778 ) -> Result<wgt::SurfaceCapabilities, GetSurfaceSupportError> {
779 profiling::scope!("Surface::get_capabilities");
780 let mut hal_caps = self.get_hal_capabilities(adapter)?;
781
782 hal_caps
783 .formats
784 .sort_by_key(|fc| !fc.format.has_srgb_suffix());
785
786 let usages = crate::conv::map_texture_usage_from_hal(hal_caps.usage);
787
788 Ok(wgt::SurfaceCapabilities {
794 formats: hal_caps
795 .formats
796 .iter()
797 .filter(|fc| {
798 crate::device::surface_config::resolve_auto_color_space(
799 fc.format,
800 fc.color_spaces,
801 )
802 .is_some()
803 })
804 .map(|fc| fc.format)
805 .collect(),
806 format_capabilities: hal_caps.formats,
807 present_modes: hal_caps.present_modes,
808 alpha_modes: hal_caps.composite_alpha_modes,
809 usages,
810 })
811 }
812
813 pub fn get_hal_capabilities(
814 &self,
815 adapter: &Adapter,
816 ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
817 self.get_capabilities_with_raw(&adapter.raw)
818 }
819
820 pub fn get_capabilities_with_raw(
821 &self,
822 adapter: &hal::DynExposedAdapter,
823 ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
824 let backend = adapter.backend();
825 let suf = self
826 .raw(backend)
827 .ok_or(GetSurfaceSupportError::NotSupportedByBackend(backend))?;
828 profiling::scope!("surface_capabilities");
829 let caps = unsafe { adapter.adapter.surface_capabilities(suf) }
830 .ok_or(GetSurfaceSupportError::FailedToRetrieveSurfaceCapabilitiesForAdapter)?;
831 Ok(caps)
832 }
833
834 pub fn display_hdr_info(&self, adapter: &Adapter) -> wgt::DisplayHdrInfo {
840 profiling::scope!("Surface::display_hdr_info");
841 self.display_hdr_info_with_raw(&adapter.raw)
842 }
843
844 pub fn display_hdr_info_with_raw(
845 &self,
846 adapter: &hal::DynExposedAdapter,
847 ) -> wgt::DisplayHdrInfo {
848 let backend = adapter.backend();
849 let Some(suf) = self.raw(backend) else {
850 return wgt::DisplayHdrInfo::default();
851 };
852 profiling::scope!("surface_display_hdr_info");
853 unsafe { adapter.adapter.surface_display_hdr_info(suf) }.unwrap_or_default()
854 }
855
856 pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynSurface> {
857 self.surface_per_backend
858 .get(&backend)
859 .map(|surface| surface.as_ref())
860 }
861
862 pub fn configure(
863 self: &Arc<Self>,
864 device: &Arc<Device>,
865 config: &wgt::SurfaceConfiguration<Vec<wgt::TextureFormat>>,
866 ) -> Option<ConfigureSurfaceError> {
867 use ConfigureSurfaceError as E;
868 profiling::scope!("Surface::configure");
869
870 #[cfg(feature = "trace")]
871 if let Some(ref mut trace) = *device.trace.lock() {
872 use crate::device::trace::{Action, IntoTrace};
873
874 trace.add(Action::ConfigureSurface(self.to_trace(), config.clone()));
875 }
876
877 log::debug!("configuring surface with {config:?}");
878
879 let error = 'error: {
880 let user_callbacks;
882 {
883 if let Err(e) = device.check_is_valid() {
884 break 'error e.into();
885 }
886
887 let caps = match self.get_hal_capabilities(&device.adapter) {
888 Ok(caps) => caps,
889 Err(_) => break 'error E::UnsupportedQueueFamily,
890 };
891
892 let mut hal_view_formats = Vec::new();
893 for format in config.view_formats.iter() {
894 if *format == config.format {
895 continue;
896 }
897 if !caps.formats.iter().any(|fc| fc.format == config.format) {
898 break 'error E::UnsupportedFormat {
899 requested: config.format,
900 available: caps.texture_formats().collect(),
901 };
902 }
903 if config.format.remove_srgb_suffix() != format.remove_srgb_suffix() {
904 break 'error E::InvalidViewFormat(*format, config.format);
905 }
906 hal_view_formats.push(*format);
907 }
908
909 if !hal_view_formats.is_empty() {
910 if let Err(missing_flag) =
911 device.require_downlevel_flags(wgt::DownlevelFlags::SURFACE_VIEW_FORMATS)
912 {
913 break 'error E::MissingDownlevelFlags(missing_flag);
914 }
915 }
916
917 let maximum_frame_latency = config.desired_maximum_frame_latency.clamp(
918 *caps.maximum_frame_latency.start(),
919 *caps.maximum_frame_latency.end(),
920 );
921 let mut hal_config = hal::SurfaceConfiguration {
922 maximum_frame_latency,
923 present_mode: config.present_mode,
924 composite_alpha_mode: config.alpha_mode,
925 format: config.format,
926 color_space: config.color_space,
927 extent: wgt::Extent3d {
928 width: config.width,
929 height: config.height,
930 depth_or_array_layers: 1,
931 },
932 usage: crate::conv::map_texture_usage(
933 config.usage,
934 hal::FormatAspects::COLOR,
935 wgt::TextureFormatFeatureFlags::STORAGE_READ_ONLY
936 | wgt::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY
937 | wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE,
938 ),
939 view_formats: hal_view_formats,
940 };
941
942 if let Err(error) = crate::device::surface_config::validate_surface_configuration(
943 &mut hal_config,
944 &caps,
945 device.limits.max_texture_dimension_2d,
946 ) {
947 break 'error error;
948 }
949
950 let snatch_guard = device.snatchable_lock.read();
952
953 let maintain_result;
954 (user_callbacks, maintain_result) =
955 device.maintain(wgt::PollType::wait_indefinitely(), snatch_guard);
956
957 match maintain_result {
958 Ok(wgt::PollStatus::QueueEmpty) => {}
960 Ok(wgt::PollStatus::WaitSucceeded) => {
961 break 'error E::GpuWaitTimeout;
964 }
965 Ok(wgt::PollStatus::Poll) => {
966 unreachable!("Cannot get a Poll result from a Wait action.")
967 }
968 Err(WaitIdleError::Timeout) if cfg!(target_family = "wasm") => {
969 }
974 Err(e) => {
975 break 'error e.into();
976 }
977 }
978
979 if let Some(present) = self.presentation.lock().take() {
981 if present.acquired_texture.is_some() {
982 break 'error E::PreviousOutputExists;
983 }
984 }
985
986 let surface_raw = self.raw(device.backend()).unwrap();
993 match unsafe { surface_raw.configure(device.raw(), &hal_config) } {
994 Ok(()) => (),
995 Err(error) => {
996 break 'error match error {
997 hal::SurfaceError::Outdated
998 | hal::SurfaceError::Lost
999 | hal::SurfaceError::Occluded
1000 | hal::SurfaceError::Timeout => E::InvalidSurface,
1001 hal::SurfaceError::Device(error) => {
1002 E::Device(device.handle_hal_error(error))
1003 }
1004 hal::SurfaceError::Other(message) => {
1005 log::error!("surface configuration failed: {message}");
1006 E::InvalidSurface
1007 }
1008 }
1009 }
1010 }
1011
1012 let mut presentation = self.presentation.lock();
1013 *presentation = Some(Presentation {
1014 device: Arc::clone(device),
1015 config: config.clone(),
1016 acquired_texture: None,
1017 });
1018 }
1019
1020 user_callbacks.fire();
1021 return None;
1022 };
1023
1024 Some(error)
1025 }
1026}
1027
1028impl Drop for Surface {
1029 #[allow(trivial_casts)]
1030 fn drop(&mut self) {
1031 profiling::scope!("Surface::drop");
1032
1033 api_log!("Surface::drop {:?}", self as *const _);
1034 if let Some(present) = self.presentation.lock().take() {
1035 for (&backend, surface) in &self.surface_per_backend {
1036 if backend == present.device.backend() {
1037 unsafe { surface.unconfigure(present.device.raw()) };
1038 }
1039 }
1040 }
1041 }
1042}
1043
1044pub struct Adapter {
1045 pub(crate) raw: hal::DynExposedAdapter,
1046 pub(crate) devices: InstanceDevices,
1047}
1048
1049impl Adapter {
1050 pub(crate) fn new(raw: hal::DynExposedAdapter, devices: InstanceDevices) -> Arc<Self> {
1051 Arc::new(Self { raw, devices })
1052 }
1053
1054 pub fn backend(&self) -> Backend {
1056 self.raw.backend()
1057 }
1058
1059 pub fn is_surface_supported(&self, surface: &Surface) -> bool {
1060 surface.get_hal_capabilities(self).is_ok()
1065 }
1066
1067 pub fn get_info(&self) -> wgt::AdapterInfo {
1068 self.raw.info.clone()
1069 }
1070
1071 pub fn features(&self) -> wgt::Features {
1072 self.raw.features
1073 }
1074
1075 pub fn limits(&self) -> wgt::Limits {
1076 self.raw.capabilities.limits.clone()
1077 }
1078
1079 pub fn downlevel_capabilities(&self) -> wgt::DownlevelCapabilities {
1080 self.raw.capabilities.downlevel.clone()
1081 }
1082
1083 pub fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
1084 unsafe { self.raw.adapter.get_presentation_timestamp() }
1085 }
1086
1087 pub fn cooperative_matrix_properties(&self) -> Vec<wgt::CooperativeMatrixProperties> {
1088 self.raw.capabilities.cooperative_matrix_properties.clone()
1089 }
1090
1091 pub fn get_texture_format_features(
1092 &self,
1093 format: wgt::TextureFormat,
1094 ) -> wgt::TextureFormatFeatures {
1095 use hal::TextureFormatCapabilities as Tfc;
1096
1097 let caps = unsafe { self.raw.adapter.texture_format_capabilities(format) };
1098 let mut allowed_usages = wgt::TextureUsages::empty();
1099
1100 allowed_usages.set(wgt::TextureUsages::COPY_SRC, caps.contains(Tfc::COPY_SRC));
1101 allowed_usages.set(wgt::TextureUsages::COPY_DST, caps.contains(Tfc::COPY_DST));
1102 allowed_usages.set(
1103 wgt::TextureUsages::TEXTURE_BINDING,
1104 caps.contains(Tfc::SAMPLED),
1105 );
1106 allowed_usages.set(
1107 wgt::TextureUsages::STORAGE_BINDING,
1108 caps.intersects(
1109 Tfc::STORAGE_WRITE_ONLY
1110 | Tfc::STORAGE_READ_ONLY
1111 | Tfc::STORAGE_READ_WRITE
1112 | Tfc::STORAGE_ATOMIC,
1113 ),
1114 );
1115 allowed_usages.set(
1116 wgt::TextureUsages::RENDER_ATTACHMENT | wgt::TextureUsages::TRANSIENT_ATTACHMENT,
1117 caps.intersects(Tfc::COLOR_ATTACHMENT | Tfc::DEPTH_STENCIL_ATTACHMENT),
1118 );
1119 allowed_usages.set(
1120 wgt::TextureUsages::STORAGE_ATOMIC,
1121 caps.contains(Tfc::STORAGE_ATOMIC),
1122 );
1123
1124 let mut flags = wgt::TextureFormatFeatureFlags::empty();
1125 flags.set(
1126 wgt::TextureFormatFeatureFlags::STORAGE_READ_ONLY,
1127 caps.contains(Tfc::STORAGE_READ_ONLY),
1128 );
1129 flags.set(
1130 wgt::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY,
1131 caps.contains(Tfc::STORAGE_WRITE_ONLY),
1132 );
1133 flags.set(
1134 wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE,
1135 caps.contains(Tfc::STORAGE_READ_WRITE),
1136 );
1137
1138 flags.set(
1139 wgt::TextureFormatFeatureFlags::STORAGE_ATOMIC,
1140 caps.contains(Tfc::STORAGE_ATOMIC),
1141 );
1142
1143 flags.set(
1144 wgt::TextureFormatFeatureFlags::FILTERABLE,
1145 caps.contains(Tfc::SAMPLED_LINEAR),
1146 );
1147
1148 flags.set(
1149 wgt::TextureFormatFeatureFlags::BLENDABLE,
1150 caps.contains(Tfc::COLOR_ATTACHMENT_BLEND),
1151 );
1152
1153 flags.set(
1154 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X2,
1155 caps.contains(Tfc::MULTISAMPLE_X2),
1156 );
1157 flags.set(
1158 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X4,
1159 caps.contains(Tfc::MULTISAMPLE_X4),
1160 );
1161 flags.set(
1162 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X8,
1163 caps.contains(Tfc::MULTISAMPLE_X8),
1164 );
1165 flags.set(
1166 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X16,
1167 caps.contains(Tfc::MULTISAMPLE_X16),
1168 );
1169
1170 flags.set(
1171 wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE,
1172 caps.contains(Tfc::MULTISAMPLE_RESOLVE),
1173 );
1174
1175 wgt::TextureFormatFeatures {
1176 allowed_usages,
1177 flags,
1178 }
1179 }
1180
1181 pub unsafe fn create_device_and_queue_from_hal(
1186 self: &Arc<Self>,
1187 hal_device: hal::DynOpenDevice,
1188 desc: &DeviceDescriptor,
1189 instance_flags: InstanceFlags,
1190 ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
1191 profiling::scope!("Adapter::create_device_and_queue_from_hal");
1192 api_log!("Adapter::create_device_and_queue_from_hal");
1193
1194 let device = Device::new(hal_device.device, self, desc, instance_flags)?;
1195 let device = Arc::new(device);
1196
1197 let queue = Queue::new(device.clone(), hal_device.queue, instance_flags)?;
1198 let queue = Arc::new(queue);
1199
1200 device.set_queue(&queue);
1201 device.late_init_resources_with_queue()?;
1202
1203 resource_log!("Created Device {:?}", Arc::as_ptr(&device));
1204 resource_log!("Created Queue {:?}", Arc::as_ptr(&queue));
1205
1206 self.devices.push(&device);
1207
1208 Ok((device, queue))
1209 }
1210
1211 pub fn request_device(
1212 self: &Arc<Self>,
1213 desc: &DeviceDescriptor,
1214 instance_flags: InstanceFlags,
1215 ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
1216 profiling::scope!("Adapter::request_device");
1217 api_log!("Adapter::request_device");
1218 let mut desc = desc.clone();
1219 filter_features_and_limits(
1220 instance_flags,
1221 &mut desc.required_features,
1222 &mut desc.required_limits,
1223 );
1224
1225 if !self.raw.features.contains(desc.required_features) {
1227 return Err(RequestDeviceError::UnsupportedFeature(
1228 desc.required_features - self.raw.features,
1229 ));
1230 }
1231
1232 if desc
1234 .required_features
1235 .intersects(wgt::Features::all_experimental_mask())
1236 && !desc.experimental_features.is_enabled()
1237 {
1238 return Err(RequestDeviceError::ExperimentalFeaturesNotEnabled(
1239 desc.required_features
1240 .intersection(wgt::Features::all_experimental_mask()),
1241 ));
1242 }
1243
1244 let caps = &self.raw.capabilities;
1245 if Backends::PRIMARY.contains(Backends::from(self.backend()))
1246 && !caps.downlevel.is_webgpu_compliant()
1247 {
1248 let missing_flags = wgt::DownlevelFlags::compliant() - caps.downlevel.flags;
1249 log::warn!("Missing downlevel flags: {missing_flags:?}\n{DOWNLEVEL_WARNING_MESSAGE}");
1250 log::warn!("{:#?}", caps.downlevel);
1251 }
1252
1253 if desc
1255 .required_features
1256 .contains(wgt::Features::MAPPABLE_PRIMARY_BUFFERS)
1257 && self.raw.info.device_type == wgt::DeviceType::DiscreteGpu
1258 {
1259 log::warn!(
1260 "Feature MAPPABLE_PRIMARY_BUFFERS enabled on a discrete gpu. \
1261 This is a massive performance footgun and likely not what you wanted"
1262 );
1263 }
1264
1265 if let Some(failed) = check_limits(&desc.required_limits, &caps.limits).pop() {
1266 return Err(RequestDeviceError::LimitsExceeded(failed));
1267 }
1268
1269 let open = unsafe {
1270 self.raw.adapter.open(
1271 desc.required_features,
1272 &desc.required_limits,
1273 &desc.memory_hints,
1274 )
1275 }
1276 .map_err(DeviceError::from_hal)?;
1277
1278 unsafe { self.create_device_and_queue_from_hal(open, &desc, instance_flags) }
1279 }
1280}
1281
1282impl Drop for Adapter {
1283 #[allow(trivial_casts)]
1284 fn drop(&mut self) {
1285 profiling::scope!("Adapter::drop");
1286 api_log!("Adapter::drop {:?}", self as *const _);
1287 }
1288}
1289
1290crate::impl_resource_type!(Adapter);
1291crate::impl_storage_item!(Adapter);
1292
1293#[derive(Clone, Debug, Error)]
1294#[non_exhaustive]
1295pub enum GetSurfaceSupportError {
1296 #[error("Surface is not supported for the specified backend {0}")]
1297 NotSupportedByBackend(Backend),
1298 #[error("Failed to retrieve surface capabilities for the specified adapter.")]
1299 FailedToRetrieveSurfaceCapabilitiesForAdapter,
1300}
1301
1302#[derive(Clone, Debug, Error)]
1303#[non_exhaustive]
1305pub enum RequestDeviceError {
1306 #[error(transparent)]
1307 Device(#[from] DeviceError),
1308 #[error(transparent)]
1309 LimitsExceeded(#[from] FailedLimit),
1310 #[error("Failed to initialize Timestamp Normalizer")]
1311 TimestampNormalizerInitFailed(#[from] TimestampNormalizerInitError),
1312 #[error("Unsupported features were requested: {0}")]
1313 UnsupportedFeature(wgt::Features),
1314 #[error(
1315 "Some experimental features, {0}, were requested, but experimental features are not enabled"
1316 )]
1317 ExperimentalFeaturesNotEnabled(wgt::Features),
1318}
1319
1320#[derive(Clone, Debug, Error)]
1321#[non_exhaustive]
1322pub enum CreateSurfaceError {
1323 #[error("The backend {0} was not enabled on the instance.")]
1324 BackendNotEnabled(Backend),
1325 #[error("Failed to create surface for any enabled backend: {0:?}")]
1326 FailedToCreateSurfaceForAnyBackend(HashMap<Backend, hal::InstanceError>),
1327 #[error("The display handle used to create this Instance does not match the one used to create a surface on it")]
1328 MismatchingDisplayHandle,
1329 #[error(
1330 "No `DisplayHandle` is available to create this surface with. When creating a surface with `create_surface()` \
1331 you must specify a display handle in `InstanceDescriptor::display`. \
1332 Rarely, if you need to create surfaces from different `DisplayHandle`s (ex. different Wayland or X11 connections), \
1333 you must use `create_surface_unsafe()`."
1334 )]
1335 MissingDisplayHandle,
1336}
1337
1338impl Global {
1339 pub unsafe fn instance_create_surface(
1358 &self,
1359 display_handle: Option<raw_window_handle::RawDisplayHandle>,
1360 window_handle: raw_window_handle::RawWindowHandle,
1361 id_in: Option<SurfaceId>,
1362 ) -> Result<SurfaceId, CreateSurfaceError> {
1363 let surface = unsafe { self.instance.create_surface(display_handle, window_handle) }?;
1364 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1365 Ok(id)
1366 }
1367
1368 #[cfg(drm)]
1380 pub unsafe fn instance_create_surface_from_drm(
1381 &self,
1382 fd: i32,
1383 plane: u32,
1384 connector_id: u32,
1385 width: u32,
1386 height: u32,
1387 refresh_rate: u32,
1388 id_in: Option<SurfaceId>,
1389 ) -> Result<SurfaceId, CreateSurfaceError> {
1390 let surface = unsafe {
1391 self.instance.create_surface_from_drm(
1392 fd,
1393 plane,
1394 connector_id,
1395 width,
1396 height,
1397 refresh_rate,
1398 )
1399 }?;
1400 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1401
1402 Ok(id)
1403 }
1404
1405 #[cfg(metal)]
1409 pub unsafe fn instance_create_surface_metal(
1410 &self,
1411 layer: *mut core::ffi::c_void,
1412 id_in: Option<SurfaceId>,
1413 ) -> Result<SurfaceId, CreateSurfaceError> {
1414 let surface = unsafe { self.instance.create_surface_metal(layer) }?;
1415 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1416 Ok(id)
1417 }
1418
1419 #[cfg(dx12)]
1420 pub unsafe fn instance_create_surface_from_visual(
1424 &self,
1425 visual: *mut core::ffi::c_void,
1426 id_in: Option<SurfaceId>,
1427 ) -> Result<SurfaceId, CreateSurfaceError> {
1428 let surface = unsafe { self.instance.create_surface_from_visual(visual) }?;
1429 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1430 Ok(id)
1431 }
1432
1433 #[cfg(dx12)]
1434 pub unsafe fn instance_create_surface_from_surface_handle(
1438 &self,
1439 surface_handle: *mut core::ffi::c_void,
1440 id_in: Option<SurfaceId>,
1441 ) -> Result<SurfaceId, CreateSurfaceError> {
1442 let surface = unsafe {
1443 self.instance
1444 .create_surface_from_surface_handle(surface_handle)
1445 }?;
1446 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1447 Ok(id)
1448 }
1449
1450 #[cfg(dx12)]
1451 pub unsafe fn instance_create_surface_from_swap_chain_panel(
1455 &self,
1456 swap_chain_panel: *mut core::ffi::c_void,
1457 id_in: Option<SurfaceId>,
1458 ) -> Result<SurfaceId, CreateSurfaceError> {
1459 let surface = unsafe {
1460 self.instance
1461 .create_surface_from_swap_chain_panel(swap_chain_panel)
1462 }?;
1463 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1464 Ok(id)
1465 }
1466
1467 pub fn surface_drop(&self, id: SurfaceId) {
1468 self.surfaces.remove(id);
1469 }
1470
1471 pub fn enumerate_adapters(
1472 &self,
1473 backends: Backends,
1474 apply_limit_buckets: bool,
1475 ) -> Vec<AdapterId> {
1476 let adapters = self
1477 .instance
1478 .enumerate_adapters(backends, apply_limit_buckets);
1479 adapters
1480 .into_iter()
1481 .map(|adapter| self.hub.adapters.prepare(None).assign(adapter))
1482 .collect()
1483 }
1484
1485 pub fn request_adapter(
1486 &self,
1487 desc: &RequestAdapterOptions,
1488 backends: Backends,
1489 id_in: Option<AdapterId>,
1490 ) -> Result<AdapterId, wgt::RequestAdapterError> {
1491 let compatible_surface = desc.compatible_surface.map(|id| self.surfaces.get(id));
1492 let desc = wgt::RequestAdapterOptions {
1493 power_preference: desc.power_preference,
1494 force_fallback_adapter: desc.force_fallback_adapter,
1495 compatible_surface: compatible_surface.as_deref(),
1496 apply_limit_buckets: desc.apply_limit_buckets,
1497 };
1498 let adapter = self.instance.request_adapter(&desc, backends)?;
1499 let id = self.hub.adapters.prepare(id_in).assign(adapter);
1500 Ok(id)
1501 }
1502
1503 pub unsafe fn create_adapter_from_hal(
1517 &self,
1518 hal_adapter: hal::DynExposedAdapter,
1519 input: Option<AdapterId>,
1520 ) -> AdapterId {
1521 let fid = self.hub.adapters.prepare(input);
1522 fid.assign(unsafe { self.instance.create_adapter_from_hal(hal_adapter) })
1523 }
1524
1525 pub fn adapter_get_info(&self, adapter_id: AdapterId) -> wgt::AdapterInfo {
1526 let adapter = self.hub.adapters.get(adapter_id);
1527 adapter.get_info()
1528 }
1529
1530 pub fn adapter_get_texture_format_features(
1531 &self,
1532 adapter_id: AdapterId,
1533 format: wgt::TextureFormat,
1534 ) -> wgt::TextureFormatFeatures {
1535 let adapter = self.hub.adapters.get(adapter_id);
1536 adapter.get_texture_format_features(format)
1537 }
1538
1539 pub fn adapter_features(&self, adapter_id: AdapterId) -> wgt::Features {
1540 let adapter = self.hub.adapters.get(adapter_id);
1541 adapter.features()
1542 }
1543
1544 pub fn adapter_limits(&self, adapter_id: AdapterId) -> wgt::Limits {
1545 let adapter = self.hub.adapters.get(adapter_id);
1546 adapter.limits()
1547 }
1548
1549 pub fn adapter_downlevel_capabilities(
1550 &self,
1551 adapter_id: AdapterId,
1552 ) -> wgt::DownlevelCapabilities {
1553 let adapter = self.hub.adapters.get(adapter_id);
1554 adapter.downlevel_capabilities()
1555 }
1556
1557 pub fn adapter_get_presentation_timestamp(
1558 &self,
1559 adapter_id: AdapterId,
1560 ) -> wgt::PresentationTimestamp {
1561 let adapter = self.hub.adapters.get(adapter_id);
1562 adapter.get_presentation_timestamp()
1563 }
1564
1565 pub fn adapter_cooperative_matrix_properties(
1566 &self,
1567 adapter_id: AdapterId,
1568 ) -> Vec<wgt::CooperativeMatrixProperties> {
1569 let adapter = self.hub.adapters.get(adapter_id);
1570 adapter.cooperative_matrix_properties()
1571 }
1572
1573 pub fn adapter_drop(&self, adapter_id: AdapterId) {
1574 self.hub.adapters.remove(adapter_id);
1575 }
1576}
1577
1578impl Global {
1579 pub fn adapter_request_device(
1580 &self,
1581 adapter_id: AdapterId,
1582 desc: &DeviceDescriptor,
1583 device_id_in: Option<DeviceId>,
1584 queue_id_in: Option<QueueId>,
1585 ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1586 let device_fid = self.hub.devices.prepare(device_id_in);
1587 let queue_fid = self.hub.queues.prepare(queue_id_in);
1588
1589 let adapter = self.hub.adapters.get(adapter_id);
1590 let (device, queue) = adapter.request_device(desc, self.instance.flags)?;
1591
1592 let device_id = device_fid.assign(device);
1593 resource_log!("Created Device {:?}", device_id);
1594
1595 let queue_id = queue_fid.assign(queue);
1596 resource_log!("Created Queue {:?}", queue_id);
1597
1598 Ok((device_id, queue_id))
1599 }
1600
1601 pub unsafe fn create_device_from_hal(
1606 &self,
1607 adapter_id: AdapterId,
1608 hal_device: hal::DynOpenDevice,
1609 desc: &DeviceDescriptor,
1610 device_id_in: Option<DeviceId>,
1611 queue_id_in: Option<QueueId>,
1612 ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1613 let devices_fid = self.hub.devices.prepare(device_id_in);
1614 let queues_fid = self.hub.queues.prepare(queue_id_in);
1615
1616 let adapter = self.hub.adapters.get(adapter_id);
1617 let (device, queue) = unsafe {
1618 adapter.create_device_and_queue_from_hal(hal_device, desc, self.instance.flags)
1619 }?;
1620
1621 let device_id = devices_fid.assign(device);
1622
1623 let queue_id = queues_fid.assign(queue);
1624
1625 Ok((device_id, queue_id))
1626 }
1627}
1628
1629fn adapter_allowed(
1634 flags: InstanceFlags,
1635 info: &impl fmt::Debug,
1636 limits: &wgt::Limits,
1637 downlevel: &wgt::DownlevelCapabilities,
1638) -> bool {
1639 let min_uniform_buffer_offset_alignment = limits.min_uniform_buffer_offset_alignment;
1645 if !min_uniform_buffer_offset_alignment.is_power_of_two() {
1646 log::error!(
1647 "Adapter {:?} min_uniform_buffer_offset_alignment limit is not a power of 2: {:?}",
1648 info,
1649 min_uniform_buffer_offset_alignment
1650 );
1651 return false;
1652 }
1653 let min_storage_buffer_offset_alignment = limits.min_storage_buffer_offset_alignment;
1654 if !min_storage_buffer_offset_alignment.is_power_of_two() {
1655 log::error!(
1656 "Adapter {:?} min_storage_buffer_offset_alignment limit is not a power of 2: {:?}",
1657 info,
1658 min_storage_buffer_offset_alignment
1659 );
1660 return false;
1661 }
1662
1663 if !flags.contains(InstanceFlags::STRICT_WEBGPU_COMPLIANCE) {
1665 return true;
1666 }
1667
1668 let mut min_limits = wgt::Limits::defaults();
1670 min_limits.zero_native_only();
1671 let failed_limits = check_limits(&min_limits, limits);
1672 if !failed_limits.is_empty() {
1673 log::debug!(
1674 "Adapter {:?} is not WebGPU compliant due to limits: {:?}",
1675 info,
1676 failed_limits
1677 );
1678 return false;
1679 }
1680
1681 if !downlevel.is_webgpu_compliant() {
1682 let missing_flags = wgt::DownlevelFlags::compliant() - downlevel.flags;
1683 log::debug!(
1684 "Adapter {:?} is not WebGPU compliant due to missing downlevel flags: {:?}",
1685 info,
1686 missing_flags
1687 );
1688 return false;
1689 }
1690
1691 true
1692}
1693
1694fn filter_features_and_limits(
1695 flags: InstanceFlags,
1696 features: &mut wgt::Features,
1697 limits: &mut wgt::Limits,
1698) {
1699 if flags.contains(InstanceFlags::STRICT_WEBGPU_COMPLIANCE) {
1700 *features &= wgt::Features::all_webgpu_mask() | limits::EXEMPT_FEATURES;
1701 limits.zero_native_only();
1702 }
1703}
1704
1705#[cfg(test)]
1706mod tests {
1707 use super::*;
1708
1709 fn compliant_downlevel() -> wgt::DownlevelCapabilities {
1710 wgt::DownlevelCapabilities {
1711 flags: wgt::DownlevelFlags::compliant(),
1712 ..Default::default()
1713 }
1714 }
1715
1716 #[test]
1717 fn non_power_of_two_uniform_alignment_always_rejected() {
1718 let limits = wgt::Limits {
1719 min_uniform_buffer_offset_alignment: 3,
1720 ..wgt::Limits::defaults()
1721 };
1722 assert!(!adapter_allowed(
1723 InstanceFlags::empty(),
1724 &"",
1725 &limits,
1726 &compliant_downlevel()
1727 ));
1728 assert!(!adapter_allowed(
1729 InstanceFlags::STRICT_WEBGPU_COMPLIANCE,
1730 &"",
1731 &limits,
1732 &compliant_downlevel()
1733 ));
1734 }
1735
1736 #[test]
1737 fn non_power_of_two_storage_alignment_always_rejected() {
1738 let limits = wgt::Limits {
1739 min_storage_buffer_offset_alignment: 96,
1740 ..wgt::Limits::defaults()
1741 };
1742 assert!(!adapter_allowed(
1743 InstanceFlags::empty(),
1744 &"",
1745 &limits,
1746 &compliant_downlevel()
1747 ));
1748 assert!(!adapter_allowed(
1749 InstanceFlags::STRICT_WEBGPU_COMPLIANCE,
1750 &"",
1751 &limits,
1752 &compliant_downlevel()
1753 ));
1754 }
1755
1756 #[test]
1757 fn low_limits_allowed_without_strict_compliance() {
1758 let limits = wgt::Limits {
1759 max_texture_dimension_1d: 1,
1760 ..wgt::Limits::defaults()
1761 };
1762 assert!(adapter_allowed(
1763 InstanceFlags::empty(),
1764 &"",
1765 &limits,
1766 &wgt::DownlevelCapabilities::default()
1767 ));
1768 }
1769
1770 #[test]
1771 fn low_limits_rejected_with_strict_compliance() {
1772 let limits = wgt::Limits {
1773 max_texture_dimension_1d: 1,
1774 ..wgt::Limits::defaults()
1775 };
1776 assert!(!adapter_allowed(
1777 InstanceFlags::STRICT_WEBGPU_COMPLIANCE,
1778 &"",
1779 &limits,
1780 &compliant_downlevel()
1781 ));
1782 }
1783
1784 #[test]
1785 fn missing_downlevel_flags_rejected_with_strict_compliance() {
1786 let downlevel = wgt::DownlevelCapabilities {
1787 flags: wgt::DownlevelFlags::empty(),
1788 ..Default::default()
1789 };
1790 assert!(!adapter_allowed(
1791 InstanceFlags::STRICT_WEBGPU_COMPLIANCE,
1792 &"",
1793 &wgt::Limits::defaults(),
1794 &downlevel
1795 ));
1796 }
1797
1798 #[test]
1799 fn fully_compliant_adapter_always_allowed() {
1800 assert!(adapter_allowed(
1801 InstanceFlags::STRICT_WEBGPU_COMPLIANCE,
1802 &"",
1803 &wgt::Limits::defaults(),
1804 &compliant_downlevel()
1805 ));
1806 }
1807}