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