Skip to content

Commit

Permalink
Utils for WebGPU support detection & Instance creation
Browse files Browse the repository at this point in the history
Clarifies the docs on `wgpu::Instance` accordingly
  • Loading branch information
Wumpf committed Oct 5, 2024
1 parent 2021e7f commit 9216f22
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 6 deletions.
13 changes: 9 additions & 4 deletions wgpu/src/api/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,15 @@ impl Instance {
/// during instantiation, and which [DX12 shader compiler][Dx12Compiler] wgpu will use.
///
/// [`Backends::BROWSER_WEBGPU`] takes a special role:
/// If it is set and WebGPU support is detected, this instance will *only* be able to create
/// WebGPU adapters. If you instead want to force use of WebGL, either
/// disable the `webgpu` compile-time feature or don't add the [`Backends::BROWSER_WEBGPU`]
/// flag to the the `instance_desc`'s `backends` field.
/// If it is set and a [`navigator.gpu`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/gpu)
/// object is present, this instance will *only* be able to create WebGPU adapters.
///
/// ⚠️ On some browsers this check is insufficient to determine whether WebGPU is supported,
/// as the browser may define the `navigator.gpu` object, but be unable to create any WebGPU adapters.
/// For targeting _both_ WebGPU & WebGL is recommended to use [`crate::util::new_instance_with_webgpu_detection`].
///
/// If you instead want to force use of WebGL, either disable the `webgpu` compile-time feature
/// or don't add the [`Backends::BROWSER_WEBGPU`] flag to the the `instance_desc`'s `backends` field.
/// If it is set and WebGPU support is *not* detected, the instance will use wgpu-core
/// to create adapters. Meaning that if the `webgl` feature is enabled, it is able to create
/// a WebGL adapter.
Expand Down
8 changes: 6 additions & 2 deletions wgpu/src/backend/webgpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1088,8 +1088,12 @@ pub struct BrowserGpuPropertyInaccessible;
/// Returns the browser's gpu object or `Err(BrowserGpuPropertyInaccessible)` if
/// the current context is neither the main thread nor a dedicated worker.
///
/// If WebGPU is not supported, the Gpu property is `undefined`, and so this
/// function will return `Ok(None)`.
/// If WebGPU is not supported, the Gpu property may (!) be `undefined`,
/// and so this function will return `Ok(None)` function will return `Ok(None)`.
/// Note that this check is insufficient to determine whether WebGPU is
/// supported, as the browser may define the Gpu property, but be unable to
/// create any WebGPU adapters.
/// To detect whether WebGPU is supported, use the [`crate::utils::is_webgpu_supported`] function.
///
/// See:
/// * <https://developer.mozilla.org/en-US/docs/Web/API/Navigator/gpu>
Expand Down
61 changes: 61 additions & 0 deletions wgpu/src/util/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,64 @@ pub fn gles_minor_version_from_env() -> Option<wgt::Gles3MinorVersion> {
},
)
}

/// 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 fn is_browser_webgpu_supported() -> impl std::future::Future<Output = bool> {
#[cfg(webgpu)]
{
let gpu = crate::backend::get_browser_gpu_property();
async move {
// In theory it should be enough to check for the presence of the `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();
OptionFuture::some(MakeSendFuture::new(
wasm_bindgen_futures::JsFuture::from(adapter_promise),
future_request_adapter,
))
.await
.is_some()
}
}
#[cfg(not(webgpu))]
{
async { 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()`].
#[allow(unused_mut)]
pub async fn new_instance_with_webgpu_detection(
mut instance_desc: wgt::InstanceDescriptor,
) -> crate::Instance {
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)
}

0 comments on commit 9216f22

Please sign in to comment.