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