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 if desc
802 .required_features
803 .intersects(wgt::Features::all_experimental_mask())
804 && !desc.experimental_features.is_enabled()
805 {
806 return Err(RequestDeviceError::ExperimentalFeaturesNotEnabled(
807 desc.required_features
808 .intersection(wgt::Features::all_experimental_mask()),
809 ));
810 }
811
812 let caps = &self.raw.capabilities;
813 if Backends::PRIMARY.contains(Backends::from(self.backend()))
814 && !caps.downlevel.is_webgpu_compliant()
815 {
816 let missing_flags = wgt::DownlevelFlags::compliant() - caps.downlevel.flags;
817 log::warn!("Missing downlevel flags: {missing_flags:?}\n{DOWNLEVEL_WARNING_MESSAGE}");
818 log::warn!("{:#?}", caps.downlevel);
819 }
820
821 if desc
823 .required_features
824 .contains(wgt::Features::MAPPABLE_PRIMARY_BUFFERS)
825 && self.raw.info.device_type == wgt::DeviceType::DiscreteGpu
826 {
827 log::warn!(
828 "Feature MAPPABLE_PRIMARY_BUFFERS enabled on a discrete gpu. \
829 This is a massive performance footgun and likely not what you wanted"
830 );
831 }
832
833 if let Some(failed) = check_limits(&desc.required_limits, &caps.limits).pop() {
834 return Err(RequestDeviceError::LimitsExceeded(failed));
835 }
836
837 let open = unsafe {
838 self.raw.adapter.open(
839 desc.required_features,
840 &desc.required_limits,
841 &desc.memory_hints,
842 )
843 }
844 .map_err(DeviceError::from_hal)?;
845
846 self.create_device_and_queue_from_hal(open, desc, instance_flags)
847 }
848}
849
850crate::impl_resource_type!(Adapter);
851crate::impl_storage_item!(Adapter);
852
853#[derive(Clone, Debug, Error)]
854#[non_exhaustive]
855pub enum GetSurfaceSupportError {
856 #[error("Surface is not supported for the specified backend {0}")]
857 NotSupportedByBackend(Backend),
858 #[error("Failed to retrieve surface capabilities for the specified adapter.")]
859 FailedToRetrieveSurfaceCapabilitiesForAdapter,
860}
861
862#[derive(Clone, Debug, Error)]
863#[non_exhaustive]
865pub enum RequestDeviceError {
866 #[error(transparent)]
867 Device(#[from] DeviceError),
868 #[error(transparent)]
869 LimitsExceeded(#[from] FailedLimit),
870 #[error("Failed to initialize Timestamp Normalizer")]
871 TimestampNormalizerInitFailed(#[from] TimestampNormalizerInitError),
872 #[error("Unsupported features were requested: {0}")]
873 UnsupportedFeature(wgt::Features),
874 #[error(
875 "Some experimental features, {0}, were requested, but experimental features are not enabled"
876 )]
877 ExperimentalFeaturesNotEnabled(wgt::Features),
878}
879
880#[derive(Clone, Debug, Error)]
881#[non_exhaustive]
882pub enum CreateSurfaceError {
883 #[error("The backend {0} was not enabled on the instance.")]
884 BackendNotEnabled(Backend),
885 #[error("Failed to create surface for any enabled backend: {0:?}")]
886 FailedToCreateSurfaceForAnyBackend(HashMap<Backend, hal::InstanceError>),
887}
888
889impl Global {
890 #[cfg(feature = "raw-window-handle")]
908 pub unsafe fn instance_create_surface(
909 &self,
910 display_handle: raw_window_handle::RawDisplayHandle,
911 window_handle: raw_window_handle::RawWindowHandle,
912 id_in: Option<SurfaceId>,
913 ) -> Result<SurfaceId, CreateSurfaceError> {
914 let surface = unsafe { self.instance.create_surface(display_handle, window_handle) }?;
915 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
916 Ok(id)
917 }
918
919 #[cfg(all(unix, not(target_vendor = "apple"), not(target_family = "wasm")))]
930 pub unsafe fn instance_create_surface_from_drm(
931 &self,
932 fd: i32,
933 plane: u32,
934 connector_id: u32,
935 width: u32,
936 height: u32,
937 refresh_rate: u32,
938 id_in: Option<SurfaceId>,
939 ) -> Result<SurfaceId, CreateSurfaceError> {
940 let surface = unsafe {
941 self.instance.create_surface_from_drm(
942 fd,
943 plane,
944 connector_id,
945 width,
946 height,
947 refresh_rate,
948 )
949 }?;
950 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
951
952 Ok(id)
953 }
954
955 #[cfg(metal)]
959 pub unsafe fn instance_create_surface_metal(
960 &self,
961 layer: *mut core::ffi::c_void,
962 id_in: Option<SurfaceId>,
963 ) -> Result<SurfaceId, CreateSurfaceError> {
964 let surface = unsafe { self.instance.create_surface_metal(layer) }?;
965 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
966 Ok(id)
967 }
968
969 #[cfg(dx12)]
970 pub unsafe fn instance_create_surface_from_visual(
974 &self,
975 visual: *mut core::ffi::c_void,
976 id_in: Option<SurfaceId>,
977 ) -> Result<SurfaceId, CreateSurfaceError> {
978 let surface = unsafe { self.instance.create_surface_from_visual(visual) }?;
979 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
980 Ok(id)
981 }
982
983 #[cfg(dx12)]
984 pub unsafe fn instance_create_surface_from_surface_handle(
988 &self,
989 surface_handle: *mut core::ffi::c_void,
990 id_in: Option<SurfaceId>,
991 ) -> Result<SurfaceId, CreateSurfaceError> {
992 let surface = unsafe {
993 self.instance
994 .create_surface_from_surface_handle(surface_handle)
995 }?;
996 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
997 Ok(id)
998 }
999
1000 #[cfg(dx12)]
1001 pub unsafe fn instance_create_surface_from_swap_chain_panel(
1005 &self,
1006 swap_chain_panel: *mut core::ffi::c_void,
1007 id_in: Option<SurfaceId>,
1008 ) -> Result<SurfaceId, CreateSurfaceError> {
1009 let surface = unsafe {
1010 self.instance
1011 .create_surface_from_swap_chain_panel(swap_chain_panel)
1012 }?;
1013 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1014 Ok(id)
1015 }
1016
1017 pub fn surface_drop(&self, id: SurfaceId) {
1018 profiling::scope!("Surface::drop");
1019
1020 api_log!("Surface::drop {id:?}");
1021
1022 self.surfaces.remove(id);
1023 }
1024
1025 pub fn enumerate_adapters(&self, backends: Backends) -> Vec<AdapterId> {
1026 let adapters = self.instance.enumerate_adapters(backends);
1027 adapters
1028 .into_iter()
1029 .map(|adapter| self.hub.adapters.prepare(None).assign(Arc::new(adapter)))
1030 .collect()
1031 }
1032
1033 pub fn request_adapter(
1034 &self,
1035 desc: &RequestAdapterOptions,
1036 backends: Backends,
1037 id_in: Option<AdapterId>,
1038 ) -> Result<AdapterId, wgt::RequestAdapterError> {
1039 let compatible_surface = desc.compatible_surface.map(|id| self.surfaces.get(id));
1040 let desc = wgt::RequestAdapterOptions {
1041 power_preference: desc.power_preference,
1042 force_fallback_adapter: desc.force_fallback_adapter,
1043 compatible_surface: compatible_surface.as_deref(),
1044 };
1045 let adapter = self.instance.request_adapter(&desc, backends)?;
1046 let id = self.hub.adapters.prepare(id_in).assign(Arc::new(adapter));
1047 Ok(id)
1048 }
1049
1050 pub unsafe fn create_adapter_from_hal(
1054 &self,
1055 hal_adapter: hal::DynExposedAdapter,
1056 input: Option<AdapterId>,
1057 ) -> AdapterId {
1058 profiling::scope!("Instance::create_adapter_from_hal");
1059
1060 let fid = self.hub.adapters.prepare(input);
1061 let id = fid.assign(Arc::new(Adapter::new(hal_adapter)));
1062
1063 resource_log!("Created Adapter {:?}", id);
1064 id
1065 }
1066
1067 pub fn adapter_get_info(&self, adapter_id: AdapterId) -> wgt::AdapterInfo {
1068 let adapter = self.hub.adapters.get(adapter_id);
1069 adapter.get_info()
1070 }
1071
1072 pub fn adapter_get_texture_format_features(
1073 &self,
1074 adapter_id: AdapterId,
1075 format: wgt::TextureFormat,
1076 ) -> wgt::TextureFormatFeatures {
1077 let adapter = self.hub.adapters.get(adapter_id);
1078 adapter.get_texture_format_features(format)
1079 }
1080
1081 pub fn adapter_features(&self, adapter_id: AdapterId) -> wgt::Features {
1082 let adapter = self.hub.adapters.get(adapter_id);
1083 adapter.features()
1084 }
1085
1086 pub fn adapter_limits(&self, adapter_id: AdapterId) -> wgt::Limits {
1087 let adapter = self.hub.adapters.get(adapter_id);
1088 adapter.limits()
1089 }
1090
1091 pub fn adapter_downlevel_capabilities(
1092 &self,
1093 adapter_id: AdapterId,
1094 ) -> wgt::DownlevelCapabilities {
1095 let adapter = self.hub.adapters.get(adapter_id);
1096 adapter.downlevel_capabilities()
1097 }
1098
1099 pub fn adapter_get_presentation_timestamp(
1100 &self,
1101 adapter_id: AdapterId,
1102 ) -> wgt::PresentationTimestamp {
1103 let adapter = self.hub.adapters.get(adapter_id);
1104 adapter.get_presentation_timestamp()
1105 }
1106
1107 pub fn adapter_drop(&self, adapter_id: AdapterId) {
1108 profiling::scope!("Adapter::drop");
1109 api_log!("Adapter::drop {adapter_id:?}");
1110
1111 self.hub.adapters.remove(adapter_id);
1112 }
1113}
1114
1115impl Global {
1116 pub fn adapter_request_device(
1117 &self,
1118 adapter_id: AdapterId,
1119 desc: &DeviceDescriptor,
1120 device_id_in: Option<DeviceId>,
1121 queue_id_in: Option<QueueId>,
1122 ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1123 profiling::scope!("Adapter::request_device");
1124 api_log!("Adapter::request_device");
1125
1126 let device_fid = self.hub.devices.prepare(device_id_in);
1127 let queue_fid = self.hub.queues.prepare(queue_id_in);
1128
1129 let adapter = self.hub.adapters.get(adapter_id);
1130 let (device, queue) = adapter.create_device_and_queue(desc, self.instance.flags)?;
1131
1132 let device_id = device_fid.assign(device);
1133 resource_log!("Created Device {:?}", device_id);
1134
1135 let queue_id = queue_fid.assign(queue);
1136 resource_log!("Created Queue {:?}", queue_id);
1137
1138 Ok((device_id, queue_id))
1139 }
1140
1141 pub unsafe fn create_device_from_hal(
1146 &self,
1147 adapter_id: AdapterId,
1148 hal_device: hal::DynOpenDevice,
1149 desc: &DeviceDescriptor,
1150 device_id_in: Option<DeviceId>,
1151 queue_id_in: Option<QueueId>,
1152 ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1153 profiling::scope!("Global::create_device_from_hal");
1154
1155 let devices_fid = self.hub.devices.prepare(device_id_in);
1156 let queues_fid = self.hub.queues.prepare(queue_id_in);
1157
1158 let adapter = self.hub.adapters.get(adapter_id);
1159 let (device, queue) =
1160 adapter.create_device_and_queue_from_hal(hal_device, desc, self.instance.flags)?;
1161
1162 let device_id = devices_fid.assign(device);
1163 resource_log!("Created Device {:?}", device_id);
1164
1165 let queue_id = queues_fid.assign(queue);
1166 resource_log!("Created Queue {:?}", queue_id);
1167
1168 Ok((device_id, queue_id))
1169 }
1170}