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