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(
96 name: &str,
97 instance_desc: &wgt::InstanceDescriptor,
98 telemetry: Option<hal::Telemetry>,
99 ) -> Self {
100 let mut this = Self {
101 name: name.to_owned(),
102 instance_per_backend: Vec::new(),
103 requested_backends: instance_desc.backends,
104 supported_backends: Backends::empty(),
105 flags: instance_desc.flags,
106 };
107
108 #[cfg(vulkan)]
109 this.try_add_hal(hal::api::Vulkan, instance_desc, telemetry);
110 #[cfg(metal)]
111 this.try_add_hal(hal::api::Metal, instance_desc, telemetry);
112 #[cfg(dx12)]
113 this.try_add_hal(hal::api::Dx12, instance_desc, telemetry);
114 #[cfg(gles)]
115 this.try_add_hal(hal::api::Gles, instance_desc, telemetry);
116 #[cfg(feature = "noop")]
117 this.try_add_hal(hal::api::Noop, instance_desc, telemetry);
118
119 this
120 }
121
122 fn try_add_hal<A: hal::Api>(
124 &mut self,
125 _: A,
126 instance_desc: &wgt::InstanceDescriptor,
127 telemetry: Option<hal::Telemetry>,
128 ) {
129 self.supported_backends |= A::VARIANT.into();
132
133 if !instance_desc.backends.contains(A::VARIANT.into()) {
134 log::trace!("Instance::new: backend {:?} not requested", A::VARIANT);
135 return;
136 }
137
138 let hal_desc = hal::InstanceDescriptor {
139 name: "wgpu",
140 flags: self.flags,
141 memory_budget_thresholds: instance_desc.memory_budget_thresholds,
142 backend_options: instance_desc.backend_options.clone(),
143 telemetry,
144 };
145
146 use hal::Instance as _;
147 match unsafe { A::Instance::init(&hal_desc) } {
148 Ok(instance) => {
149 log::debug!("Instance::new: created {:?} backend", A::VARIANT);
150 self.instance_per_backend
151 .push((A::VARIANT, Box::new(instance)));
152 }
153 Err(err) => {
154 log::debug!(
155 "Instance::new: failed to create {:?} backend: {:?}",
156 A::VARIANT,
157 err
158 );
159 }
160 }
161 }
162
163 pub(crate) fn from_hal_instance<A: hal::Api>(
164 name: String,
165 hal_instance: <A as hal::Api>::Instance,
166 ) -> Self {
167 Self {
168 name,
169 instance_per_backend: vec![(A::VARIANT, Box::new(hal_instance))],
170 requested_backends: A::VARIANT.into(),
171 supported_backends: A::VARIANT.into(),
172 flags: wgt::InstanceFlags::default(),
173 }
174 }
175
176 pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynInstance> {
177 self.instance_per_backend
178 .iter()
179 .find_map(|(instance_backend, instance)| {
180 (*instance_backend == backend).then(|| instance.as_ref())
181 })
182 }
183
184 pub unsafe fn as_hal<A: hal::Api>(&self) -> Option<&A::Instance> {
188 self.raw(A::VARIANT).map(|instance| {
189 instance
190 .as_any()
191 .downcast_ref()
192 .expect("Stored instance is not of the correct type")
194 })
195 }
196
197 #[cfg(feature = "raw-window-handle")]
212 pub unsafe fn create_surface(
213 &self,
214 display_handle: raw_window_handle::RawDisplayHandle,
215 window_handle: raw_window_handle::RawWindowHandle,
216 ) -> Result<Surface, CreateSurfaceError> {
217 profiling::scope!("Instance::create_surface");
218
219 let mut errors = HashMap::default();
220 let mut surface_per_backend = HashMap::default();
221
222 for (backend, instance) in &self.instance_per_backend {
223 match unsafe {
224 instance
225 .as_ref()
226 .create_surface(display_handle, window_handle)
227 } {
228 Ok(raw) => {
229 surface_per_backend.insert(*backend, raw);
230 }
231 Err(err) => {
232 log::debug!(
233 "Instance::create_surface: failed to create surface for {backend:?}: {err:?}"
234 );
235 errors.insert(*backend, err);
236 }
237 }
238 }
239
240 if surface_per_backend.is_empty() {
241 Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
242 errors,
243 ))
244 } else {
245 let surface = Surface {
246 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
247 surface_per_backend,
248 };
249
250 Ok(surface)
251 }
252 }
253
254 #[cfg(all(unix, not(target_vendor = "apple"), not(target_family = "wasm")))]
265 #[cfg_attr(not(vulkan), expect(unused_variables))]
266 pub unsafe fn create_surface_from_drm(
267 &self,
268 fd: i32,
269 plane: u32,
270 connector_id: u32,
271 width: u32,
272 height: u32,
273 refresh_rate: u32,
274 ) -> Result<Surface, CreateSurfaceError> {
275 profiling::scope!("Instance::create_surface_from_drm");
276
277 let mut errors = HashMap::default();
278 let mut surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>> =
279 HashMap::default();
280
281 #[cfg(vulkan)]
282 {
283 let instance = unsafe { self.as_hal::<hal::api::Vulkan>() }
284 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Vulkan))?;
285
286 match unsafe {
288 instance.create_surface_from_drm(
289 fd,
290 plane,
291 connector_id,
292 width,
293 height,
294 refresh_rate,
295 )
296 } {
297 Ok(surface) => {
298 surface_per_backend.insert(Backend::Vulkan, Box::new(surface));
299 }
300 Err(err) => {
301 errors.insert(Backend::Vulkan, 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(metal)]
324 pub unsafe fn create_surface_metal(
325 &self,
326 layer: *mut core::ffi::c_void,
327 ) -> Result<Surface, CreateSurfaceError> {
328 profiling::scope!("Instance::create_surface_metal");
329
330 let instance = unsafe { self.as_hal::<hal::api::Metal>() }
331 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Metal))?;
332
333 let layer = layer.cast();
334 let layer = unsafe { &*layer };
346 let raw_surface: Box<dyn hal::DynSurface> =
347 Box::new(instance.create_surface_from_layer(layer));
348
349 let surface = Surface {
350 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
351 surface_per_backend: core::iter::once((Backend::Metal, raw_surface)).collect(),
352 };
353
354 Ok(surface)
355 }
356
357 #[cfg(dx12)]
358 fn create_surface_dx12(
359 &self,
360 create_surface_func: impl FnOnce(&hal::dx12::Instance) -> hal::dx12::Surface,
361 ) -> Result<Surface, CreateSurfaceError> {
362 let instance = unsafe { self.as_hal::<hal::api::Dx12>() }
363 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Dx12))?;
364 let surface: Box<dyn hal::DynSurface> = Box::new(create_surface_func(instance));
365
366 let surface = Surface {
367 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
368 surface_per_backend: core::iter::once((Backend::Dx12, surface)).collect(),
369 };
370
371 Ok(surface)
372 }
373
374 #[cfg(dx12)]
375 pub unsafe fn create_surface_from_visual(
379 &self,
380 visual: *mut core::ffi::c_void,
381 ) -> Result<Surface, CreateSurfaceError> {
382 profiling::scope!("Instance::instance_create_surface_from_visual");
383 self.create_surface_dx12(|inst| unsafe { inst.create_surface_from_visual(visual) })
384 }
385
386 #[cfg(dx12)]
387 pub unsafe fn create_surface_from_surface_handle(
391 &self,
392 surface_handle: *mut core::ffi::c_void,
393 ) -> Result<Surface, CreateSurfaceError> {
394 profiling::scope!("Instance::instance_create_surface_from_surface_handle");
395 self.create_surface_dx12(|inst| unsafe {
396 inst.create_surface_from_surface_handle(surface_handle)
397 })
398 }
399
400 #[cfg(dx12)]
401 pub unsafe fn create_surface_from_swap_chain_panel(
405 &self,
406 swap_chain_panel: *mut core::ffi::c_void,
407 ) -> Result<Surface, CreateSurfaceError> {
408 profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel");
409 self.create_surface_dx12(|inst| unsafe {
410 inst.create_surface_from_swap_chain_panel(swap_chain_panel)
411 })
412 }
413
414 pub fn enumerate_adapters(&self, backends: Backends) -> Vec<Adapter> {
415 profiling::scope!("Instance::enumerate_adapters");
416 api_log!("Instance::enumerate_adapters");
417
418 let mut adapters = Vec::new();
419 for (_backend, instance) in self
420 .instance_per_backend
421 .iter()
422 .filter(|(backend, _)| backends.contains(Backends::from(*backend)))
423 {
424 profiling::scope!("enumerating", &*alloc::format!("{_backend:?}"));
427
428 let hal_adapters = unsafe { instance.enumerate_adapters(None) };
429 for raw in hal_adapters {
430 let adapter = Adapter::new(raw);
431 api_log_debug!("Adapter {:?}", adapter.raw.info);
432 adapters.push(adapter);
433 }
434 }
435 adapters
436 }
437
438 pub fn request_adapter(
439 &self,
440 desc: &wgt::RequestAdapterOptions<&Surface>,
441 backends: Backends,
442 ) -> Result<Adapter, wgt::RequestAdapterError> {
443 profiling::scope!("Instance::request_adapter");
444 api_log!("Instance::request_adapter");
445
446 let mut adapters = Vec::new();
447 let mut incompatible_surface_backends = Backends::empty();
448 let mut no_fallback_backends = Backends::empty();
449 let mut no_adapter_backends = Backends::empty();
450
451 for &(backend, ref instance) in self
452 .instance_per_backend
453 .iter()
454 .filter(|&&(backend, _)| backends.contains(Backends::from(backend)))
455 {
456 let compatible_hal_surface = desc
457 .compatible_surface
458 .and_then(|surface| surface.raw(backend));
459
460 let mut backend_adapters =
461 unsafe { instance.enumerate_adapters(compatible_hal_surface) };
462 if backend_adapters.is_empty() {
463 log::debug!("enabled backend `{backend:?}` has no adapters");
464 no_adapter_backends |= Backends::from(backend);
465 continue;
467 }
468
469 if desc.force_fallback_adapter {
470 log::debug!("Filtering `{backend:?}` for `force_fallback_adapter`");
471 backend_adapters.retain(|exposed| {
472 let keep = exposed.info.device_type == wgt::DeviceType::Cpu;
473 if !keep {
474 log::debug!("* Eliminating adapter `{}`", exposed.info.name);
475 }
476 keep
477 });
478 if backend_adapters.is_empty() {
479 log::debug!("* Backend `{backend:?}` has no fallback adapters");
480 no_fallback_backends |= Backends::from(backend);
481 continue;
482 }
483 }
484
485 if let Some(surface) = desc.compatible_surface {
486 backend_adapters.retain(|exposed| {
487 let capabilities = surface.get_capabilities_with_raw(exposed);
488 if let Err(err) = capabilities {
489 log::debug!(
490 "Adapter {:?} not compatible with surface: {}",
491 exposed.info,
492 err
493 );
494 incompatible_surface_backends |= Backends::from(backend);
495 false
496 } else {
497 true
498 }
499 });
500 if backend_adapters.is_empty() {
501 incompatible_surface_backends |= Backends::from(backend);
502 continue;
503 }
504 }
505 adapters.extend(backend_adapters);
506 }
507
508 match desc.power_preference {
509 PowerPreference::LowPower => {
510 sort(&mut adapters, true);
511 }
512 PowerPreference::HighPerformance => {
513 sort(&mut adapters, false);
514 }
515 PowerPreference::None => {}
516 };
517
518 fn sort(adapters: &mut [hal::DynExposedAdapter], prefer_integrated_gpu: bool) {
519 adapters
520 .sort_by_key(|adapter| get_order(adapter.info.device_type, prefer_integrated_gpu));
521 }
522
523 fn get_order(device_type: wgt::DeviceType, prefer_integrated_gpu: bool) -> u8 {
524 match device_type {
532 wgt::DeviceType::DiscreteGpu if prefer_integrated_gpu => 2,
533 wgt::DeviceType::IntegratedGpu if prefer_integrated_gpu => 1,
534 wgt::DeviceType::DiscreteGpu => 1,
535 wgt::DeviceType::IntegratedGpu => 2,
536 wgt::DeviceType::Other => 3,
537 wgt::DeviceType::VirtualGpu => 4,
538 wgt::DeviceType::Cpu => 5,
539 }
540 }
541
542 if adapters.is_empty() {
545 log::debug!("Request adapter didn't find compatible adapters.");
546 } else {
547 log::debug!(
548 "Found {} compatible adapters. Sorted by preference:",
549 adapters.len()
550 );
551 for adapter in &adapters {
552 log::debug!("* {:?}", adapter.info);
553 }
554 }
555
556 if let Some(adapter) = adapters.into_iter().next() {
557 api_log_debug!("Request adapter result {:?}", adapter.info);
558 let adapter = Adapter::new(adapter);
559 Ok(adapter)
560 } else {
561 Err(wgt::RequestAdapterError::NotFound {
562 supported_backends: self.supported_backends,
563 requested_backends: self.requested_backends,
564 active_backends: self.active_backends(),
565 no_fallback_backends,
566 no_adapter_backends,
567 incompatible_surface_backends,
568 })
569 }
570 }
571
572 fn active_backends(&self) -> Backends {
573 self.instance_per_backend
574 .iter()
575 .map(|&(backend, _)| Backends::from(backend))
576 .collect()
577 }
578}
579
580pub struct Surface {
581 pub(crate) presentation: Mutex<Option<Presentation>>,
582 pub surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>>,
583}
584
585impl ResourceType for Surface {
586 const TYPE: &'static str = "Surface";
587}
588impl crate::storage::StorageItem for Surface {
589 type Marker = markers::Surface;
590}
591
592impl Surface {
593 pub fn get_capabilities(
594 &self,
595 adapter: &Adapter,
596 ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
597 self.get_capabilities_with_raw(&adapter.raw)
598 }
599
600 pub fn get_capabilities_with_raw(
601 &self,
602 adapter: &hal::DynExposedAdapter,
603 ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
604 let backend = adapter.backend();
605 let suf = self
606 .raw(backend)
607 .ok_or(GetSurfaceSupportError::NotSupportedByBackend(backend))?;
608 profiling::scope!("surface_capabilities");
609 let caps = unsafe { adapter.adapter.surface_capabilities(suf) }
610 .ok_or(GetSurfaceSupportError::FailedToRetrieveSurfaceCapabilitiesForAdapter)?;
611 Ok(caps)
612 }
613
614 pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynSurface> {
615 self.surface_per_backend
616 .get(&backend)
617 .map(|surface| surface.as_ref())
618 }
619}
620
621impl Drop for Surface {
622 fn drop(&mut self) {
623 if let Some(present) = self.presentation.lock().take() {
624 for (&backend, surface) in &self.surface_per_backend {
625 if backend == present.device.backend() {
626 unsafe { surface.unconfigure(present.device.raw()) };
627 }
628 }
629 }
630 }
631}
632
633pub struct Adapter {
634 pub(crate) raw: hal::DynExposedAdapter,
635}
636
637impl Adapter {
638 pub fn new(mut raw: hal::DynExposedAdapter) -> Self {
639 const MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND: u32 = 32;
641
642 let limits = &mut raw.capabilities.limits;
643
644 limits.min_uniform_buffer_offset_alignment = limits
645 .min_uniform_buffer_offset_alignment
646 .max(MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND);
647 limits.min_storage_buffer_offset_alignment = limits
648 .min_storage_buffer_offset_alignment
649 .max(MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND);
650
651 Self { raw }
652 }
653
654 pub fn backend(&self) -> Backend {
656 self.raw.backend()
657 }
658
659 pub fn is_surface_supported(&self, surface: &Surface) -> bool {
660 surface.get_capabilities(self).is_ok()
665 }
666
667 pub fn get_info(&self) -> wgt::AdapterInfo {
668 self.raw.info.clone()
669 }
670
671 pub fn features(&self) -> wgt::Features {
672 self.raw.features
673 }
674
675 pub fn limits(&self) -> wgt::Limits {
676 self.raw.capabilities.limits.clone()
677 }
678
679 pub fn downlevel_capabilities(&self) -> wgt::DownlevelCapabilities {
680 self.raw.capabilities.downlevel.clone()
681 }
682
683 pub fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
684 unsafe { self.raw.adapter.get_presentation_timestamp() }
685 }
686
687 pub fn get_texture_format_features(
688 &self,
689 format: wgt::TextureFormat,
690 ) -> wgt::TextureFormatFeatures {
691 use hal::TextureFormatCapabilities as Tfc;
692
693 let caps = unsafe { self.raw.adapter.texture_format_capabilities(format) };
694 let mut allowed_usages = wgt::TextureUsages::empty();
695
696 allowed_usages.set(wgt::TextureUsages::COPY_SRC, caps.contains(Tfc::COPY_SRC));
697 allowed_usages.set(wgt::TextureUsages::COPY_DST, caps.contains(Tfc::COPY_DST));
698 allowed_usages.set(
699 wgt::TextureUsages::TEXTURE_BINDING,
700 caps.contains(Tfc::SAMPLED),
701 );
702 allowed_usages.set(
703 wgt::TextureUsages::STORAGE_BINDING,
704 caps.intersects(
705 Tfc::STORAGE_WRITE_ONLY
706 | Tfc::STORAGE_READ_ONLY
707 | Tfc::STORAGE_READ_WRITE
708 | Tfc::STORAGE_ATOMIC,
709 ),
710 );
711 allowed_usages.set(
712 wgt::TextureUsages::RENDER_ATTACHMENT | wgt::TextureUsages::TRANSIENT,
713 caps.intersects(Tfc::COLOR_ATTACHMENT | Tfc::DEPTH_STENCIL_ATTACHMENT),
714 );
715 allowed_usages.set(
716 wgt::TextureUsages::STORAGE_ATOMIC,
717 caps.contains(Tfc::STORAGE_ATOMIC),
718 );
719
720 let mut flags = wgt::TextureFormatFeatureFlags::empty();
721 flags.set(
722 wgt::TextureFormatFeatureFlags::STORAGE_READ_ONLY,
723 caps.contains(Tfc::STORAGE_READ_ONLY),
724 );
725 flags.set(
726 wgt::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY,
727 caps.contains(Tfc::STORAGE_WRITE_ONLY),
728 );
729 flags.set(
730 wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE,
731 caps.contains(Tfc::STORAGE_READ_WRITE),
732 );
733
734 flags.set(
735 wgt::TextureFormatFeatureFlags::STORAGE_ATOMIC,
736 caps.contains(Tfc::STORAGE_ATOMIC),
737 );
738
739 flags.set(
740 wgt::TextureFormatFeatureFlags::FILTERABLE,
741 caps.contains(Tfc::SAMPLED_LINEAR),
742 );
743
744 flags.set(
745 wgt::TextureFormatFeatureFlags::BLENDABLE,
746 caps.contains(Tfc::COLOR_ATTACHMENT_BLEND),
747 );
748
749 flags.set(
750 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X2,
751 caps.contains(Tfc::MULTISAMPLE_X2),
752 );
753 flags.set(
754 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X4,
755 caps.contains(Tfc::MULTISAMPLE_X4),
756 );
757 flags.set(
758 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X8,
759 caps.contains(Tfc::MULTISAMPLE_X8),
760 );
761 flags.set(
762 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X16,
763 caps.contains(Tfc::MULTISAMPLE_X16),
764 );
765
766 flags.set(
767 wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE,
768 caps.contains(Tfc::MULTISAMPLE_RESOLVE),
769 );
770
771 wgt::TextureFormatFeatures {
772 allowed_usages,
773 flags,
774 }
775 }
776
777 #[allow(clippy::type_complexity)]
778 fn create_device_and_queue_from_hal(
779 self: &Arc<Self>,
780 hal_device: hal::DynOpenDevice,
781 desc: &DeviceDescriptor,
782 instance_flags: wgt::InstanceFlags,
783 ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
784 api_log!("Adapter::create_device");
785
786 let device = Device::new(hal_device.device, self, desc, instance_flags)?;
787 let device = Arc::new(device);
788
789 let queue = Queue::new(device.clone(), hal_device.queue, instance_flags)?;
790 let queue = Arc::new(queue);
791
792 device.set_queue(&queue);
793 device.late_init_resources_with_queue()?;
794
795 Ok((device, queue))
796 }
797
798 pub fn create_device_and_queue(
799 self: &Arc<Self>,
800 desc: &DeviceDescriptor,
801 instance_flags: wgt::InstanceFlags,
802 ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
803 if !self.raw.features.contains(desc.required_features) {
805 return Err(RequestDeviceError::UnsupportedFeature(
806 desc.required_features - self.raw.features,
807 ));
808 }
809
810 if desc
812 .required_features
813 .intersects(wgt::Features::all_experimental_mask())
814 && !desc.experimental_features.is_enabled()
815 {
816 return Err(RequestDeviceError::ExperimentalFeaturesNotEnabled(
817 desc.required_features
818 .intersection(wgt::Features::all_experimental_mask()),
819 ));
820 }
821
822 let caps = &self.raw.capabilities;
823 if Backends::PRIMARY.contains(Backends::from(self.backend()))
824 && !caps.downlevel.is_webgpu_compliant()
825 {
826 let missing_flags = wgt::DownlevelFlags::compliant() - caps.downlevel.flags;
827 log::warn!("Missing downlevel flags: {missing_flags:?}\n{DOWNLEVEL_WARNING_MESSAGE}");
828 log::warn!("{:#?}", caps.downlevel);
829 }
830
831 if desc
833 .required_features
834 .contains(wgt::Features::MAPPABLE_PRIMARY_BUFFERS)
835 && self.raw.info.device_type == wgt::DeviceType::DiscreteGpu
836 {
837 log::warn!(
838 "Feature MAPPABLE_PRIMARY_BUFFERS enabled on a discrete gpu. \
839 This is a massive performance footgun and likely not what you wanted"
840 );
841 }
842
843 if let Some(failed) = check_limits(&desc.required_limits, &caps.limits).pop() {
844 return Err(RequestDeviceError::LimitsExceeded(failed));
845 }
846
847 let open = unsafe {
848 self.raw.adapter.open(
849 desc.required_features,
850 &desc.required_limits,
851 &desc.memory_hints,
852 )
853 }
854 .map_err(DeviceError::from_hal)?;
855
856 self.create_device_and_queue_from_hal(open, desc, instance_flags)
857 }
858}
859
860crate::impl_resource_type!(Adapter);
861crate::impl_storage_item!(Adapter);
862
863#[derive(Clone, Debug, Error)]
864#[non_exhaustive]
865pub enum GetSurfaceSupportError {
866 #[error("Surface is not supported for the specified backend {0}")]
867 NotSupportedByBackend(Backend),
868 #[error("Failed to retrieve surface capabilities for the specified adapter.")]
869 FailedToRetrieveSurfaceCapabilitiesForAdapter,
870}
871
872#[derive(Clone, Debug, Error)]
873#[non_exhaustive]
875pub enum RequestDeviceError {
876 #[error(transparent)]
877 Device(#[from] DeviceError),
878 #[error(transparent)]
879 LimitsExceeded(#[from] FailedLimit),
880 #[error("Failed to initialize Timestamp Normalizer")]
881 TimestampNormalizerInitFailed(#[from] TimestampNormalizerInitError),
882 #[error("Unsupported features were requested: {0}")]
883 UnsupportedFeature(wgt::Features),
884 #[error(
885 "Some experimental features, {0}, were requested, but experimental features are not enabled"
886 )]
887 ExperimentalFeaturesNotEnabled(wgt::Features),
888}
889
890#[derive(Clone, Debug, Error)]
891#[non_exhaustive]
892pub enum CreateSurfaceError {
893 #[error("The backend {0} was not enabled on the instance.")]
894 BackendNotEnabled(Backend),
895 #[error("Failed to create surface for any enabled backend: {0:?}")]
896 FailedToCreateSurfaceForAnyBackend(HashMap<Backend, hal::InstanceError>),
897}
898
899impl Global {
900 #[cfg(feature = "raw-window-handle")]
918 pub unsafe fn instance_create_surface(
919 &self,
920 display_handle: raw_window_handle::RawDisplayHandle,
921 window_handle: raw_window_handle::RawWindowHandle,
922 id_in: Option<SurfaceId>,
923 ) -> Result<SurfaceId, CreateSurfaceError> {
924 let surface = unsafe { self.instance.create_surface(display_handle, window_handle) }?;
925 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
926 Ok(id)
927 }
928
929 #[cfg(all(unix, not(target_vendor = "apple"), not(target_family = "wasm")))]
940 pub unsafe fn instance_create_surface_from_drm(
941 &self,
942 fd: i32,
943 plane: u32,
944 connector_id: u32,
945 width: u32,
946 height: u32,
947 refresh_rate: u32,
948 id_in: Option<SurfaceId>,
949 ) -> Result<SurfaceId, CreateSurfaceError> {
950 let surface = unsafe {
951 self.instance.create_surface_from_drm(
952 fd,
953 plane,
954 connector_id,
955 width,
956 height,
957 refresh_rate,
958 )
959 }?;
960 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
961
962 Ok(id)
963 }
964
965 #[cfg(metal)]
969 pub unsafe fn instance_create_surface_metal(
970 &self,
971 layer: *mut core::ffi::c_void,
972 id_in: Option<SurfaceId>,
973 ) -> Result<SurfaceId, CreateSurfaceError> {
974 let surface = unsafe { self.instance.create_surface_metal(layer) }?;
975 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
976 Ok(id)
977 }
978
979 #[cfg(dx12)]
980 pub unsafe fn instance_create_surface_from_visual(
984 &self,
985 visual: *mut core::ffi::c_void,
986 id_in: Option<SurfaceId>,
987 ) -> Result<SurfaceId, CreateSurfaceError> {
988 let surface = unsafe { self.instance.create_surface_from_visual(visual) }?;
989 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
990 Ok(id)
991 }
992
993 #[cfg(dx12)]
994 pub unsafe fn instance_create_surface_from_surface_handle(
998 &self,
999 surface_handle: *mut core::ffi::c_void,
1000 id_in: Option<SurfaceId>,
1001 ) -> Result<SurfaceId, CreateSurfaceError> {
1002 let surface = unsafe {
1003 self.instance
1004 .create_surface_from_surface_handle(surface_handle)
1005 }?;
1006 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1007 Ok(id)
1008 }
1009
1010 #[cfg(dx12)]
1011 pub unsafe fn instance_create_surface_from_swap_chain_panel(
1015 &self,
1016 swap_chain_panel: *mut core::ffi::c_void,
1017 id_in: Option<SurfaceId>,
1018 ) -> Result<SurfaceId, CreateSurfaceError> {
1019 let surface = unsafe {
1020 self.instance
1021 .create_surface_from_swap_chain_panel(swap_chain_panel)
1022 }?;
1023 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1024 Ok(id)
1025 }
1026
1027 pub fn surface_drop(&self, id: SurfaceId) {
1028 profiling::scope!("Surface::drop");
1029
1030 api_log!("Surface::drop {id:?}");
1031
1032 self.surfaces.remove(id);
1033 }
1034
1035 pub fn enumerate_adapters(&self, backends: Backends) -> Vec<AdapterId> {
1036 let adapters = self.instance.enumerate_adapters(backends);
1037 adapters
1038 .into_iter()
1039 .map(|adapter| self.hub.adapters.prepare(None).assign(Arc::new(adapter)))
1040 .collect()
1041 }
1042
1043 pub fn request_adapter(
1044 &self,
1045 desc: &RequestAdapterOptions,
1046 backends: Backends,
1047 id_in: Option<AdapterId>,
1048 ) -> Result<AdapterId, wgt::RequestAdapterError> {
1049 let compatible_surface = desc.compatible_surface.map(|id| self.surfaces.get(id));
1050 let desc = wgt::RequestAdapterOptions {
1051 power_preference: desc.power_preference,
1052 force_fallback_adapter: desc.force_fallback_adapter,
1053 compatible_surface: compatible_surface.as_deref(),
1054 };
1055 let adapter = self.instance.request_adapter(&desc, backends)?;
1056 let id = self.hub.adapters.prepare(id_in).assign(Arc::new(adapter));
1057 Ok(id)
1058 }
1059
1060 pub unsafe fn create_adapter_from_hal(
1064 &self,
1065 hal_adapter: hal::DynExposedAdapter,
1066 input: Option<AdapterId>,
1067 ) -> AdapterId {
1068 profiling::scope!("Instance::create_adapter_from_hal");
1069
1070 let fid = self.hub.adapters.prepare(input);
1071 let id = fid.assign(Arc::new(Adapter::new(hal_adapter)));
1072
1073 resource_log!("Created Adapter {:?}", id);
1074 id
1075 }
1076
1077 pub fn adapter_get_info(&self, adapter_id: AdapterId) -> wgt::AdapterInfo {
1078 let adapter = self.hub.adapters.get(adapter_id);
1079 adapter.get_info()
1080 }
1081
1082 pub fn adapter_get_texture_format_features(
1083 &self,
1084 adapter_id: AdapterId,
1085 format: wgt::TextureFormat,
1086 ) -> wgt::TextureFormatFeatures {
1087 let adapter = self.hub.adapters.get(adapter_id);
1088 adapter.get_texture_format_features(format)
1089 }
1090
1091 pub fn adapter_features(&self, adapter_id: AdapterId) -> wgt::Features {
1092 let adapter = self.hub.adapters.get(adapter_id);
1093 adapter.features()
1094 }
1095
1096 pub fn adapter_limits(&self, adapter_id: AdapterId) -> wgt::Limits {
1097 let adapter = self.hub.adapters.get(adapter_id);
1098 adapter.limits()
1099 }
1100
1101 pub fn adapter_downlevel_capabilities(
1102 &self,
1103 adapter_id: AdapterId,
1104 ) -> wgt::DownlevelCapabilities {
1105 let adapter = self.hub.adapters.get(adapter_id);
1106 adapter.downlevel_capabilities()
1107 }
1108
1109 pub fn adapter_get_presentation_timestamp(
1110 &self,
1111 adapter_id: AdapterId,
1112 ) -> wgt::PresentationTimestamp {
1113 let adapter = self.hub.adapters.get(adapter_id);
1114 adapter.get_presentation_timestamp()
1115 }
1116
1117 pub fn adapter_drop(&self, adapter_id: AdapterId) {
1118 profiling::scope!("Adapter::drop");
1119 api_log!("Adapter::drop {adapter_id:?}");
1120
1121 self.hub.adapters.remove(adapter_id);
1122 }
1123}
1124
1125impl Global {
1126 pub fn adapter_request_device(
1127 &self,
1128 adapter_id: AdapterId,
1129 desc: &DeviceDescriptor,
1130 device_id_in: Option<DeviceId>,
1131 queue_id_in: Option<QueueId>,
1132 ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1133 profiling::scope!("Adapter::request_device");
1134 api_log!("Adapter::request_device");
1135
1136 let device_fid = self.hub.devices.prepare(device_id_in);
1137 let queue_fid = self.hub.queues.prepare(queue_id_in);
1138
1139 let adapter = self.hub.adapters.get(adapter_id);
1140 let (device, queue) = adapter.create_device_and_queue(desc, self.instance.flags)?;
1141
1142 let device_id = device_fid.assign(device);
1143 resource_log!("Created Device {:?}", device_id);
1144
1145 let queue_id = queue_fid.assign(queue);
1146 resource_log!("Created Queue {:?}", queue_id);
1147
1148 Ok((device_id, queue_id))
1149 }
1150
1151 pub unsafe fn create_device_from_hal(
1156 &self,
1157 adapter_id: AdapterId,
1158 hal_device: hal::DynOpenDevice,
1159 desc: &DeviceDescriptor,
1160 device_id_in: Option<DeviceId>,
1161 queue_id_in: Option<QueueId>,
1162 ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1163 profiling::scope!("Global::create_device_from_hal");
1164
1165 let devices_fid = self.hub.devices.prepare(device_id_in);
1166 let queues_fid = self.hub.queues.prepare(queue_id_in);
1167
1168 let adapter = self.hub.adapters.get(adapter_id);
1169 let (device, queue) =
1170 adapter.create_device_and_queue_from_hal(hal_device, desc, self.instance.flags)?;
1171
1172 let device_id = devices_fid.assign(device);
1173 resource_log!("Created Device {:?}", device_id);
1174
1175 let queue_id = queues_fid.assign(queue);
1176 resource_log!("Created Queue {:?}", queue_id);
1177
1178 Ok((device_id, queue_id))
1179 }
1180}