1use std::sync::Arc;
2use std::{borrow::Cow, collections::HashMap};
3
4use crate::{
5 api_log,
6 device::{queue::Queue, resource::Device, DeviceDescriptor, DeviceError},
7 global::Global,
8 hal_api::HalApi,
9 id::{markers, AdapterId, DeviceId, QueueId, SurfaceId},
10 lock::{rank, Mutex},
11 present::Presentation,
12 resource::ResourceType,
13 resource_log, DOWNLEVEL_WARNING_MESSAGE,
14};
15
16use wgt::{Backend, Backends, PowerPreference};
17
18use thiserror::Error;
19
20pub type RequestAdapterOptions = wgt::RequestAdapterOptions<SurfaceId>;
21
22#[derive(Clone, Debug, Error)]
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24#[error("Limit '{name}' value {requested} is better than allowed {allowed}")]
25pub struct FailedLimit {
26 name: Cow<'static, str>,
27 requested: u64,
28 allowed: u64,
29}
30
31fn check_limits(requested: &wgt::Limits, allowed: &wgt::Limits) -> Vec<FailedLimit> {
32 let mut failed = Vec::new();
33
34 requested.check_limits_with_fail_fn(allowed, false, |name, requested, allowed| {
35 failed.push(FailedLimit {
36 name: Cow::Borrowed(name),
37 requested,
38 allowed,
39 })
40 });
41
42 failed
43}
44
45#[test]
46fn downlevel_default_limits_less_than_default_limits() {
47 let res = check_limits(&wgt::Limits::downlevel_defaults(), &wgt::Limits::default());
48 assert!(
49 res.is_empty(),
50 "Downlevel limits are greater than default limits",
51 )
52}
53
54#[derive(Default)]
55pub struct Instance {
56 #[allow(dead_code)]
57 pub name: String,
58 pub instance_per_backend: Vec<(Backend, Box<dyn hal::DynInstance>)>,
62 pub flags: wgt::InstanceFlags,
63}
64
65impl Instance {
66 pub fn new(name: &str, instance_desc: wgt::InstanceDescriptor) -> Self {
67 fn init<A: HalApi>(
68 _: A,
69 instance_desc: &wgt::InstanceDescriptor,
70 instance_per_backend: &mut Vec<(Backend, Box<dyn hal::DynInstance>)>,
71 ) {
72 if instance_desc.backends.contains(A::VARIANT.into()) {
73 let hal_desc = hal::InstanceDescriptor {
74 name: "wgpu",
75 flags: instance_desc.flags,
76 dx12_shader_compiler: instance_desc.dx12_shader_compiler.clone(),
77 gles_minor_version: instance_desc.gles_minor_version,
78 };
79
80 use hal::Instance as _;
81 match unsafe { A::Instance::init(&hal_desc) } {
82 Ok(instance) => {
83 log::debug!("Instance::new: created {:?} backend", A::VARIANT);
84 instance_per_backend.push((A::VARIANT, Box::new(instance)));
85 }
86 Err(err) => {
87 log::debug!(
88 "Instance::new: failed to create {:?} backend: {:?}",
89 A::VARIANT,
90 err
91 );
92 }
93 }
94 } else {
95 log::trace!("Instance::new: backend {:?} not requested", A::VARIANT);
96 }
97 }
98
99 let mut instance_per_backend = Vec::new();
100
101 #[cfg(vulkan)]
102 init(hal::api::Vulkan, &instance_desc, &mut instance_per_backend);
103 #[cfg(metal)]
104 init(hal::api::Metal, &instance_desc, &mut instance_per_backend);
105 #[cfg(dx12)]
106 init(hal::api::Dx12, &instance_desc, &mut instance_per_backend);
107 #[cfg(gles)]
108 init(hal::api::Gles, &instance_desc, &mut instance_per_backend);
109
110 Self {
111 name: name.to_string(),
112 instance_per_backend,
113 flags: instance_desc.flags,
114 }
115 }
116
117 pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynInstance> {
118 self.instance_per_backend
119 .iter()
120 .find_map(|(instance_backend, instance)| {
121 (*instance_backend == backend).then(|| instance.as_ref())
122 })
123 }
124
125 pub unsafe fn as_hal<A: HalApi>(&self) -> Option<&A::Instance> {
129 self.raw(A::VARIANT).map(|instance| {
130 instance
131 .as_any()
132 .downcast_ref()
133 .expect("Stored instance is not of the correct type")
135 })
136 }
137
138 #[cfg(feature = "raw-window-handle")]
153 pub unsafe fn create_surface(
154 &self,
155 display_handle: raw_window_handle::RawDisplayHandle,
156 window_handle: raw_window_handle::RawWindowHandle,
157 ) -> Result<Surface, CreateSurfaceError> {
158 profiling::scope!("Instance::create_surface");
159
160 let mut errors = HashMap::default();
161 let mut surface_per_backend = HashMap::default();
162
163 for (backend, instance) in &self.instance_per_backend {
164 match unsafe {
165 instance
166 .as_ref()
167 .create_surface(display_handle, window_handle)
168 } {
169 Ok(raw) => {
170 surface_per_backend.insert(*backend, raw);
171 }
172 Err(err) => {
173 log::debug!(
174 "Instance::create_surface: failed to create surface for {:?}: {:?}",
175 backend,
176 err
177 );
178 errors.insert(*backend, err);
179 }
180 }
181 }
182
183 if surface_per_backend.is_empty() {
184 Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
185 errors,
186 ))
187 } else {
188 let surface = Surface {
189 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
190 surface_per_backend,
191 };
192
193 Ok(surface)
194 }
195 }
196
197 #[cfg(metal)]
201 pub unsafe fn create_surface_metal(
202 &self,
203 layer: *mut std::ffi::c_void,
204 ) -> Result<Surface, CreateSurfaceError> {
205 profiling::scope!("Instance::create_surface_metal");
206
207 let instance = unsafe { self.as_hal::<hal::api::Metal>() }
208 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Metal))?;
209
210 let layer = layer.cast();
211 let layer = unsafe { &*layer };
223 let raw_surface: Box<dyn hal::DynSurface> =
224 Box::new(instance.create_surface_from_layer(layer));
225
226 let surface = Surface {
227 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
228 surface_per_backend: std::iter::once((Backend::Metal, raw_surface)).collect(),
229 };
230
231 Ok(surface)
232 }
233
234 #[cfg(dx12)]
235 fn create_surface_dx12(
236 &self,
237 create_surface_func: impl FnOnce(&hal::dx12::Instance) -> hal::dx12::Surface,
238 ) -> Result<Surface, CreateSurfaceError> {
239 let instance = unsafe { self.as_hal::<hal::api::Dx12>() }
240 .ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Dx12))?;
241 let surface: Box<dyn hal::DynSurface> = Box::new(create_surface_func(instance));
242
243 let surface = Surface {
244 presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
245 surface_per_backend: std::iter::once((Backend::Dx12, surface)).collect(),
246 };
247
248 Ok(surface)
249 }
250
251 #[cfg(dx12)]
252 pub unsafe fn create_surface_from_visual(
256 &self,
257 visual: *mut std::ffi::c_void,
258 ) -> Result<Surface, CreateSurfaceError> {
259 profiling::scope!("Instance::instance_create_surface_from_visual");
260 self.create_surface_dx12(|inst| unsafe { inst.create_surface_from_visual(visual) })
261 }
262
263 #[cfg(dx12)]
264 pub unsafe fn create_surface_from_surface_handle(
268 &self,
269 surface_handle: *mut std::ffi::c_void,
270 ) -> Result<Surface, CreateSurfaceError> {
271 profiling::scope!("Instance::instance_create_surface_from_surface_handle");
272 self.create_surface_dx12(|inst| unsafe {
273 inst.create_surface_from_surface_handle(surface_handle)
274 })
275 }
276
277 #[cfg(dx12)]
278 pub unsafe fn create_surface_from_swap_chain_panel(
282 &self,
283 swap_chain_panel: *mut std::ffi::c_void,
284 ) -> Result<Surface, CreateSurfaceError> {
285 profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel");
286 self.create_surface_dx12(|inst| unsafe {
287 inst.create_surface_from_swap_chain_panel(swap_chain_panel)
288 })
289 }
290
291 pub fn enumerate_adapters(&self, backends: Backends) -> Vec<Adapter> {
292 profiling::scope!("Instance::enumerate_adapters");
293 api_log!("Instance::enumerate_adapters");
294
295 let mut adapters = Vec::new();
296 for (_backend, instance) in self
297 .instance_per_backend
298 .iter()
299 .filter(|(backend, _)| backends.contains(Backends::from(*backend)))
300 {
301 profiling::scope!("enumerating", &*format!("{:?}", _backend));
304
305 let hal_adapters = unsafe { instance.enumerate_adapters(None) };
306 for raw in hal_adapters {
307 let adapter = Adapter::new(raw);
308 log::info!("Adapter {:?}", adapter.raw.info);
309 adapters.push(adapter);
310 }
311 }
312 adapters
313 }
314
315 pub fn request_adapter(
316 &self,
317 desc: &wgt::RequestAdapterOptions<&Surface>,
318 backends: Backends,
319 ) -> Result<Adapter, RequestAdapterError> {
320 profiling::scope!("Instance::request_adapter");
321 api_log!("Instance::request_adapter");
322
323 let mut adapters = Vec::new();
324
325 for (backend, instance) in self
326 .instance_per_backend
327 .iter()
328 .filter(|(backend, _)| backends.contains(Backends::from(*backend)))
329 {
330 let compatible_hal_surface = desc
331 .compatible_surface
332 .and_then(|surface| surface.raw(*backend));
333 let mut backend_adapters =
334 unsafe { instance.enumerate_adapters(compatible_hal_surface) };
335 if desc.force_fallback_adapter {
336 backend_adapters.retain(|exposed| exposed.info.device_type == wgt::DeviceType::Cpu);
337 }
338 if let Some(surface) = desc.compatible_surface {
339 backend_adapters
340 .retain(|exposed| surface.get_capabilities_with_raw(exposed).is_ok());
341 }
342 adapters.extend(backend_adapters);
343 }
344
345 match desc.power_preference {
346 PowerPreference::LowPower => {
347 sort(&mut adapters, true);
348 }
349 PowerPreference::HighPerformance => {
350 sort(&mut adapters, false);
351 }
352 PowerPreference::None => {}
353 };
354
355 fn sort(adapters: &mut [hal::DynExposedAdapter], prefer_integrated_gpu: bool) {
356 adapters.sort_by(|a, b| {
357 get_order(a.info.device_type, prefer_integrated_gpu)
358 .cmp(&get_order(b.info.device_type, prefer_integrated_gpu))
359 });
360 }
361
362 fn get_order(device_type: wgt::DeviceType, prefer_integrated_gpu: bool) -> u8 {
363 match device_type {
371 wgt::DeviceType::DiscreteGpu if prefer_integrated_gpu => 2,
372 wgt::DeviceType::IntegratedGpu if prefer_integrated_gpu => 1,
373 wgt::DeviceType::DiscreteGpu => 1,
374 wgt::DeviceType::IntegratedGpu => 2,
375 wgt::DeviceType::Other => 3,
376 wgt::DeviceType::VirtualGpu => 4,
377 wgt::DeviceType::Cpu => 5,
378 }
379 }
380
381 if let Some(adapter) = adapters.into_iter().next() {
382 log::info!("Adapter {:?}", adapter.info);
383 let adapter = Adapter::new(adapter);
384 Ok(adapter)
385 } else {
386 Err(RequestAdapterError::NotFound)
387 }
388 }
389}
390
391pub struct Surface {
392 pub(crate) presentation: Mutex<Option<Presentation>>,
393 pub surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>>,
394}
395
396impl ResourceType for Surface {
397 const TYPE: &'static str = "Surface";
398}
399impl crate::storage::StorageItem for Surface {
400 type Marker = markers::Surface;
401}
402
403impl Surface {
404 pub fn get_capabilities(
405 &self,
406 adapter: &Adapter,
407 ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
408 self.get_capabilities_with_raw(&adapter.raw)
409 }
410
411 pub fn get_capabilities_with_raw(
412 &self,
413 adapter: &hal::DynExposedAdapter,
414 ) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
415 let suf = self
416 .raw(adapter.backend())
417 .ok_or(GetSurfaceSupportError::Unsupported)?;
418 profiling::scope!("surface_capabilities");
419 let caps = unsafe { adapter.adapter.surface_capabilities(suf) }
420 .ok_or(GetSurfaceSupportError::Unsupported)?;
421
422 Ok(caps)
423 }
424
425 pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynSurface> {
426 self.surface_per_backend
427 .get(&backend)
428 .map(|surface| surface.as_ref())
429 }
430}
431
432impl Drop for Surface {
433 fn drop(&mut self) {
434 if let Some(present) = self.presentation.lock().take() {
435 for (&backend, surface) in &self.surface_per_backend {
436 if backend == present.device.backend() {
437 unsafe { surface.unconfigure(present.device.raw()) };
438 }
439 }
440 }
441 }
442}
443
444pub struct Adapter {
445 pub(crate) raw: hal::DynExposedAdapter,
446}
447
448impl Adapter {
449 pub fn new(mut raw: hal::DynExposedAdapter) -> Self {
450 const MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND: u32 = 32;
452
453 let limits = &mut raw.capabilities.limits;
454
455 limits.min_uniform_buffer_offset_alignment = limits
456 .min_uniform_buffer_offset_alignment
457 .max(MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND);
458 limits.min_storage_buffer_offset_alignment = limits
459 .min_storage_buffer_offset_alignment
460 .max(MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND);
461
462 Self { raw }
463 }
464
465 pub fn backend(&self) -> Backend {
467 self.raw.backend()
468 }
469
470 pub fn is_surface_supported(&self, surface: &Surface) -> bool {
471 surface.get_capabilities(self).is_ok()
476 }
477
478 pub fn get_info(&self) -> wgt::AdapterInfo {
479 self.raw.info.clone()
480 }
481
482 pub fn features(&self) -> wgt::Features {
483 self.raw.features
484 }
485
486 pub fn limits(&self) -> wgt::Limits {
487 self.raw.capabilities.limits.clone()
488 }
489
490 pub fn downlevel_capabilities(&self) -> wgt::DownlevelCapabilities {
491 self.raw.capabilities.downlevel.clone()
492 }
493
494 pub fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
495 unsafe { self.raw.adapter.get_presentation_timestamp() }
496 }
497
498 pub fn get_texture_format_features(
499 &self,
500 format: wgt::TextureFormat,
501 ) -> wgt::TextureFormatFeatures {
502 use hal::TextureFormatCapabilities as Tfc;
503
504 let caps = unsafe { self.raw.adapter.texture_format_capabilities(format) };
505 let mut allowed_usages = wgt::TextureUsages::empty();
506
507 allowed_usages.set(wgt::TextureUsages::COPY_SRC, caps.contains(Tfc::COPY_SRC));
508 allowed_usages.set(wgt::TextureUsages::COPY_DST, caps.contains(Tfc::COPY_DST));
509 allowed_usages.set(
510 wgt::TextureUsages::TEXTURE_BINDING,
511 caps.contains(Tfc::SAMPLED),
512 );
513 allowed_usages.set(
514 wgt::TextureUsages::STORAGE_BINDING,
515 caps.contains(Tfc::STORAGE),
516 );
517 allowed_usages.set(
518 wgt::TextureUsages::RENDER_ATTACHMENT,
519 caps.intersects(Tfc::COLOR_ATTACHMENT | Tfc::DEPTH_STENCIL_ATTACHMENT),
520 );
521
522 let mut flags = wgt::TextureFormatFeatureFlags::empty();
523 flags.set(
524 wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE,
525 caps.contains(Tfc::STORAGE_READ_WRITE),
526 );
527
528 flags.set(
529 wgt::TextureFormatFeatureFlags::FILTERABLE,
530 caps.contains(Tfc::SAMPLED_LINEAR),
531 );
532
533 flags.set(
534 wgt::TextureFormatFeatureFlags::BLENDABLE,
535 caps.contains(Tfc::COLOR_ATTACHMENT_BLEND),
536 );
537
538 flags.set(
539 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X2,
540 caps.contains(Tfc::MULTISAMPLE_X2),
541 );
542 flags.set(
543 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X4,
544 caps.contains(Tfc::MULTISAMPLE_X4),
545 );
546 flags.set(
547 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X8,
548 caps.contains(Tfc::MULTISAMPLE_X8),
549 );
550 flags.set(
551 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X16,
552 caps.contains(Tfc::MULTISAMPLE_X16),
553 );
554
555 flags.set(
556 wgt::TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE,
557 caps.contains(Tfc::MULTISAMPLE_RESOLVE),
558 );
559
560 wgt::TextureFormatFeatures {
561 allowed_usages,
562 flags,
563 }
564 }
565
566 #[allow(clippy::type_complexity)]
567 fn create_device_and_queue_from_hal(
568 self: &Arc<Self>,
569 hal_device: hal::DynOpenDevice,
570 desc: &DeviceDescriptor,
571 instance_flags: wgt::InstanceFlags,
572 trace_path: Option<&std::path::Path>,
573 ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
574 api_log!("Adapter::create_device");
575
576 let device = Device::new(
577 hal_device.device,
578 hal_device.queue.as_ref(),
579 self,
580 desc,
581 trace_path,
582 instance_flags,
583 )?;
584
585 let device = Arc::new(device);
586 let queue = Arc::new(Queue::new(device.clone(), hal_device.queue));
587 device.set_queue(&queue);
588 Ok((device, queue))
589 }
590
591 pub fn create_device_and_queue(
592 self: &Arc<Self>,
593 desc: &DeviceDescriptor,
594 instance_flags: wgt::InstanceFlags,
595 trace_path: Option<&std::path::Path>,
596 ) -> Result<(Arc<Device>, Arc<Queue>), RequestDeviceError> {
597 if !self.raw.features.contains(desc.required_features) {
599 return Err(RequestDeviceError::UnsupportedFeature(
600 desc.required_features - self.raw.features,
601 ));
602 }
603
604 let caps = &self.raw.capabilities;
605 if Backends::PRIMARY.contains(Backends::from(self.backend()))
606 && !caps.downlevel.is_webgpu_compliant()
607 {
608 let missing_flags = wgt::DownlevelFlags::compliant() - caps.downlevel.flags;
609 log::warn!(
610 "Missing downlevel flags: {:?}\n{}",
611 missing_flags,
612 DOWNLEVEL_WARNING_MESSAGE
613 );
614 log::warn!("{:#?}", caps.downlevel);
615 }
616
617 if desc
619 .required_features
620 .contains(wgt::Features::MAPPABLE_PRIMARY_BUFFERS)
621 && self.raw.info.device_type == wgt::DeviceType::DiscreteGpu
622 {
623 log::warn!(
624 "Feature MAPPABLE_PRIMARY_BUFFERS enabled on a discrete gpu. \
625 This is a massive performance footgun and likely not what you wanted"
626 );
627 }
628
629 if let Some(failed) = check_limits(&desc.required_limits, &caps.limits).pop() {
630 return Err(RequestDeviceError::LimitsExceeded(failed));
631 }
632
633 let open = unsafe {
634 self.raw.adapter.open(
635 desc.required_features,
636 &desc.required_limits,
637 &desc.memory_hints,
638 )
639 }
640 .map_err(DeviceError::from_hal)?;
641
642 self.create_device_and_queue_from_hal(open, desc, instance_flags, trace_path)
643 }
644}
645
646crate::impl_resource_type!(Adapter);
647crate::impl_storage_item!(Adapter);
648
649#[derive(Clone, Debug, Error)]
650#[non_exhaustive]
651pub enum GetSurfaceSupportError {
652 #[error("Surface is not supported by the adapter")]
653 Unsupported,
654}
655
656#[derive(Clone, Debug, Error)]
657#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
658#[non_exhaustive]
660pub enum RequestDeviceError {
661 #[error(transparent)]
662 Device(#[from] DeviceError),
663 #[error(transparent)]
664 LimitsExceeded(#[from] FailedLimit),
665 #[error("Device has no queue supporting graphics")]
666 NoGraphicsQueue,
667 #[error("Unsupported features were requested: {0:?}")]
668 UnsupportedFeature(wgt::Features),
669}
670
671#[derive(Clone, Debug, Error)]
672#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
673#[non_exhaustive]
674pub enum RequestAdapterError {
675 #[error("No suitable adapter found")]
676 NotFound,
677}
678
679#[derive(Clone, Debug, Error)]
680#[non_exhaustive]
681pub enum CreateSurfaceError {
682 #[error("The backend {0} was not enabled on the instance.")]
683 BackendNotEnabled(Backend),
684 #[error("Failed to create surface for any enabled backend: {0:?}")]
685 FailedToCreateSurfaceForAnyBackend(HashMap<Backend, hal::InstanceError>),
686}
687
688impl Global {
689 #[cfg(feature = "raw-window-handle")]
707 pub unsafe fn instance_create_surface(
708 &self,
709 display_handle: raw_window_handle::RawDisplayHandle,
710 window_handle: raw_window_handle::RawWindowHandle,
711 id_in: Option<SurfaceId>,
712 ) -> Result<SurfaceId, CreateSurfaceError> {
713 let surface = unsafe { self.instance.create_surface(display_handle, window_handle) }?;
714 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
715 Ok(id)
716 }
717
718 #[cfg(metal)]
722 pub unsafe fn instance_create_surface_metal(
723 &self,
724 layer: *mut std::ffi::c_void,
725 id_in: Option<SurfaceId>,
726 ) -> Result<SurfaceId, CreateSurfaceError> {
727 let surface = unsafe { self.instance.create_surface_metal(layer) }?;
728 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
729 Ok(id)
730 }
731
732 #[cfg(dx12)]
733 pub unsafe fn instance_create_surface_from_visual(
737 &self,
738 visual: *mut std::ffi::c_void,
739 id_in: Option<SurfaceId>,
740 ) -> Result<SurfaceId, CreateSurfaceError> {
741 let surface = unsafe { self.instance.create_surface_from_visual(visual) }?;
742 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
743 Ok(id)
744 }
745
746 #[cfg(dx12)]
747 pub unsafe fn instance_create_surface_from_surface_handle(
751 &self,
752 surface_handle: *mut std::ffi::c_void,
753 id_in: Option<SurfaceId>,
754 ) -> Result<SurfaceId, CreateSurfaceError> {
755 let surface = unsafe {
756 self.instance
757 .create_surface_from_surface_handle(surface_handle)
758 }?;
759 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
760 Ok(id)
761 }
762
763 #[cfg(dx12)]
764 pub unsafe fn instance_create_surface_from_swap_chain_panel(
768 &self,
769 swap_chain_panel: *mut std::ffi::c_void,
770 id_in: Option<SurfaceId>,
771 ) -> Result<SurfaceId, CreateSurfaceError> {
772 let surface = unsafe {
773 self.instance
774 .create_surface_from_swap_chain_panel(swap_chain_panel)
775 }?;
776 let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
777 Ok(id)
778 }
779
780 pub fn surface_drop(&self, id: SurfaceId) {
781 profiling::scope!("Surface::drop");
782
783 api_log!("Surface::drop {id:?}");
784
785 self.surfaces.remove(id);
786 }
787
788 pub fn enumerate_adapters(&self, backends: Backends) -> Vec<AdapterId> {
789 let adapters = self.instance.enumerate_adapters(backends);
790 adapters
791 .into_iter()
792 .map(|adapter| self.hub.adapters.prepare(None).assign(Arc::new(adapter)))
793 .collect()
794 }
795
796 pub fn request_adapter(
797 &self,
798 desc: &RequestAdapterOptions,
799 backends: Backends,
800 id_in: Option<AdapterId>,
801 ) -> Result<AdapterId, RequestAdapterError> {
802 let compatible_surface = desc.compatible_surface.map(|id| self.surfaces.get(id));
803 let desc = wgt::RequestAdapterOptions {
804 power_preference: desc.power_preference,
805 force_fallback_adapter: desc.force_fallback_adapter,
806 compatible_surface: compatible_surface.as_deref(),
807 };
808 let adapter = self.instance.request_adapter(&desc, backends)?;
809 let id = self.hub.adapters.prepare(id_in).assign(Arc::new(adapter));
810 Ok(id)
811 }
812
813 pub unsafe fn create_adapter_from_hal(
817 &self,
818 hal_adapter: hal::DynExposedAdapter,
819 input: Option<AdapterId>,
820 ) -> AdapterId {
821 profiling::scope!("Instance::create_adapter_from_hal");
822
823 let fid = self.hub.adapters.prepare(input);
824 let id = fid.assign(Arc::new(Adapter::new(hal_adapter)));
825
826 resource_log!("Created Adapter {:?}", id);
827 id
828 }
829
830 pub fn adapter_get_info(&self, adapter_id: AdapterId) -> wgt::AdapterInfo {
831 let adapter = self.hub.adapters.get(adapter_id);
832 adapter.get_info()
833 }
834
835 pub fn adapter_get_texture_format_features(
836 &self,
837 adapter_id: AdapterId,
838 format: wgt::TextureFormat,
839 ) -> wgt::TextureFormatFeatures {
840 let adapter = self.hub.adapters.get(adapter_id);
841 adapter.get_texture_format_features(format)
842 }
843
844 pub fn adapter_features(&self, adapter_id: AdapterId) -> wgt::Features {
845 let adapter = self.hub.adapters.get(adapter_id);
846 adapter.features()
847 }
848
849 pub fn adapter_limits(&self, adapter_id: AdapterId) -> wgt::Limits {
850 let adapter = self.hub.adapters.get(adapter_id);
851 adapter.limits()
852 }
853
854 pub fn adapter_downlevel_capabilities(
855 &self,
856 adapter_id: AdapterId,
857 ) -> wgt::DownlevelCapabilities {
858 let adapter = self.hub.adapters.get(adapter_id);
859 adapter.downlevel_capabilities()
860 }
861
862 pub fn adapter_get_presentation_timestamp(
863 &self,
864 adapter_id: AdapterId,
865 ) -> wgt::PresentationTimestamp {
866 let adapter = self.hub.adapters.get(adapter_id);
867 adapter.get_presentation_timestamp()
868 }
869
870 pub fn adapter_drop(&self, adapter_id: AdapterId) {
871 profiling::scope!("Adapter::drop");
872 api_log!("Adapter::drop {adapter_id:?}");
873
874 self.hub.adapters.remove(adapter_id);
875 }
876}
877
878impl Global {
879 pub fn adapter_request_device(
880 &self,
881 adapter_id: AdapterId,
882 desc: &DeviceDescriptor,
883 trace_path: Option<&std::path::Path>,
884 device_id_in: Option<DeviceId>,
885 queue_id_in: Option<QueueId>,
886 ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
887 profiling::scope!("Adapter::request_device");
888 api_log!("Adapter::request_device");
889
890 let device_fid = self.hub.devices.prepare(device_id_in);
891 let queue_fid = self.hub.queues.prepare(queue_id_in);
892
893 let adapter = self.hub.adapters.get(adapter_id);
894 let (device, queue) =
895 adapter.create_device_and_queue(desc, self.instance.flags, trace_path)?;
896
897 let device_id = device_fid.assign(device);
898 resource_log!("Created Device {:?}", device_id);
899
900 let queue_id = queue_fid.assign(queue);
901 resource_log!("Created Queue {:?}", queue_id);
902
903 Ok((device_id, queue_id))
904 }
905
906 pub unsafe fn create_device_from_hal(
911 &self,
912 adapter_id: AdapterId,
913 hal_device: hal::DynOpenDevice,
914 desc: &DeviceDescriptor,
915 trace_path: Option<&std::path::Path>,
916 device_id_in: Option<DeviceId>,
917 queue_id_in: Option<QueueId>,
918 ) -> Result<(DeviceId, QueueId), RequestDeviceError> {
919 profiling::scope!("Global::create_device_from_hal");
920
921 let devices_fid = self.hub.devices.prepare(device_id_in);
922 let queues_fid = self.hub.queues.prepare(queue_id_in);
923
924 let adapter = self.hub.adapters.get(adapter_id);
925 let (device, queue) = adapter.create_device_and_queue_from_hal(
926 hal_device,
927 desc,
928 self.instance.flags,
929 trace_path,
930 )?;
931
932 let device_id = devices_fid.assign(device);
933 resource_log!("Created Device {:?}", device_id);
934
935 let queue_id = queues_fid.assign(queue);
936 resource_log!("Created Queue {:?}", queue_id);
937
938 Ok((device_id, queue_id))
939 }
940}
941
942pub fn parse_backends_from_comma_list(string: &str) -> Backends {
955 let mut backends = Backends::empty();
956 for backend in string.to_lowercase().split(',') {
957 backends |= match backend.trim() {
958 "vulkan" | "vk" => Backends::VULKAN,
959 "dx12" | "d3d12" => Backends::DX12,
960 "metal" | "mtl" => Backends::METAL,
961 "opengl" | "gles" | "gl" => Backends::GL,
962 "webgpu" => Backends::BROWSER_WEBGPU,
963 b => {
964 log::warn!("unknown backend string '{}'", b);
965 continue;
966 }
967 }
968 }
969
970 if backends.is_empty() {
971 log::warn!("no valid backend strings found!");
972 }
973
974 backends
975}