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