1use alloc::{
2 borrow::{Cow, ToOwned as _},
3 boxed::Box,
4 string::String,
5 sync::Arc,
6 vec,
7 vec::Vec,
8};
9
10use hashbrown::HashMap;
11use thiserror::Error;
12use wgt::error::{ErrorType, WebGpuError};
13
14use crate::{
15 api_log, api_log_debug,
16 device::{queue::Queue, resource::Device, DeviceDescriptor, DeviceError},
17 global::Global,
18 hal_api::HalApi,
19 id::{markers, AdapterId, DeviceId, QueueId, SurfaceId},
20 lock::{rank, Mutex},
21 present::Presentation,
22 resource::ResourceType,
23 resource_log,
24 timestamp_normalization::TimestampNormalizerInitError,
25 DOWNLEVEL_WARNING_MESSAGE,
26};
27
28use wgt::{Backend, Backends, PowerPreference};
29
30pub type RequestAdapterOptions = wgt::RequestAdapterOptions<SurfaceId>;
31
32#[derive(Clone, Debug, Error)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
34#[error("Limit '{name}' value {requested} is better than allowed {allowed}")]
35pub struct FailedLimit {
36 name: Cow<'static, str>,
37 requested: u64,
38 allowed: u64,
39}
40
41impl WebGpuError for FailedLimit {
42 fn webgpu_error_type(&self) -> ErrorType {
43 ErrorType::Validation
44 }
45}
46
47fn check_limits(requested: &wgt::Limits, allowed: &wgt::Limits) -> Vec<FailedLimit> {
48 let mut failed = Vec::new();
49
50 requested.check_limits_with_fail_fn(allowed, false, |name, requested, allowed| {
51 failed.push(FailedLimit {
52 name: Cow::Borrowed(name),
53 requested,
54 allowed,
55 })
56 });
57
58 failed
59}
60
61#[test]
62fn downlevel_default_limits_less_than_default_limits() {
63 let res = check_limits(&wgt::Limits::downlevel_defaults(), &wgt::Limits::default());
64 assert!(
65 res.is_empty(),
66 "Downlevel limits are greater than default limits",
67 )
68}
69
70#[derive(Default)]
71pub struct Instance {
72 #[allow(dead_code)]
73 name: String,
74
75 instance_per_backend: Vec<(Backend, Box<dyn hal::DynInstance>)>,
79
80 requested_backends: Backends,
82
83 supported_backends: Backends,
91
92 pub flags: wgt::InstanceFlags,
93}
94
95impl Instance {
96 pub fn new(name: &str, instance_desc: &wgt::InstanceDescriptor) -> Self {
97 let mut this = Self {
98 name: name.to_owned(),
99 instance_per_backend: Vec::new(),
100 requested_backends: instance_desc.backends,
101 supported_backends: Backends::empty(),
102 flags: instance_desc.flags,
103 };
104
105 #[cfg(vulkan)]
106 this.try_add_hal(hal::api::Vulkan, instance_desc);
107 #[cfg(metal)]
108 this.try_add_hal(hal::api::Metal, instance_desc);
109 #[cfg(dx12)]
110 this.try_add_hal(hal::api::Dx12, instance_desc);
111 #[cfg(gles)]
112 this.try_add_hal(hal::api::Gles, instance_desc);
113 #[cfg(feature = "noop")]
114 this.try_add_hal(hal::api::Noop, instance_desc);
115
116 this
117 }
118
119 fn try_add_hal<A: HalApi>(&mut self, _: A, instance_desc: &wgt::InstanceDescriptor) {
121 self.supported_backends |= A::VARIANT.into();
124
125 if !instance_desc.backends.contains(A::VARIANT.into()) {
126 log::trace!("Instance::new: backend {:?} not requested", A::VARIANT);
127 return;
128 }
129
130 let hal_desc = hal::InstanceDescriptor {
131 name: "wgpu",
132 flags: self.flags,
133 memory_budget_thresholds: instance_desc.memory_budget_thresholds,
134 backend_options: instance_desc.backend_options.clone(),
135 };
136
137 use hal::Instance as _;
138 match unsafe { A::Instance::init(&hal_desc) } {
139 Ok(instance) => {
140 log::debug!("Instance::new: created {:?} backend", A::VARIANT);
141 self.instance_per_backend
142 .push((A::VARIANT, Box::new(instance)));
143 }
144 Err(err) => {
145 log::debug!(
146 "Instance::new: failed to create {:?} backend: {:?}",
147 A::VARIANT,
148 err
149 );
150 }
151 }
152 }
153
154 pub(crate) fn from_hal_instance<A: HalApi>(
155 name: String,
156 hal_instance: <A as hal::Api>::Instance,
157 ) -> Self {
158 Self {
159 name,
160 instance_per_backend: vec![(A::VARIANT, Box::new(hal_instance))],
161 requested_backends: A::VARIANT.into(),
162 supported_backends: A::VARIANT.into(),
163 flags: wgt::InstanceFlags::default(),
164 }
165 }
166
167 pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynInstance> {
168 self.instance_per_backend
169 .iter()
170 .find_map(|(instance_backend, instance)| {
171 (*instance_backend == backend).then(|| instance.as_ref())
172 })
173 }
174
175 pub unsafe fn as_hal<A: HalApi>(&self) -> Option<&A::Instance> {
179 self.raw(A::VARIANT).map(|instance| {
180 instance
181 .as_any()
182 .downcast_ref()
183 .expect("Stored instance is not of the correct type")
185 })
186 }
187
188 #[cfg(feature = "raw-window-handle")]
203 pub unsafe fn create_surface(
204 &self,
205 display_handle: raw_window_handle::RawDisplayHandle,
206 window_handle: raw_window_handle::RawWindowHandle,
207 ) -> Result<Surface, CreateSurfaceError> {
208 profiling::scope!("Instance::create_surface");
209
210 let mut errors = HashMap::default();
211 let mut surface_per_backend = HashMap::default();
212
213 for (backend, instance) in &self.instance_per_backend {
214 match unsafe {
215 instance
216 .as_ref()
217 .create_surface(display_handle, window_handle)
218 } {
219 Ok(raw) => {
220 surface_per_backend.insert(*backend, raw);
221 }
222 Err(err) => {
223 log::debug!(
224 "Instance::create_surface: failed to create surface for {:?}: {:?}",
225 backend,
226 err
227 );
228 errors.insert(*backend, err);
229 }
230 }
231 }
232
233 if surface_per_backend.is_empty() {
234 Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
235 errors,
236 ))
237 } else {
238 let surface = Surface {
239 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
240 surface_per_backend,
241 };
242
243 Ok(surface)
244 }
245 }
246
247 #[cfg(all(unix, not(target_vendor = "apple"), not(target_family = "wasm")))]
258 #[cfg_attr(not(vulkan), expect(unused_variables))]
259 pub unsafe fn create_surface_from_drm(
260 &self,
261 fd: i32,
262 plane: u32,
263 connector_id: u32,
264 width: u32,
265 height: u32,
266 refresh_rate: u32,
267 ) -> Result<Surface, CreateSurfaceError> {
268 profiling::scope!("Instance::create_surface_from_drm");
269
270 let mut errors = HashMap::default();
271 let mut surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>> =
272 HashMap::default();
273
274 #[cfg(vulkan)]
275 {
276 let instance = unsafe { self.as_hal::<hal::api::Vulkan>() }
277 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Vulkan))?;
278
279 match unsafe {
281 instance.create_surface_from_drm(
282 fd,
283 plane,
284 connector_id,
285 width,
286 height,
287 refresh_rate,
288 )
289 } {
290 Ok(surface) => {
291 surface_per_backend.insert(Backend::Vulkan, Box::new(surface));
292 }
293 Err(err) => {
294 errors.insert(Backend::Vulkan, err);
295 }
296 }
297 }
298
299 if surface_per_backend.is_empty() {
300 Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
301 errors,
302 ))
303 } else {
304 let surface = Surface {
305 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
306 surface_per_backend,
307 };
308
309 Ok(surface)
310 }
311 }
312
313 #[cfg(metal)]
317 pub unsafe fn create_surface_metal(
318 &self,
319 layer: *mut core::ffi::c_void,
320 ) -> Result<Surface, CreateSurfaceError> {
321 profiling::scope!("Instance::create_surface_metal");
322
323 let instance = unsafe { self.as_hal::<hal::api::Metal>() }
324 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Metal))?;
325
326 let layer = layer.cast();
327 let layer = unsafe { &*layer };
339 let raw_surface: Box<dyn hal::DynSurface> =
340 Box::new(instance.create_surface_from_layer(layer));
341
342 let surface = Surface {
343 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
344 surface_per_backend: core::iter::once((Backend::Metal, raw_surface)).collect(),
345 };
346
347 Ok(surface)
348 }
349
350 #[cfg(dx12)]
351 fn create_surface_dx12(
352 &self,
353 create_surface_func: impl FnOnce(&hal::dx12::Instance) -> hal::dx12::Surface,
354 ) -> Result<Surface, CreateSurfaceError> {
355 let instance = unsafe { self.as_hal::<hal::api::Dx12>() }
356 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Dx12))?;
357 let surface: Box<dyn hal::DynSurface> = Box::new(create_surface_func(instance));
358
359 let surface = Surface {
360 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
361 surface_per_backend: core::iter::once((Backend::Dx12, surface)).collect(),
362 };
363
364 Ok(surface)
365 }
366
367 #[cfg(dx12)]
368 pub unsafe fn create_surface_from_visual(
372 &self,
373 visual: *mut core::ffi::c_void,
374 ) -> Result<Surface, CreateSurfaceError> {
375 profiling::scope!("Instance::instance_create_surface_from_visual");
376 self.create_surface_dx12(|inst| unsafe { inst.create_surface_from_visual(visual) })
377 }
378
379 #[cfg(dx12)]
380 pub unsafe fn create_surface_from_surface_handle(
384 &self,
385 surface_handle: *mut core::ffi::c_void,
386 ) -> Result<Surface, CreateSurfaceError> {
387 profiling::scope!("Instance::instance_create_surface_from_surface_handle");
388 self.create_surface_dx12(|inst| unsafe {
389 inst.create_surface_from_surface_handle(surface_handle)
390 })
391 }
392
393 #[cfg(dx12)]
394 pub unsafe fn create_surface_from_swap_chain_panel(
398 &self,
399 swap_chain_panel: *mut core::ffi::c_void,
400 ) -> Result<Surface, CreateSurfaceError> {
401 profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel");
402 self.create_surface_dx12(|inst| unsafe {
403 inst.create_surface_from_swap_chain_panel(swap_chain_panel)
404 })
405 }
406
407 pub fn enumerate_adapters(&self, backends: Backends) -> Vec<Adapter> {
408 profiling::scope!("Instance::enumerate_adapters");
409 api_log!("Instance::enumerate_adapters");
410
411 let mut adapters = Vec::new();
412 for (_backend, instance) in self
413 .instance_per_backend
414 .iter()
415 .filter(|(backend, _)| backends.contains(Backends::from(*backend)))
416 {
417 profiling::scope!("enumerating", &*alloc::format!("{:?}", _backend));
420
421 let hal_adapters = unsafe { instance.enumerate_adapters(None) };
422 for raw in hal_adapters {
423 let adapter = Adapter::new(raw);
424 api_log_debug!("Adapter {:?}", adapter.raw.info);
425 adapters.push(adapter);
426 }
427 }
428 adapters
429 }
430
431 pub fn request_adapter(
432 &self,
433 desc: &wgt::RequestAdapterOptions<&Surface>,
434 backends: Backends,
435 ) -> Result<Adapter, wgt::RequestAdapterError> {
436 profiling::scope!("Instance::request_adapter");
437 api_log!("Instance::request_adapter");
438
439 let mut adapters = Vec::new();
440 let mut incompatible_surface_backends = Backends::empty();
441 let mut no_fallback_backends = Backends::empty();
442 let mut no_adapter_backends = Backends::empty();
443
444 for &(backend, ref instance) in self
445 .instance_per_backend
446 .iter()
447 .filter(|&&(backend, _)| backends.contains(Backends::from(backend)))
448 {
449 let compatible_hal_surface = desc
450 .compatible_surface
451 .and_then(|surface| surface.raw(backend));
452
453 let mut backend_adapters =
454 unsafe { instance.enumerate_adapters(compatible_hal_surface) };
455 if backend_adapters.is_empty() {
456 log::debug!("enabled backend `{:?}` has no adapters", backend);
457 no_adapter_backends |= Backends::from(backend);
458 continue;
460 }
461
462 if desc.force_fallback_adapter {
463 log::debug!("Filtering `{backend:?}` for `force_fallback_adapter`");
464 backend_adapters.retain(|exposed| {
465 let keep = exposed.info.device_type == wgt::DeviceType::Cpu;
466 if !keep {
467 log::debug!("* Eliminating adapter `{}`", exposed.info.name);
468 }
469 keep
470 });
471 if backend_adapters.is_empty() {
472 log::debug!("* Backend `{:?}` has no fallback adapters", backend);
473 no_fallback_backends |= Backends::from(backend);
474 continue;
475 }
476 }
477
478 if let Some(surface) = desc.compatible_surface {
479 backend_adapters.retain(|exposed| {
480 let capabilities = surface.get_capabilities_with_raw(exposed);
481 if let Err(err) = capabilities {
482 log::debug!(
483 "Adapter {:?} not compatible with surface: {}",
484 exposed.info,
485 err
486 );
487 incompatible_surface_backends |= Backends::from(backend);
488 false
489 } else {
490 true
491 }
492 });
493 if backend_adapters.is_empty() {
494 incompatible_surface_backends |= Backends::from(backend);
495 continue;
496 }
497 }
498 adapters.extend(backend_adapters);
499 }
500
501 match desc.power_preference {
502 PowerPreference::LowPower => {
503 sort(&mut adapters, true);
504 }
505 PowerPreference::HighPerformance => {
506 sort(&mut adapters, false);
507 }
508 PowerPreference::None => {}
509 };
510
511 fn sort(adapters: &mut [hal::DynExposedAdapter], prefer_integrated_gpu: bool) {
512 adapters
513 .sort_by_key(|adapter| get_order(adapter.info.device_type, prefer_integrated_gpu));
514 }
515
516 fn get_order(device_type: wgt::DeviceType, prefer_integrated_gpu: bool) -> u8 {
517 match device_type {
525 wgt::DeviceType::DiscreteGpu if prefer_integrated_gpu => 2,
526 wgt::DeviceType::IntegratedGpu if prefer_integrated_gpu => 1,
527 wgt::DeviceType::DiscreteGpu => 1,
528 wgt::DeviceType::IntegratedGpu => 2,
529 wgt::DeviceType::Other => 3,
530 wgt::DeviceType::VirtualGpu => 4,
531 wgt::DeviceType::Cpu => 5,
532 }
533 }
534
535 if adapters.is_empty() {
538 log::debug!("Request adapter didn't find compatible adapters.");
539 } else {
540 log::debug!(
541 "Found {} compatible adapters. Sorted by preference:",
542 adapters.len()
543 );
544 for adapter in &adapters {
545 log::debug!("* {:?}", adapter.info);
546 }
547 }
548
549 if let Some(adapter) = adapters.into_iter().next() {
550 api_log_debug!("Request adapter result {:?}", adapter.info);
551 let adapter = Adapter::new(adapter);
552 Ok(adapter)
553 } else {
554 Err(wgt::RequestAdapterError::NotFound {
555 supported_backends: self.supported_backends,
556 requested_backends: self.requested_backends,
557 active_backends: self.active_backends(),
558 no_fallback_backends,
559 no_adapter_backends,
560 incompatible_surface_backends,
561 })
562 }
563 }
564
565 fn active_backends(&self) -> Backends {
566 self.instance_per_backend
567 .iter()
568 .map(|&(backend, _)| Backends::from(backend))
569 .collect()
570 }
571}
572
573pub struct Surface {
574 pub(crate) presentation: Mutex<Option<Presentation>>,
575 pub surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>>,
576}
577
578impl ResourceType for Surface {
579 const TYPE: &'static str = "Surface";
580}
581impl crate::storage::StorageItem for Surface {
582 type Marker = markers::Surface;
583}
584
585impl Surface {
586 pub fn get_capabilities(
587 &self,
588 adapter: &Adapter,
589 ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
590 self.get_capabilities_with_raw(&adapter.raw)
591 }
592
593 pub fn get_capabilities_with_raw(
594 &self,
595 adapter: &hal::DynExposedAdapter,
596 ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
597 let backend = adapter.backend();
598 let suf = self
599 .raw(backend)
600 .ok_or(GetSurfaceSupportError::NotSupportedByBackend(backend))?;
601 profiling::scope!("surface_capabilities");
602 let caps = unsafe { adapter.adapter.surface_capabilities(suf) }
603 .ok_or(GetSurfaceSupportError::FailedToRetrieveSurfaceCapabilitiesForAdapter)?;
604 Ok(caps)
605 }
606
607 pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynSurface> {
608 self.surface_per_backend
609 .get(&backend)
610 .map(|surface| surface.as_ref())
611 }
612}
613
614impl Drop for Surface {
615 fn drop(&mut self) {
616 if let Some(present) = self.presentation.lock().take() {
617 for (&backend, surface) in &self.surface_per_backend {
618 if backend == present.device.backend() {
619 unsafe { surface.unconfigure(present.device.raw()) };
620 }
621 }
622 }
623 }
624}
625
626pub struct Adapter {
627 pub(crate) raw: hal::DynExposedAdapter,
628}
629
630impl Adapter {
631 pub fn new(mut raw: hal::DynExposedAdapter) -> Self {
632 const MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND: u32 = 32;
634
635 let limits = &mut raw.capabilities.limits;
636
637 limits.min_uniform_buffer_offset_alignment = limits
638 .min_uniform_buffer_offset_alignment
639 .max(MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND);
640 limits.min_storage_buffer_offset_alignment = limits
641 .min_storage_buffer_offset_alignment
642 .max(MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND);
643
644 Self { raw }
645 }
646
647 pub fn backend(&self) -> Backend {
649 self.raw.backend()
650 }
651
652 pub fn is_surface_supported(&self, surface: &Surface) -> bool {
653 surface.get_capabilities(self).is_ok()
658 }
659
660 pub fn get_info(&self) -> wgt::AdapterInfo {
661 self.raw.info.clone()
662 }
663
664 pub fn features(&self) -> wgt::Features {
665 self.raw.features
666 }
667
668 pub fn limits(&self) -> wgt::Limits {
669 self.raw.capabilities.limits.clone()
670 }
671
672 pub fn downlevel_capabilities(&self) -> wgt::DownlevelCapabilities {
673 self.raw.capabilities.downlevel.clone()
674 }
675
676 pub fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
677 unsafe { self.raw.adapter.get_presentation_timestamp() }
678 }
679
680 pub fn get_texture_format_features(
681 &self,
682 format: wgt::TextureFormat,
683 ) -> wgt::TextureFormatFeatures {
684 use hal::TextureFormatCapabilities as Tfc;
685
686 let caps = unsafe { self.raw.adapter.texture_format_capabilities(format) };
687 let mut allowed_usages = wgt::TextureUsages::empty();
688
689 allowed_usages.set(wgt::TextureUsages::COPY_SRC, caps.contains(Tfc::COPY_SRC));
690 allowed_usages.set(wgt::TextureUsages::COPY_DST, caps.contains(Tfc::COPY_DST));
691 allowed_usages.set(
692 wgt::TextureUsages::TEXTURE_BINDING,
693 caps.contains(Tfc::SAMPLED),
694 );
695 allowed_usages.set(
696 wgt::TextureUsages::STORAGE_BINDING,
697 caps.intersects(
698 Tfc::STORAGE_WRITE_ONLY
699 | Tfc::STORAGE_READ_ONLY
700 | Tfc::STORAGE_READ_WRITE
701 | Tfc::STORAGE_ATOMIC,
702 ),
703 );
704 allowed_usages.set(
705 wgt::TextureUsages::RENDER_ATTACHMENT,
706 caps.intersects(Tfc::COLOR_ATTACHMENT | Tfc::DEPTH_STENCIL_ATTACHMENT),
707 );
708 allowed_usages.set(
709 wgt::TextureUsages::STORAGE_ATOMIC,
710 caps.contains(Tfc::STORAGE_ATOMIC),
711 );
712
713 let mut flags = wgt::TextureFormatFeatureFlags::empty();
714 flags.set(
715 wgt::TextureFormatFeatureFlags::STORAGE_READ_ONLY,
716 caps.contains(Tfc::STORAGE_READ_ONLY),
717 );
718 flags.set(
719 wgt::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY,
720 caps.contains(Tfc::STORAGE_WRITE_ONLY),
721 );
722 flags.set(
723 wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE,
724 caps.contains(Tfc::STORAGE_READ_WRITE),
725 );
726
727 flags.set(
728 wgt::TextureFormatFeatureFlags::STORAGE_ATOMIC,
729 caps.contains(Tfc::STORAGE_ATOMIC),
730 );
731
732 flags.set(
733 wgt::TextureFormatFeatureFlags::FILTERABLE,
734 caps.contains(Tfc::SAMPLED_LINEAR),
735 );
736
737 flags.set(
738 wgt::TextureFormatFeatureFlags::BLENDABLE,
739 caps.contains(Tfc::COLOR_ATTACHMENT_BLEND),
740 );
741
742 flags.set(
743 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X2,
744 caps.contains(Tfc::MULTISAMPLE_X2),
745 );
746 flags.set(
747 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X4,
748 caps.contains(Tfc::MULTISAMPLE_X4),
749 );
750 flags.set(
751 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X8,
752 caps.contains(Tfc::MULTISAMPLE_X8),
753 );
754 flags.set(
755 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X16,
756 caps.contains(Tfc::MULTISAMPLE_X16),
757 );
758
759 flags.set(
760 wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE,
761 caps.contains(Tfc::MULTISAMPLE_RESOLVE),
762 );
763
764 wgt::TextureFormatFeatures {
765 allowed_usages,
766 flags,
767 }
768 }
769
770 #[allow(clippy::type_complexity)]
771 fn create_device_and_queue_from_hal(
772 self: &Arc<Self>,
773 hal_device: hal::DynOpenDevice,
774 desc: &DeviceDescriptor,
775 instance_flags: wgt::InstanceFlags,
776 ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
777 api_log!("Adapter::create_device");
778
779 let device = Device::new(hal_device.device, self, desc, instance_flags)?;
780 let device = Arc::new(device);
781
782 let queue = Queue::new(device.clone(), hal_device.queue)?;
783 let queue = Arc::new(queue);
784
785 device.set_queue(&queue);
786 device.late_init_resources_with_queue()?;
787
788 Ok((device, queue))
789 }
790
791 pub fn create_device_and_queue(
792 self: &Arc<Self>,
793 desc: &DeviceDescriptor,
794 instance_flags: wgt::InstanceFlags,
795 ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
796 if !self.raw.features.contains(desc.required_features) {
798 return Err(RequestDeviceError::UnsupportedFeature(
799 desc.required_features - self.raw.features,
800 ));
801 }
802
803 let caps = &self.raw.capabilities;
804 if Backends::PRIMARY.contains(Backends::from(self.backend()))
805 && !caps.downlevel.is_webgpu_compliant()
806 {
807 let missing_flags = wgt::DownlevelFlags::compliant() - caps.downlevel.flags;
808 log::warn!(
809 "Missing downlevel flags: {:?}\n{}",
810 missing_flags,
811 DOWNLEVEL_WARNING_MESSAGE
812 );
813 log::warn!("{:#?}", caps.downlevel);
814 }
815
816 if desc
818 .required_features
819 .contains(wgt::Features::MAPPABLE_PRIMARY_BUFFERS)
820 && self.raw.info.device_type == wgt::DeviceType::DiscreteGpu
821 {
822 log::warn!(
823 "Feature MAPPABLE_PRIMARY_BUFFERS enabled on a discrete gpu. \
824 This is a massive performance footgun and likely not what you wanted"
825 );
826 }
827
828 if let Some(failed) = check_limits(&desc.required_limits, &caps.limits).pop() {
829 return Err(RequestDeviceError::LimitsExceeded(failed));
830 }
831
832 let open = unsafe {
833 self.raw.adapter.open(
834 desc.required_features,
835 &desc.required_limits,
836 &desc.memory_hints,
837 )
838 }
839 .map_err(DeviceError::from_hal)?;
840
841 self.create_device_and_queue_from_hal(open, desc, instance_flags)
842 }
843}
844
845crate::impl_resource_type!(Adapter);
846crate::impl_storage_item!(Adapter);
847
848#[derive(Clone, Debug, Error)]
849#[non_exhaustive]
850pub enum GetSurfaceSupportError {
851 #[error("Surface is not supported for the specified backend {0}")]
852 NotSupportedByBackend(Backend),
853 #[error("Failed to retrieve surface capabilities for the specified adapter.")]
854 FailedToRetrieveSurfaceCapabilitiesForAdapter,
855}
856
857#[derive(Clone, Debug, Error)]
858#[non_exhaustive]
860pub enum RequestDeviceError {
861 #[error(transparent)]
862 Device(#[from] DeviceError),
863 #[error(transparent)]
864 LimitsExceeded(#[from] FailedLimit),
865 #[error("Failed to initialize Timestamp Normalizer")]
866 TimestampNormalizerInitFailed(#[from] TimestampNormalizerInitError),
867 #[error("Unsupported features were requested: {0:?}")]
868 UnsupportedFeature(wgt::Features),
869}
870
871#[derive(Clone, Debug, Error)]
872#[non_exhaustive]
873pub enum CreateSurfaceError {
874 #[error("The backend {0} was not enabled on the instance.")]
875 BackendNotEnabled(Backend),
876 #[error("Failed to create surface for any enabled backend: {0:?}")]
877 FailedToCreateSurfaceForAnyBackend(HashMap<Backend, hal::InstanceError>),
878}
879
880impl Global {
881 #[cfg(feature = "raw-window-handle")]
899 pub unsafe fn instance_create_surface(
900 &self,
901 display_handle: raw_window_handle::RawDisplayHandle,
902 window_handle: raw_window_handle::RawWindowHandle,
903 id_in: Option<SurfaceId>,
904 ) -> Result<SurfaceId, CreateSurfaceError> {
905 let surface = unsafe { self.instance.create_surface(display_handle, window_handle) }?;
906 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
907 Ok(id)
908 }
909
910 #[cfg(all(unix, not(target_vendor = "apple"), not(target_family = "wasm")))]
921 pub unsafe fn instance_create_surface_from_drm(
922 &self,
923 fd: i32,
924 plane: u32,
925 connector_id: u32,
926 width: u32,
927 height: u32,
928 refresh_rate: u32,
929 id_in: Option<SurfaceId>,
930 ) -> Result<SurfaceId, CreateSurfaceError> {
931 let surface = unsafe {
932 self.instance.create_surface_from_drm(
933 fd,
934 plane,
935 connector_id,
936 width,
937 height,
938 refresh_rate,
939 )
940 }?;
941 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
942
943 Ok(id)
944 }
945
946 #[cfg(metal)]
950 pub unsafe fn instance_create_surface_metal(
951 &self,
952 layer: *mut core::ffi::c_void,
953 id_in: Option<SurfaceId>,
954 ) -> Result<SurfaceId, CreateSurfaceError> {
955 let surface = unsafe { self.instance.create_surface_metal(layer) }?;
956 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
957 Ok(id)
958 }
959
960 #[cfg(dx12)]
961 pub unsafe fn instance_create_surface_from_visual(
965 &self,
966 visual: *mut core::ffi::c_void,
967 id_in: Option<SurfaceId>,
968 ) -> Result<SurfaceId, CreateSurfaceError> {
969 let surface = unsafe { self.instance.create_surface_from_visual(visual) }?;
970 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
971 Ok(id)
972 }
973
974 #[cfg(dx12)]
975 pub unsafe fn instance_create_surface_from_surface_handle(
979 &self,
980 surface_handle: *mut core::ffi::c_void,
981 id_in: Option<SurfaceId>,
982 ) -> Result<SurfaceId, CreateSurfaceError> {
983 let surface = unsafe {
984 self.instance
985 .create_surface_from_surface_handle(surface_handle)
986 }?;
987 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
988 Ok(id)
989 }
990
991 #[cfg(dx12)]
992 pub unsafe fn instance_create_surface_from_swap_chain_panel(
996 &self,
997 swap_chain_panel: *mut core::ffi::c_void,
998 id_in: Option<SurfaceId>,
999 ) -> Result<SurfaceId, CreateSurfaceError> {
1000 let surface = unsafe {
1001 self.instance
1002 .create_surface_from_swap_chain_panel(swap_chain_panel)
1003 }?;
1004 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1005 Ok(id)
1006 }
1007
1008 pub fn surface_drop(&self, id: SurfaceId) {
1009 profiling::scope!("Surface::drop");
1010
1011 api_log!("Surface::drop {id:?}");
1012
1013 self.surfaces.remove(id);
1014 }
1015
1016 pub fn enumerate_adapters(&self, backends: Backends) -> Vec<AdapterId> {
1017 let adapters = self.instance.enumerate_adapters(backends);
1018 adapters
1019 .into_iter()
1020 .map(|adapter| self.hub.adapters.prepare(None).assign(Arc::new(adapter)))
1021 .collect()
1022 }
1023
1024 pub fn request_adapter(
1025 &self,
1026 desc: &RequestAdapterOptions,
1027 backends: Backends,
1028 id_in: Option<AdapterId>,
1029 ) -> Result<AdapterId, wgt::RequestAdapterError> {
1030 let compatible_surface = desc.compatible_surface.map(|id| self.surfaces.get(id));
1031 let desc = wgt::RequestAdapterOptions {
1032 power_preference: desc.power_preference,
1033 force_fallback_adapter: desc.force_fallback_adapter,
1034 compatible_surface: compatible_surface.as_deref(),
1035 };
1036 let adapter = self.instance.request_adapter(&desc, backends)?;
1037 let id = self.hub.adapters.prepare(id_in).assign(Arc::new(adapter));
1038 Ok(id)
1039 }
1040
1041 pub unsafe fn create_adapter_from_hal(
1045 &self,
1046 hal_adapter: hal::DynExposedAdapter,
1047 input: Option<AdapterId>,
1048 ) -> AdapterId {
1049 profiling::scope!("Instance::create_adapter_from_hal");
1050
1051 let fid = self.hub.adapters.prepare(input);
1052 let id = fid.assign(Arc::new(Adapter::new(hal_adapter)));
1053
1054 resource_log!("Created Adapter {:?}", id);
1055 id
1056 }
1057
1058 pub fn adapter_get_info(&self, adapter_id: AdapterId) -> wgt::AdapterInfo {
1059 let adapter = self.hub.adapters.get(adapter_id);
1060 adapter.get_info()
1061 }
1062
1063 pub fn adapter_get_texture_format_features(
1064 &self,
1065 adapter_id: AdapterId,
1066 format: wgt::TextureFormat,
1067 ) -> wgt::TextureFormatFeatures {
1068 let adapter = self.hub.adapters.get(adapter_id);
1069 adapter.get_texture_format_features(format)
1070 }
1071
1072 pub fn adapter_features(&self, adapter_id: AdapterId) -> wgt::Features {
1073 let adapter = self.hub.adapters.get(adapter_id);
1074 adapter.features()
1075 }
1076
1077 pub fn adapter_limits(&self, adapter_id: AdapterId) -> wgt::Limits {
1078 let adapter = self.hub.adapters.get(adapter_id);
1079 adapter.limits()
1080 }
1081
1082 pub fn adapter_downlevel_capabilities(
1083 &self,
1084 adapter_id: AdapterId,
1085 ) -> wgt::DownlevelCapabilities {
1086 let adapter = self.hub.adapters.get(adapter_id);
1087 adapter.downlevel_capabilities()
1088 }
1089
1090 pub fn adapter_get_presentation_timestamp(
1091 &self,
1092 adapter_id: AdapterId,
1093 ) -> wgt::PresentationTimestamp {
1094 let adapter = self.hub.adapters.get(adapter_id);
1095 adapter.get_presentation_timestamp()
1096 }
1097
1098 pub fn adapter_drop(&self, adapter_id: AdapterId) {
1099 profiling::scope!("Adapter::drop");
1100 api_log!("Adapter::drop {adapter_id:?}");
1101
1102 self.hub.adapters.remove(adapter_id);
1103 }
1104}
1105
1106impl Global {
1107 pub fn adapter_request_device(
1108 &self,
1109 adapter_id: AdapterId,
1110 desc: &DeviceDescriptor,
1111 device_id_in: Option<DeviceId>,
1112 queue_id_in: Option<QueueId>,
1113 ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1114 profiling::scope!("Adapter::request_device");
1115 api_log!("Adapter::request_device");
1116
1117 let device_fid = self.hub.devices.prepare(device_id_in);
1118 let queue_fid = self.hub.queues.prepare(queue_id_in);
1119
1120 let adapter = self.hub.adapters.get(adapter_id);
1121 let (device, queue) = adapter.create_device_and_queue(desc, self.instance.flags)?;
1122
1123 let device_id = device_fid.assign(device);
1124 resource_log!("Created Device {:?}", device_id);
1125
1126 let queue_id = queue_fid.assign(queue);
1127 resource_log!("Created Queue {:?}", queue_id);
1128
1129 Ok((device_id, queue_id))
1130 }
1131
1132 pub unsafe fn create_device_from_hal(
1137 &self,
1138 adapter_id: AdapterId,
1139 hal_device: hal::DynOpenDevice,
1140 desc: &DeviceDescriptor,
1141 device_id_in: Option<DeviceId>,
1142 queue_id_in: Option<QueueId>,
1143 ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1144 profiling::scope!("Global::create_device_from_hal");
1145
1146 let devices_fid = self.hub.devices.prepare(device_id_in);
1147 let queues_fid = self.hub.queues.prepare(queue_id_in);
1148
1149 let adapter = self.hub.adapters.get(adapter_id);
1150 let (device, queue) =
1151 adapter.create_device_and_queue_from_hal(hal_device, desc, self.instance.flags)?;
1152
1153 let device_id = devices_fid.assign(device);
1154 resource_log!("Created Device {:?}", device_id);
1155
1156 let queue_id = queues_fid.assign(queue);
1157 resource_log!("Created Queue {:?}", queue_id);
1158
1159 Ok((device_id, queue_id))
1160 }
1161}