wgpu/util/
init.rs

1use crate::{Adapter, Instance, RequestAdapterOptions, Surface};
2
3#[cfg(doc)]
4use crate::Backends;
5
6/// Initialize the adapter obeying the WGPU_ADAPTER_NAME environment variable.
7#[cfg(native)]
8pub fn initialize_adapter_from_env(
9    instance: &Instance,
10    compatible_surface: Option<&Surface<'_>>,
11) -> Option<Adapter> {
12    let desired_adapter_name = std::env::var("WGPU_ADAPTER_NAME")
13        .as_deref()
14        .map(str::to_lowercase)
15        .ok()?;
16
17    let adapters = instance.enumerate_adapters(crate::Backends::all());
18
19    let mut chosen_adapter = None;
20    for adapter in adapters {
21        let info = adapter.get_info();
22
23        if let Some(surface) = compatible_surface {
24            if !adapter.is_surface_supported(surface) {
25                continue;
26            }
27        }
28
29        if info.name.to_lowercase().contains(&desired_adapter_name) {
30            chosen_adapter = Some(adapter);
31            break;
32        }
33    }
34
35    Some(chosen_adapter.expect("WGPU_ADAPTER_NAME set but no matching adapter found!"))
36}
37
38/// Initialize the adapter obeying the WGPU_ADAPTER_NAME environment variable.
39#[cfg(not(native))]
40pub fn initialize_adapter_from_env(
41    _instance: &Instance,
42    _compatible_surface: Option<&Surface<'_>>,
43) -> Option<Adapter> {
44    None
45}
46
47/// Initialize the adapter obeying the WGPU_ADAPTER_NAME environment variable and if it doesn't exist fall back on a default adapter.
48pub async fn initialize_adapter_from_env_or_default(
49    instance: &Instance,
50    compatible_surface: Option<&Surface<'_>>,
51) -> Option<Adapter> {
52    match initialize_adapter_from_env(instance, compatible_surface) {
53        Some(a) => Some(a),
54        None => {
55            instance
56                .request_adapter(&RequestAdapterOptions {
57                    power_preference: crate::PowerPreference::from_env().unwrap_or_default(),
58                    force_fallback_adapter: false,
59                    compatible_surface,
60                })
61                .await
62        }
63    }
64}
65
66/// Determines whether the [`Backends::BROWSER_WEBGPU`] backend is supported.
67///
68/// The result can only be true if this is called from the main thread or a dedicated worker.
69/// For convenience, this is also supported on non-wasm targets, always returning false there.
70pub async fn is_browser_webgpu_supported() -> bool {
71    #[cfg(webgpu)]
72    {
73        // In theory it should be enough to check for the presence of the `gpu` property...
74        let gpu = crate::backend::get_browser_gpu_property();
75        let Ok(Some(gpu)) = gpu else {
76            return false;
77        };
78
79        // ...but in practice, we also have to try to create an adapter, since as of writing
80        // Chrome on Linux has the `gpu` property but doesn't support WebGPU.
81        let adapter_promise = gpu.request_adapter();
82        wasm_bindgen_futures::JsFuture::from(adapter_promise)
83            .await
84            .is_ok_and(|adapter| !adapter.is_undefined() && !adapter.is_null())
85    }
86    #[cfg(not(webgpu))]
87    {
88        false
89    }
90}
91
92/// Create an new instance of wgpu, but disabling [`Backends::BROWSER_WEBGPU`] if no WebGPU support was detected.
93///
94/// If the instance descriptor enables [`Backends::BROWSER_WEBGPU`],
95/// this checks via [`is_browser_webgpu_supported`] for WebGPU support before forwarding
96/// the descriptor with or without [`Backends::BROWSER_WEBGPU`] respecitively to [`Instance::new`].
97///
98/// You should prefer this method over [`Instance::new`] if you want to target WebGPU and automatically
99/// fall back to WebGL if WebGPU is not available.
100/// This is because WebGPU support has to be decided upon instance creation and [`Instance::new`]
101/// (being a `sync` function) can't establish WebGPU support (details see [`is_browser_webgpu_supported`]).
102///
103/// # Panics
104///
105/// If no backend feature for the active target platform is enabled,
106/// this method will panic, see [`Instance::enabled_backend_features()`].
107pub async fn new_instance_with_webgpu_detection(
108    instance_desc: &wgt::InstanceDescriptor,
109) -> crate::Instance {
110    let mut instance_desc = instance_desc.clone();
111    if instance_desc
112        .backends
113        .contains(wgt::Backends::BROWSER_WEBGPU)
114        && !is_browser_webgpu_supported().await
115    {
116        instance_desc.backends.remove(wgt::Backends::BROWSER_WEBGPU);
117    }
118
119    crate::Instance::new(&instance_desc)
120}