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