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(vulkan)]
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(unix, not(target_vendor = "apple"), not(target_family = "wasm")))]
297 #[cfg_attr(not(vulkan), expect(unused_variables))]
298 pub unsafe fn create_surface_from_drm(
299 &self,
300 fd: i32,
301 plane: u32,
302 connector_id: u32,
303 width: u32,
304 height: u32,
305 refresh_rate: u32,
306 ) -> Result<Surface, CreateSurfaceError> {
307 profiling::scope!("Instance::create_surface_from_drm");
308
309 let mut errors = HashMap::default();
310 let mut surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>> =
311 HashMap::default();
312
313 #[cfg(vulkan)]
314 {
315 let instance = unsafe { self.as_hal::<hal::api::Vulkan>() }
316 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Vulkan))?;
317
318 match unsafe {
320 instance.create_surface_from_drm(
321 fd,
322 plane,
323 connector_id,
324 width,
325 height,
326 refresh_rate,
327 )
328 } {
329 Ok(surface) => {
330 surface_per_backend.insert(Backend::Vulkan, Box::new(surface));
331 }
332 Err(err) => {
333 errors.insert(Backend::Vulkan, err);
334 }
335 }
336 }
337
338 if surface_per_backend.is_empty() {
339 Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
340 errors,
341 ))
342 } else {
343 let surface = Surface {
344 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
345 surface_per_backend,
346 };
347
348 Ok(surface)
349 }
350 }
351
352 #[cfg(metal)]
356 pub unsafe fn create_surface_metal(
357 &self,
358 layer: *mut core::ffi::c_void,
359 ) -> Result<Surface, CreateSurfaceError> {
360 profiling::scope!("Instance::create_surface_metal");
361
362 let instance = unsafe { self.as_hal::<hal::api::Metal>() }
363 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Metal))?;
364
365 let layer = layer.cast();
366 let layer = unsafe { &*layer };
378 let raw_surface: Box<dyn hal::DynSurface> =
379 Box::new(instance.create_surface_from_layer(layer));
380
381 let surface = Surface {
382 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
383 surface_per_backend: core::iter::once((Backend::Metal, raw_surface)).collect(),
384 };
385
386 Ok(surface)
387 }
388
389 #[cfg(dx12)]
390 fn create_surface_dx12(
391 &self,
392 create_surface_func: impl FnOnce(&hal::dx12::Instance) -> hal::dx12::Surface,
393 ) -> Result<Surface, CreateSurfaceError> {
394 let instance = unsafe { self.as_hal::<hal::api::Dx12>() }
395 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Dx12))?;
396 let surface: Box<dyn hal::DynSurface> = Box::new(create_surface_func(instance));
397
398 let surface = Surface {
399 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
400 surface_per_backend: core::iter::once((Backend::Dx12, surface)).collect(),
401 };
402
403 Ok(surface)
404 }
405
406 #[cfg(dx12)]
407 pub unsafe fn create_surface_from_visual(
411 &self,
412 visual: *mut core::ffi::c_void,
413 ) -> Result<Surface, CreateSurfaceError> {
414 profiling::scope!("Instance::instance_create_surface_from_visual");
415 self.create_surface_dx12(|inst| unsafe { inst.create_surface_from_visual(visual) })
416 }
417
418 #[cfg(dx12)]
419 pub unsafe fn create_surface_from_surface_handle(
423 &self,
424 surface_handle: *mut core::ffi::c_void,
425 ) -> Result<Surface, CreateSurfaceError> {
426 profiling::scope!("Instance::instance_create_surface_from_surface_handle");
427 self.create_surface_dx12(|inst| unsafe {
428 inst.create_surface_from_surface_handle(surface_handle)
429 })
430 }
431
432 #[cfg(dx12)]
433 pub unsafe fn create_surface_from_swap_chain_panel(
437 &self,
438 swap_chain_panel: *mut core::ffi::c_void,
439 ) -> Result<Surface, CreateSurfaceError> {
440 profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel");
441 self.create_surface_dx12(|inst| unsafe {
442 inst.create_surface_from_swap_chain_panel(swap_chain_panel)
443 })
444 }
445
446 pub fn enumerate_adapters(&self, backends: Backends) -> Vec<Adapter> {
447 profiling::scope!("Instance::enumerate_adapters");
448 api_log!("Instance::enumerate_adapters");
449
450 let mut adapters = Vec::new();
451 for (_backend, instance) in self
452 .instance_per_backend
453 .iter()
454 .filter(|(backend, _)| backends.contains(Backends::from(*backend)))
455 {
456 profiling::scope!("enumerating", &*alloc::format!("{_backend:?}"));
459
460 let hal_adapters = unsafe { instance.enumerate_adapters(None) };
461 for raw in hal_adapters {
462 let adapter = Adapter::new(raw);
463 api_log_debug!("Adapter {:?}", adapter.raw.info);
464 adapters.push(adapter);
465 }
466 }
467 adapters
468 }
469
470 pub fn request_adapter(
471 &self,
472 desc: &wgt::RequestAdapterOptions<&Surface>,
473 backends: Backends,
474 ) -> Result<Adapter, wgt::RequestAdapterError> {
475 profiling::scope!("Instance::request_adapter");
476 api_log!("Instance::request_adapter");
477
478 let mut adapters = Vec::new();
479 let mut incompatible_surface_backends = Backends::empty();
480 let mut no_fallback_backends = Backends::empty();
481 let mut no_adapter_backends = Backends::empty();
482
483 for &(backend, ref instance) in self
484 .instance_per_backend
485 .iter()
486 .filter(|&&(backend, _)| backends.contains(Backends::from(backend)))
487 {
488 let compatible_hal_surface = desc
489 .compatible_surface
490 .and_then(|surface| surface.raw(backend));
491
492 let mut backend_adapters =
493 unsafe { instance.enumerate_adapters(compatible_hal_surface) };
494 if backend_adapters.is_empty() {
495 log::debug!("enabled backend `{backend:?}` has no adapters");
496 no_adapter_backends |= Backends::from(backend);
497 continue;
499 }
500
501 if desc.force_fallback_adapter {
502 log::debug!("Filtering `{backend:?}` for `force_fallback_adapter`");
503 backend_adapters.retain(|exposed| {
504 let keep = exposed.info.device_type == wgt::DeviceType::Cpu;
505 if !keep {
506 log::debug!("* Eliminating adapter `{}`", exposed.info.name);
507 }
508 keep
509 });
510 if backend_adapters.is_empty() {
511 log::debug!("* Backend `{backend:?}` has no fallback adapters");
512 no_fallback_backends |= Backends::from(backend);
513 continue;
514 }
515 }
516
517 if let Some(surface) = desc.compatible_surface {
518 backend_adapters.retain(|exposed| {
519 let capabilities = surface.get_capabilities_with_raw(exposed);
520 if let Err(err) = capabilities {
521 log::debug!(
522 "Adapter {:?} not compatible with surface: {}",
523 exposed.info,
524 err
525 );
526 incompatible_surface_backends |= Backends::from(backend);
527 false
528 } else {
529 true
530 }
531 });
532 if backend_adapters.is_empty() {
533 incompatible_surface_backends |= Backends::from(backend);
534 continue;
535 }
536 }
537 adapters.extend(backend_adapters);
538 }
539
540 match desc.power_preference {
541 PowerPreference::LowPower => {
542 sort(&mut adapters, true);
543 }
544 PowerPreference::HighPerformance => {
545 sort(&mut adapters, false);
546 }
547 PowerPreference::None => {}
548 };
549
550 fn sort(adapters: &mut [hal::DynExposedAdapter], prefer_integrated_gpu: bool) {
551 adapters
552 .sort_by_key(|adapter| get_order(adapter.info.device_type, prefer_integrated_gpu));
553 }
554
555 fn get_order(device_type: wgt::DeviceType, prefer_integrated_gpu: bool) -> u8 {
556 match device_type {
564 wgt::DeviceType::DiscreteGpu if prefer_integrated_gpu => 2,
565 wgt::DeviceType::IntegratedGpu if prefer_integrated_gpu => 1,
566 wgt::DeviceType::DiscreteGpu => 1,
567 wgt::DeviceType::IntegratedGpu => 2,
568 wgt::DeviceType::Other => 3,
569 wgt::DeviceType::VirtualGpu => 4,
570 wgt::DeviceType::Cpu => 5,
571 }
572 }
573
574 if adapters.is_empty() {
577 log::debug!("Request adapter didn't find compatible adapters.");
578 } else {
579 log::debug!(
580 "Found {} compatible adapters. Sorted by preference:",
581 adapters.len()
582 );
583 for adapter in &adapters {
584 log::debug!("* {:?}", adapter.info);
585 }
586 }
587
588 if let Some(adapter) = adapters.into_iter().next() {
589 api_log_debug!("Request adapter result {:?}", adapter.info);
590 let adapter = Adapter::new(adapter);
591 Ok(adapter)
592 } else {
593 Err(wgt::RequestAdapterError::NotFound {
594 supported_backends: self.supported_backends,
595 requested_backends: self.requested_backends,
596 active_backends: self.active_backends(),
597 no_fallback_backends,
598 no_adapter_backends,
599 incompatible_surface_backends,
600 })
601 }
602 }
603
604 fn active_backends(&self) -> Backends {
605 self.instance_per_backend
606 .iter()
607 .map(|&(backend, _)| Backends::from(backend))
608 .collect()
609 }
610}
611
612pub struct Surface {
613 pub(crate) presentation: Mutex<Option<Presentation>>,
614 pub surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>>,
615}
616
617impl ResourceType for Surface {
618 const TYPE: &'static str = "Surface";
619}
620impl crate::storage::StorageItem for Surface {
621 type Marker = markers::Surface;
622}
623
624impl Surface {
625 pub fn get_capabilities(
626 &self,
627 adapter: &Adapter,
628 ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
629 self.get_capabilities_with_raw(&adapter.raw)
630 }
631
632 pub fn get_capabilities_with_raw(
633 &self,
634 adapter: &hal::DynExposedAdapter,
635 ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
636 let backend = adapter.backend();
637 let suf = self
638 .raw(backend)
639 .ok_or(GetSurfaceSupportError::NotSupportedByBackend(backend))?;
640 profiling::scope!("surface_capabilities");
641 let caps = unsafe { adapter.adapter.surface_capabilities(suf) }
642 .ok_or(GetSurfaceSupportError::FailedToRetrieveSurfaceCapabilitiesForAdapter)?;
643 Ok(caps)
644 }
645
646 pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynSurface> {
647 self.surface_per_backend
648 .get(&backend)
649 .map(|surface| surface.as_ref())
650 }
651}
652
653impl Drop for Surface {
654 fn drop(&mut self) {
655 if let Some(present) = self.presentation.lock().take() {
656 for (&backend, surface) in &self.surface_per_backend {
657 if backend == present.device.backend() {
658 unsafe { surface.unconfigure(present.device.raw()) };
659 }
660 }
661 }
662 }
663}
664
665pub struct Adapter {
666 pub(crate) raw: hal::DynExposedAdapter,
667}
668
669impl Adapter {
670 pub fn new(mut raw: hal::DynExposedAdapter) -> Self {
671 const MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND: u32 = 32;
673
674 let limits = &mut raw.capabilities.limits;
675
676 limits.min_uniform_buffer_offset_alignment = limits
677 .min_uniform_buffer_offset_alignment
678 .max(MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND);
679 limits.min_storage_buffer_offset_alignment = limits
680 .min_storage_buffer_offset_alignment
681 .max(MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND);
682
683 Self { raw }
684 }
685
686 pub fn backend(&self) -> Backend {
688 self.raw.backend()
689 }
690
691 pub fn is_surface_supported(&self, surface: &Surface) -> bool {
692 surface.get_capabilities(self).is_ok()
697 }
698
699 pub fn get_info(&self) -> wgt::AdapterInfo {
700 self.raw.info.clone()
701 }
702
703 pub fn features(&self) -> wgt::Features {
704 self.raw.features
705 }
706
707 pub fn limits(&self) -> wgt::Limits {
708 self.raw.capabilities.limits.clone()
709 }
710
711 pub fn downlevel_capabilities(&self) -> wgt::DownlevelCapabilities {
712 self.raw.capabilities.downlevel.clone()
713 }
714
715 pub fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
716 unsafe { self.raw.adapter.get_presentation_timestamp() }
717 }
718
719 pub fn cooperative_matrix_properties(&self) -> Vec<wgt::CooperativeMatrixProperties> {
720 self.raw.capabilities.cooperative_matrix_properties.clone()
721 }
722
723 pub fn get_texture_format_features(
724 &self,
725 format: wgt::TextureFormat,
726 ) -> wgt::TextureFormatFeatures {
727 use hal::TextureFormatCapabilities as Tfc;
728
729 let caps = unsafe { self.raw.adapter.texture_format_capabilities(format) };
730 let mut allowed_usages = wgt::TextureUsages::empty();
731
732 allowed_usages.set(wgt::TextureUsages::COPY_SRC, caps.contains(Tfc::COPY_SRC));
733 allowed_usages.set(wgt::TextureUsages::COPY_DST, caps.contains(Tfc::COPY_DST));
734 allowed_usages.set(
735 wgt::TextureUsages::TEXTURE_BINDING,
736 caps.contains(Tfc::SAMPLED),
737 );
738 allowed_usages.set(
739 wgt::TextureUsages::STORAGE_BINDING,
740 caps.intersects(
741 Tfc::STORAGE_WRITE_ONLY
742 | Tfc::STORAGE_READ_ONLY
743 | Tfc::STORAGE_READ_WRITE
744 | Tfc::STORAGE_ATOMIC,
745 ),
746 );
747 allowed_usages.set(
748 wgt::TextureUsages::RENDER_ATTACHMENT | wgt::TextureUsages::TRANSIENT,
749 caps.intersects(Tfc::COLOR_ATTACHMENT | Tfc::DEPTH_STENCIL_ATTACHMENT),
750 );
751 allowed_usages.set(
752 wgt::TextureUsages::STORAGE_ATOMIC,
753 caps.contains(Tfc::STORAGE_ATOMIC),
754 );
755
756 let mut flags = wgt::TextureFormatFeatureFlags::empty();
757 flags.set(
758 wgt::TextureFormatFeatureFlags::STORAGE_READ_ONLY,
759 caps.contains(Tfc::STORAGE_READ_ONLY),
760 );
761 flags.set(
762 wgt::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY,
763 caps.contains(Tfc::STORAGE_WRITE_ONLY),
764 );
765 flags.set(
766 wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE,
767 caps.contains(Tfc::STORAGE_READ_WRITE),
768 );
769
770 flags.set(
771 wgt::TextureFormatFeatureFlags::STORAGE_ATOMIC,
772 caps.contains(Tfc::STORAGE_ATOMIC),
773 );
774
775 flags.set(
776 wgt::TextureFormatFeatureFlags::FILTERABLE,
777 caps.contains(Tfc::SAMPLED_LINEAR),
778 );
779
780 flags.set(
781 wgt::TextureFormatFeatureFlags::BLENDABLE,
782 caps.contains(Tfc::COLOR_ATTACHMENT_BLEND),
783 );
784
785 flags.set(
786 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X2,
787 caps.contains(Tfc::MULTISAMPLE_X2),
788 );
789 flags.set(
790 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X4,
791 caps.contains(Tfc::MULTISAMPLE_X4),
792 );
793 flags.set(
794 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X8,
795 caps.contains(Tfc::MULTISAMPLE_X8),
796 );
797 flags.set(
798 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X16,
799 caps.contains(Tfc::MULTISAMPLE_X16),
800 );
801
802 flags.set(
803 wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE,
804 caps.contains(Tfc::MULTISAMPLE_RESOLVE),
805 );
806
807 wgt::TextureFormatFeatures {
808 allowed_usages,
809 flags,
810 }
811 }
812
813 #[allow(clippy::type_complexity)]
814 fn create_device_and_queue_from_hal(
815 self: &Arc<Self>,
816 hal_device: hal::DynOpenDevice,
817 desc: &DeviceDescriptor,
818 instance_flags: wgt::InstanceFlags,
819 ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
820 api_log!("Adapter::create_device");
821
822 let device = Device::new(hal_device.device, self, desc, instance_flags)?;
823 let device = Arc::new(device);
824
825 let queue = Queue::new(device.clone(), hal_device.queue, instance_flags)?;
826 let queue = Arc::new(queue);
827
828 device.set_queue(&queue);
829 device.late_init_resources_with_queue()?;
830
831 Ok((device, queue))
832 }
833
834 pub fn create_device_and_queue(
835 self: &Arc<Self>,
836 desc: &DeviceDescriptor,
837 instance_flags: wgt::InstanceFlags,
838 ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
839 if !self.raw.features.contains(desc.required_features) {
841 return Err(RequestDeviceError::UnsupportedFeature(
842 desc.required_features - self.raw.features,
843 ));
844 }
845
846 if desc
848 .required_features
849 .intersects(wgt::Features::all_experimental_mask())
850 && !desc.experimental_features.is_enabled()
851 {
852 return Err(RequestDeviceError::ExperimentalFeaturesNotEnabled(
853 desc.required_features
854 .intersection(wgt::Features::all_experimental_mask()),
855 ));
856 }
857
858 let caps = &self.raw.capabilities;
859 if Backends::PRIMARY.contains(Backends::from(self.backend()))
860 && !caps.downlevel.is_webgpu_compliant()
861 {
862 let missing_flags = wgt::DownlevelFlags::compliant() - caps.downlevel.flags;
863 log::warn!("Missing downlevel flags: {missing_flags:?}\n{DOWNLEVEL_WARNING_MESSAGE}");
864 log::warn!("{:#?}", caps.downlevel);
865 }
866
867 if desc
869 .required_features
870 .contains(wgt::Features::MAPPABLE_PRIMARY_BUFFERS)
871 && self.raw.info.device_type == wgt::DeviceType::DiscreteGpu
872 {
873 log::warn!(
874 "Feature MAPPABLE_PRIMARY_BUFFERS enabled on a discrete gpu. \
875 This is a massive performance footgun and likely not what you wanted"
876 );
877 }
878
879 if let Some(failed) = check_limits(&desc.required_limits, &caps.limits).pop() {
880 return Err(RequestDeviceError::LimitsExceeded(failed));
881 }
882
883 let open = unsafe {
884 self.raw.adapter.open(
885 desc.required_features,
886 &desc.required_limits,
887 &desc.memory_hints,
888 )
889 }
890 .map_err(DeviceError::from_hal)?;
891
892 self.create_device_and_queue_from_hal(open, desc, instance_flags)
893 }
894}
895
896crate::impl_resource_type!(Adapter);
897crate::impl_storage_item!(Adapter);
898
899#[derive(Clone, Debug, Error)]
900#[non_exhaustive]
901pub enum GetSurfaceSupportError {
902 #[error("Surface is not supported for the specified backend {0}")]
903 NotSupportedByBackend(Backend),
904 #[error("Failed to retrieve surface capabilities for the specified adapter.")]
905 FailedToRetrieveSurfaceCapabilitiesForAdapter,
906}
907
908#[derive(Clone, Debug, Error)]
909#[non_exhaustive]
911pub enum RequestDeviceError {
912 #[error(transparent)]
913 Device(#[from] DeviceError),
914 #[error(transparent)]
915 LimitsExceeded(#[from] FailedLimit),
916 #[error("Failed to initialize Timestamp Normalizer")]
917 TimestampNormalizerInitFailed(#[from] TimestampNormalizerInitError),
918 #[error("Unsupported features were requested: {0}")]
919 UnsupportedFeature(wgt::Features),
920 #[error(
921 "Some experimental features, {0}, were requested, but experimental features are not enabled"
922 )]
923 ExperimentalFeaturesNotEnabled(wgt::Features),
924}
925
926#[derive(Clone, Debug, Error)]
927#[non_exhaustive]
928pub enum CreateSurfaceError {
929 #[error("The backend {0} was not enabled on the instance.")]
930 BackendNotEnabled(Backend),
931 #[error("Failed to create surface for any enabled backend: {0:?}")]
932 FailedToCreateSurfaceForAnyBackend(HashMap<Backend, hal::InstanceError>),
933 #[error("The display handle used to create this Instance does not match the one used to create a surface on it")]
934 MismatchingDisplayHandle,
935}
936
937impl Global {
938 pub unsafe fn instance_create_surface(
956 &self,
957 display_handle: raw_window_handle::RawDisplayHandle,
958 window_handle: raw_window_handle::RawWindowHandle,
959 id_in: Option<SurfaceId>,
960 ) -> Result<SurfaceId, CreateSurfaceError> {
961 let surface = unsafe { self.instance.create_surface(display_handle, window_handle) }?;
962 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
963 Ok(id)
964 }
965
966 #[cfg(all(unix, not(target_vendor = "apple"), not(target_family = "wasm")))]
977 pub unsafe fn instance_create_surface_from_drm(
978 &self,
979 fd: i32,
980 plane: u32,
981 connector_id: u32,
982 width: u32,
983 height: u32,
984 refresh_rate: u32,
985 id_in: Option<SurfaceId>,
986 ) -> Result<SurfaceId, CreateSurfaceError> {
987 let surface = unsafe {
988 self.instance.create_surface_from_drm(
989 fd,
990 plane,
991 connector_id,
992 width,
993 height,
994 refresh_rate,
995 )
996 }?;
997 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
998
999 Ok(id)
1000 }
1001
1002 #[cfg(metal)]
1006 pub unsafe fn instance_create_surface_metal(
1007 &self,
1008 layer: *mut core::ffi::c_void,
1009 id_in: Option<SurfaceId>,
1010 ) -> Result<SurfaceId, CreateSurfaceError> {
1011 let surface = unsafe { self.instance.create_surface_metal(layer) }?;
1012 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1013 Ok(id)
1014 }
1015
1016 #[cfg(dx12)]
1017 pub unsafe fn instance_create_surface_from_visual(
1021 &self,
1022 visual: *mut core::ffi::c_void,
1023 id_in: Option<SurfaceId>,
1024 ) -> Result<SurfaceId, CreateSurfaceError> {
1025 let surface = unsafe { self.instance.create_surface_from_visual(visual) }?;
1026 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1027 Ok(id)
1028 }
1029
1030 #[cfg(dx12)]
1031 pub unsafe fn instance_create_surface_from_surface_handle(
1035 &self,
1036 surface_handle: *mut core::ffi::c_void,
1037 id_in: Option<SurfaceId>,
1038 ) -> Result<SurfaceId, CreateSurfaceError> {
1039 let surface = unsafe {
1040 self.instance
1041 .create_surface_from_surface_handle(surface_handle)
1042 }?;
1043 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1044 Ok(id)
1045 }
1046
1047 #[cfg(dx12)]
1048 pub unsafe fn instance_create_surface_from_swap_chain_panel(
1052 &self,
1053 swap_chain_panel: *mut core::ffi::c_void,
1054 id_in: Option<SurfaceId>,
1055 ) -> Result<SurfaceId, CreateSurfaceError> {
1056 let surface = unsafe {
1057 self.instance
1058 .create_surface_from_swap_chain_panel(swap_chain_panel)
1059 }?;
1060 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
1061 Ok(id)
1062 }
1063
1064 pub fn surface_drop(&self, id: SurfaceId) {
1065 profiling::scope!("Surface::drop");
1066
1067 api_log!("Surface::drop {id:?}");
1068
1069 self.surfaces.remove(id);
1070 }
1071
1072 pub fn enumerate_adapters(&self, backends: Backends) -> Vec<AdapterId> {
1073 let adapters = self.instance.enumerate_adapters(backends);
1074 adapters
1075 .into_iter()
1076 .map(|adapter| self.hub.adapters.prepare(None).assign(Arc::new(adapter)))
1077 .collect()
1078 }
1079
1080 pub fn request_adapter(
1081 &self,
1082 desc: &RequestAdapterOptions,
1083 backends: Backends,
1084 id_in: Option<AdapterId>,
1085 ) -> Result<AdapterId, wgt::RequestAdapterError> {
1086 let compatible_surface = desc.compatible_surface.map(|id| self.surfaces.get(id));
1087 let desc = wgt::RequestAdapterOptions {
1088 power_preference: desc.power_preference,
1089 force_fallback_adapter: desc.force_fallback_adapter,
1090 compatible_surface: compatible_surface.as_deref(),
1091 };
1092 let adapter = self.instance.request_adapter(&desc, backends)?;
1093 let id = self.hub.adapters.prepare(id_in).assign(Arc::new(adapter));
1094 Ok(id)
1095 }
1096
1097 pub unsafe fn create_adapter_from_hal(
1101 &self,
1102 hal_adapter: hal::DynExposedAdapter,
1103 input: Option<AdapterId>,
1104 ) -> AdapterId {
1105 profiling::scope!("Instance::create_adapter_from_hal");
1106
1107 let fid = self.hub.adapters.prepare(input);
1108 let id = fid.assign(Arc::new(Adapter::new(hal_adapter)));
1109
1110 resource_log!("Created Adapter {:?}", id);
1111 id
1112 }
1113
1114 pub fn adapter_get_info(&self, adapter_id: AdapterId) -> wgt::AdapterInfo {
1115 let adapter = self.hub.adapters.get(adapter_id);
1116 adapter.get_info()
1117 }
1118
1119 pub fn adapter_get_texture_format_features(
1120 &self,
1121 adapter_id: AdapterId,
1122 format: wgt::TextureFormat,
1123 ) -> wgt::TextureFormatFeatures {
1124 let adapter = self.hub.adapters.get(adapter_id);
1125 adapter.get_texture_format_features(format)
1126 }
1127
1128 pub fn adapter_features(&self, adapter_id: AdapterId) -> wgt::Features {
1129 let adapter = self.hub.adapters.get(adapter_id);
1130 adapter.features()
1131 }
1132
1133 pub fn adapter_limits(&self, adapter_id: AdapterId) -> wgt::Limits {
1134 let adapter = self.hub.adapters.get(adapter_id);
1135 adapter.limits()
1136 }
1137
1138 pub fn adapter_downlevel_capabilities(
1139 &self,
1140 adapter_id: AdapterId,
1141 ) -> wgt::DownlevelCapabilities {
1142 let adapter = self.hub.adapters.get(adapter_id);
1143 adapter.downlevel_capabilities()
1144 }
1145
1146 pub fn adapter_get_presentation_timestamp(
1147 &self,
1148 adapter_id: AdapterId,
1149 ) -> wgt::PresentationTimestamp {
1150 let adapter = self.hub.adapters.get(adapter_id);
1151 adapter.get_presentation_timestamp()
1152 }
1153
1154 pub fn adapter_cooperative_matrix_properties(
1155 &self,
1156 adapter_id: AdapterId,
1157 ) -> Vec<wgt::CooperativeMatrixProperties> {
1158 let adapter = self.hub.adapters.get(adapter_id);
1159 adapter.cooperative_matrix_properties()
1160 }
1161
1162 pub fn adapter_drop(&self, adapter_id: AdapterId) {
1163 profiling::scope!("Adapter::drop");
1164 api_log!("Adapter::drop {adapter_id:?}");
1165
1166 self.hub.adapters.remove(adapter_id);
1167 }
1168}
1169
1170impl Global {
1171 pub fn adapter_request_device(
1172 &self,
1173 adapter_id: AdapterId,
1174 desc: &DeviceDescriptor,
1175 device_id_in: Option<DeviceId>,
1176 queue_id_in: Option<QueueId>,
1177 ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1178 profiling::scope!("Adapter::request_device");
1179 api_log!("Adapter::request_device");
1180
1181 let device_fid = self.hub.devices.prepare(device_id_in);
1182 let queue_fid = self.hub.queues.prepare(queue_id_in);
1183
1184 let adapter = self.hub.adapters.get(adapter_id);
1185 let (device, queue) = adapter.create_device_and_queue(desc, self.instance.flags)?;
1186
1187 let device_id = device_fid.assign(device);
1188 resource_log!("Created Device {:?}", device_id);
1189
1190 let queue_id = queue_fid.assign(queue);
1191 resource_log!("Created Queue {:?}", queue_id);
1192
1193 Ok((device_id, queue_id))
1194 }
1195
1196 pub unsafe fn create_device_from_hal(
1201 &self,
1202 adapter_id: AdapterId,
1203 hal_device: hal::DynOpenDevice,
1204 desc: &DeviceDescriptor,
1205 device_id_in: Option<DeviceId>,
1206 queue_id_in: Option<QueueId>,
1207 ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
1208 profiling::scope!("Global::create_device_from_hal");
1209
1210 let devices_fid = self.hub.devices.prepare(device_id_in);
1211 let queues_fid = self.hub.queues.prepare(queue_id_in);
1212
1213 let adapter = self.hub.adapters.get(adapter_id);
1214 let (device, queue) =
1215 adapter.create_device_and_queue_from_hal(hal_device, desc, self.instance.flags)?;
1216
1217 let device_id = devices_fid.assign(device);
1218 resource_log!("Created Device {:?}", device_id);
1219
1220 let queue_id = queues_fid.assign(queue);
1221 resource_log!("Created Queue {:?}", queue_id);
1222
1223 Ok((device_id, queue_id))
1224 }
1225}