diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d2e87ae864..f568a86ab1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,20 @@ Bottom level categories: ## Unreleased +#### 'wgpu::Instance::enumerate_adapters` is now `async` & available on WebGPU + +Making `enumerate_adapters` async allows custom backends to use it along with elimnating some native/non-native distinctions + +This is a breaking change + +```diff +- pub fn enumerate_adapters(&self, backends: Backends) -> Vec { ++ pub fn enumerate_adapters(&self, backends: Backends) -> impl Future> { + +``` + +By @R-Cramer4 in [#8230](https://github.com/gfx-rs/wgpu/pull/8230) + ## v27.0.2 (2025-10-03) ### Bug Fixes @@ -175,7 +189,6 @@ by if the `Feature::MULTI_DRAW_INDIRECT_COUNT` feature is available on the devic By @cwfitzgerald in [#8162](https://github.com/gfx-rs/wgpu/pull/8162). - #### `wgpu::PollType::Wait` has now an optional timeout We removed `wgpu::PollType::WaitForSubmissionIndex` and added fields to `wgpu::PollType::Wait` in order to express timeouts. diff --git a/Cargo.lock b/Cargo.lock index 5ac6df3d5d5..9e734d1ade8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,9 +120,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.20" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -600,9 +600,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.39" +version = "1.2.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1354349954c6fc9cb0deab020f27f783cf0b604e8bb754dc4658ecf0d29c35f" +checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" dependencies = [ "find-msvc-tools", "jobserver", @@ -1438,9 +1438,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" +checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" [[package]] name = "fixedbitset" @@ -5012,6 +5012,7 @@ dependencies = [ "env_logger", "hashbrown 0.16.0", "pico-args", + "pollster", "serde", "serde_json", "wgpu", diff --git a/examples/features/src/utils.rs b/examples/features/src/utils.rs index 5d2913c185a..94bbdb83824 100644 --- a/examples/features/src/utils.rs +++ b/examples/features/src/utils.rs @@ -203,7 +203,7 @@ pub(crate) async fn get_adapter_with_capabilities_or_from_env( ); adapter } else { - let adapters = instance.enumerate_adapters(Backends::all()); + let adapters = instance.enumerate_adapters(Backends::all()).await; let mut chosen_adapter = None; for adapter in adapters { diff --git a/examples/standalone/custom_backend/src/custom.rs b/examples/standalone/custom_backend/src/custom.rs index 3082be20b5f..7b2403611eb 100644 --- a/examples/standalone/custom_backend/src/custom.rs +++ b/examples/standalone/custom_backend/src/custom.rs @@ -55,6 +55,13 @@ impl InstanceInterface for CustomInstance { fn wgsl_language_features(&self) -> wgpu::WgslLanguageFeatures { unimplemented!() } + + fn enumerate_adapters( + &self, + _backends: wgpu::Backends, + ) -> Pin> { + unimplemented!() + } } #[derive(Debug)] diff --git a/tests/src/init.rs b/tests/src/init.rs index 38073fa1b39..2c14010ef29 100644 --- a/tests/src/init.rs +++ b/tests/src/init.rs @@ -122,7 +122,7 @@ pub async fn initialize_adapter( cfg_if::cfg_if! { if #[cfg(not(target_arch = "wasm32"))] { - let adapter_iter = instance.enumerate_adapters(backends); + let adapter_iter = instance.enumerate_adapters(backends).await; let adapter = adapter_iter.into_iter() // If we have a report, we only want to match the adapter with the same info. // @@ -136,7 +136,7 @@ pub async fn initialize_adapter( panic!( "Could not find adapter with info {:#?} in {:#?}", adapter_report.map(|r| &r.info), - instance.enumerate_adapters(backends).into_iter().map(|a| a.get_info()).collect::>(), + instance.enumerate_adapters(backends).await.into_iter().map(|a| a.get_info()).collect::>(), ); }; } else { diff --git a/wgpu-info/Cargo.toml b/wgpu-info/Cargo.toml index 56ddf860bfa..720e06c9382 100644 --- a/wgpu-info/Cargo.toml +++ b/wgpu-info/Cargo.toml @@ -16,6 +16,7 @@ bitflags.workspace = true env_logger.workspace = true hashbrown = { workspace = true, features = ["serde"] } pico-args.workspace = true +pollster.workspace = true serde = { workspace = true, features = ["default"] } serde_json.workspace = true wgpu.workspace = true diff --git a/wgpu-info/src/report.rs b/wgpu-info/src/report.rs index ed0f1691486..fa0522b2bef 100644 --- a/wgpu-info/src/report.rs +++ b/wgpu-info/src/report.rs @@ -25,7 +25,8 @@ impl GpuReport { desc.flags = wgpu::InstanceFlags::debugging(); desc.with_env() }); - let adapters = instance.enumerate_adapters(wgpu::Backends::all()); + + let adapters = pollster::block_on(instance.enumerate_adapters(wgpu::Backends::all())); let mut devices = Vec::with_capacity(adapters.len()); for adapter in adapters { diff --git a/wgpu/src/api/instance.rs b/wgpu/src/api/instance.rs index b9decd59603..77b70f51c7a 100644 --- a/wgpu/src/api/instance.rs +++ b/wgpu/src/api/instance.rs @@ -1,4 +1,3 @@ -#[cfg(wgpu_core)] use alloc::vec::Vec; use core::future::Future; @@ -142,23 +141,18 @@ impl Instance { /// # Arguments /// /// - `backends` - Backends from which to enumerate adapters. - #[cfg(wgpu_core)] - pub fn enumerate_adapters(&self, backends: Backends) -> Vec { - let Some(core_instance) = self.inner.as_core_opt() else { - return Vec::new(); - }; - - core_instance - .enumerate_adapters(backends) - .into_iter() - .map(|adapter| { - let core = backend::wgpu_core::CoreAdapter { - context: core_instance.clone(), - id: adapter, - }; - crate::Adapter { inner: core.into() } - }) - .collect() + pub fn enumerate_adapters(&self, backends: Backends) -> impl Future> { + let future = self.inner.enumerate_adapters(backends); + + async move { + future + .await + .iter() + .map(|adapter| Adapter { + inner: adapter.clone(), + }) + .collect() + } } /// Retrieves an [`Adapter`] which matches the given [`RequestAdapterOptions`]. diff --git a/wgpu/src/backend/webgpu.rs b/wgpu/src/backend/webgpu.rs index 920ad58ba17..4c34042c55d 100644 --- a/wgpu/src/backend/webgpu.rs +++ b/wgpu/src/backend/webgpu.rs @@ -1569,6 +1569,20 @@ impl dispatch::InstanceInterface for ContextWebGpu { )))) } } + fn enumerate_adapters( + &self, + _backends: crate::Backends, + ) -> Pin> { + let future = self.request_adapter(&crate::RequestAdapterOptions::default()); + let enumerate_future = async move { + let adapter = future.await; + match adapter { + Ok(a) => vec![a], + Err(_) => vec![], + } + }; + Box::pin(enumerate_future) + } fn poll_all_devices(&self, _force_wait: bool) -> bool { // Devices are automatically polled. diff --git a/wgpu/src/backend/wgpu_core.rs b/wgpu/src/backend/wgpu_core.rs index 074b1239029..405e4779b70 100644 --- a/wgpu/src/backend/wgpu_core.rs +++ b/wgpu/src/backend/wgpu_core.rs @@ -28,7 +28,6 @@ use wgt::{ WasmNotSendSync, }; -use crate::util::Mutex; use crate::{ api, dispatch::{self, BlasCompactCallback, BufferMappedRangeInterface}, @@ -36,6 +35,7 @@ use crate::{ CompilationMessageType, ErrorSource, Features, Label, LoadOp, MapMode, Operations, ShaderSource, SurfaceTargetUnsafe, TextureDescriptor, Tlas, }; +use crate::{dispatch::DispatchAdapter, util::Mutex}; #[derive(Clone)] pub struct ContextWgpuCore(Arc); @@ -902,6 +902,24 @@ impl dispatch::InstanceInterface for ContextWgpuCore { }, ) } + + fn enumerate_adapters( + &self, + backends: crate::Backends, + ) -> Pin> { + let adapters: Vec = self + .enumerate_adapters(backends) + .into_iter() + .map(|adapter| { + let core = crate::backend::wgpu_core::CoreAdapter { + context: self.clone(), + id: adapter, + }; + core.into() + }) + .collect(); + Box::pin(ready(adapters)) + } } impl dispatch::AdapterInterface for CoreAdapter { diff --git a/wgpu/src/dispatch.rs b/wgpu/src/dispatch.rs index 8e48f7d593e..ed73932dd87 100644 --- a/wgpu/src/dispatch.rs +++ b/wgpu/src/dispatch.rs @@ -39,6 +39,7 @@ trait_alias!(RequestAdapterFuture: Future> + WasmNotSend + 'static); trait_alias!(PopErrorScopeFuture: Future> + WasmNotSend + 'static); trait_alias!(ShaderCompilationInfoFuture: Future + WasmNotSend + 'static); +trait_alias!(EnumerateAdapterFuture: Future> + WasmNotSend + 'static); // We can't use trait aliases here, as you can't convert from a dyn Trait to dyn Supertrait _yet_. #[cfg(send_sync)] @@ -93,6 +94,9 @@ pub trait InstanceInterface: CommonTraits { #[cfg(feature = "wgsl")] fn wgsl_language_features(&self) -> crate::WgslLanguageFeatures; + + fn enumerate_adapters(&self, backends: crate::Backends) + -> Pin>; } pub trait AdapterInterface: CommonTraits { diff --git a/wgpu/src/util/init.rs b/wgpu/src/util/init.rs index 527274ebe84..20b058ff80e 100644 --- a/wgpu/src/util/init.rs +++ b/wgpu/src/util/init.rs @@ -6,7 +6,7 @@ use crate::Backends; /// Initialize the adapter obeying the `WGPU_ADAPTER_NAME` environment variable. #[cfg(wgpu_core)] #[cfg_attr(not(std), expect(unused_variables, unreachable_code))] -pub fn initialize_adapter_from_env( +pub async fn initialize_adapter_from_env( instance: &Instance, compatible_surface: Option<&Surface<'_>>, ) -> Result { @@ -23,7 +23,7 @@ pub fn initialize_adapter_from_env( } }; - let adapters = instance.enumerate_adapters(crate::Backends::all()); + let adapters = instance.enumerate_adapters(crate::Backends::all()).await; let mut chosen_adapter = None; for adapter in adapters { @@ -46,7 +46,7 @@ pub fn initialize_adapter_from_env( /// Initialize the adapter obeying the `WGPU_ADAPTER_NAME` environment variable. #[cfg(not(wgpu_core))] -pub fn initialize_adapter_from_env( +pub async fn initialize_adapter_from_env( _instance: &Instance, _compatible_surface: Option<&Surface<'_>>, ) -> Result { @@ -58,7 +58,7 @@ pub async fn initialize_adapter_from_env_or_default( instance: &Instance, compatible_surface: Option<&Surface<'_>>, ) -> Result { - match initialize_adapter_from_env(instance, compatible_surface) { + match initialize_adapter_from_env(instance, compatible_surface).await { Ok(a) => Ok(a), Err(_) => { instance