From 6100d156b804acd552b58c1c81992c51654a1ddf Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Thu, 1 Dec 2022 09:40:17 -0800 Subject: [PATCH] Make `wgpu-core` users responsible for choosing back ends. Give `wgpu-core` a set of features parallel to those in `wgpu-hal`, and pass them through. Within `wgpu-core`, use features to decide when back-end-specific code is enabled. Move the platform-specific dependencies that select appropriate backends as high as possible in the dependency DAG: `wgpu` and `deno_webgpu`. Since all the `gfx_select` macros now use configuration predicates of the same form, simplify those macros and their uses. Similarly, let `wgpu-core`'s users decide whether to support renderdoc, not `wgpu-core` itself. In wgpu-hal give a more helpful error when no backends are enabled. Don't select backends in CI that the current platform can't handle. Before this change, backend selection is done by target dependencies in `wgpu-core/Cargo.toml`, giving `wgpu-core` users no way to override those choices. (Firefox doesn't want the GLES back end, for example.) There doesn't seem to be any way to have a crate select backends based on target architecture and OS that users of that crate can still override. The default features can't be selected based on the target, for example. That implies that we should do the selection as late in the dependency DAG as feasible. Having `wgpu` (and `wgpu-core`'s other dependents) choose backends seems good enough. --- .github/workflows/ci.yml | 13 +++-- CHANGELOG.md | 36 +++++++++++++ Cargo.lock | 7 --- deno_webgpu/Cargo.toml | 20 ++++++- wgpu-core/Cargo.toml | 31 ++++++----- wgpu-core/build.rs | 22 -------- wgpu-core/src/device/mod.rs | 10 ++-- wgpu-core/src/hub.rs | 60 ++++++++++----------- wgpu-core/src/instance.rs | 102 ++++++++++++++++++------------------ wgpu-core/src/lib.rs | 80 +++++++++++++--------------- wgpu-hal/Cargo.toml | 2 +- wgpu-hal/src/lib.rs | 9 ++++ wgpu/Cargo.toml | 43 ++++++++++++--- 13 files changed, 247 insertions(+), 188 deletions(-) delete mode 100644 wgpu-core/build.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c287b927cb..5820963e176 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -159,11 +159,18 @@ jobs: # check with no features cargo clippy --target ${{ matrix.target }} -p wgpu -p wgpu-core -p wgpu-info -p player --no-default-features - # check with all features - cargo clippy --target ${{ matrix.target }} -p wgpu -p wgpu-core -p wgpu-info -p player --tests --all-features + # Check with all features. + # (But watch out for backend-selection features in wgpu-core; some of + # those only build on the right platforms.) + cargo clippy --target ${{ matrix.target }} -p wgpu -p wgpu-info -p player --tests --all-features + cargo clippy --target ${{ matrix.target }} -p wgpu-core --tests \ + --features="portable_features" # build docs - cargo doc --target ${{ matrix.target }} -p wgpu -p wgpu-core -p wgpu-info -p player --all-features --no-deps + # (Watch out for backend-selection features in wgpu-core; some of + # those only build on the right platforms.) + cargo doc --target ${{ matrix.target }} -p wgpu -p wgpu-info -p player --all-features --no-deps + cargo doc --target ${{ matrix.target }} -p wgpu-core --no-deps --features="portable_features" gpu-test: strategy: diff --git a/CHANGELOG.md b/CHANGELOG.md index dd841e7d15d..823a700c19a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,42 @@ Bottom level categories: ### Major Changes +#### Backend selection by features + +Whereas `wgpu-core` used to automatically select backends to enable +based on the target OS and architecture, it now has separate features +to enable each backend: + +- "metal", for the Metal API on macOS and iOS +- "vulkan", for the Vulkan API (Linux, some Android, and occasionally Windows) +- "dx12", for Microsoft's Direct3D 12 API +- "gles", OpenGL ES, available on many systems +- "dx11", for Microsoft's Direct3D 11 API + +None are enabled by default, but the `wgpu` crate automatically +selects these features based on the target operating system and +architecture, using the same rules that `wgpu-core` used to, so users +of `wgpu` should be unaffected by this change. However, other crates +using `wgpu-core` directly will need to copy `wgpu`'s logic or write +their own. See the `[target]` section of `wgpu/Cargo.toml` for +details. + +Similarly, `wgpu-core` now has a `renderdoc` feature that `wgpu` +enables on appropriate platforms. + +In previous releases, the `wgpu-core` crate decided which backends to +support. However, this left `wgpu-core`'s users with no way to +override those choices. (Firefox doesn't want the GLES back end, for +example.) There doesn't seem to be any way to have a crate select +backends based on target OS and architecture that users of that crate +can still override. Default features can't be selected based on the +target, for example. That implies that we should do the selection as +late in the dependency DAG as feasible. Having `wgpu` (and +`wgpu-core`'s other dependents) choose backends seems like the best +option. + +By @jimblandy in [#3254](https://github.com/gfx-rs/wgpu/pull/3254). + #### Surface Capabilities API The various surface capability functions were combined into a single call that gives you all the capabilities. diff --git a/Cargo.lock b/Cargo.lock index 021fdf6d781..e371d9c8a73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -259,12 +259,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - [[package]] name = "cgl" version = "0.3.2" @@ -2818,7 +2812,6 @@ dependencies = [ "arrayvec 0.7.2", "bit-vec", "bitflags", - "cfg_aliases", "codespan-reporting", "fxhash", "log", diff --git a/deno_webgpu/Cargo.toml b/deno_webgpu/Cargo.toml index 3091c9c088c..81feeeaf134 100644 --- a/deno_webgpu/Cargo.toml +++ b/deno_webgpu/Cargo.toml @@ -14,5 +14,23 @@ description = "WebGPU implementation for Deno" deno_core.workspace = true serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["full"] } -wgpu-core = { workspace = true, features = ["trace", "replay", "serde", "strict_asserts", "wgsl"] } wgpu-types = { workspace = true, features = ["trace", "replay", "serde"] } + +[dependencies.wgpu-core] +workspace = true +features = ["trace", "replay", "serde", "strict_asserts", "wgsl", "gles"] + +# We want the wgpu-core Metal backend on macOS and iOS. +[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.wgpu-core] +workspace = true +features = ["metal"] + +# We want the wgpu-core Direct3D backends on Windows. +[target.'cfg(windows)'.dependencies.wgpu-core] +workspace = true +features = ["dx11", "dx12"] + +# We want the wgpu-core Vulkan backend on Unix (but not Emscripten) and Windows. +[target.'cfg(any(windows, all(unix, not(target_arch = "emscripten"))))'.dependencies.wgpu-core] +workspace = true +features = ["vulkan"] diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index c92865b73d2..42293b0c1bb 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -17,6 +17,18 @@ rustdoc-args = ["--cfg", "docsrs"] [features] default = [] + +# Backends, passed through to wgpu-hal +metal = ["hal/metal"] +vulkan = ["hal/vulkan"] +gles = ["hal/gles"] +dx11 = ["hal/dx11"] +dx12 = ["hal/dx12"] + +# Support the Renderdoc graphics debugger: +# https://renderdoc.org/ +renderdoc = ["hal/renderdoc"] + # Apply run-time checks, even in release builds. These are in addition # to the validation carried out at public APIs in all builds. strict_asserts = [] @@ -32,6 +44,9 @@ id32 = [] wgsl = ["naga/wgsl-in"] vulkan-portability = ["hal/vulkan"] +# Features that are intended to work on all platforms. +portable_features = ["gles", "strict_asserts", "trace", "replay", "serial-pass", "id32", "wgsl"] + [dependencies] arrayvec.workspace = true bitflags.workspace = true @@ -60,21 +75,5 @@ workspace = true [target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies] web-sys = { workspace = true, features = ["HtmlCanvasElement", "OffscreenCanvas"] } -[target.'cfg(target_arch = "wasm32")'.dependencies] -hal = { workspace = true, features = ["gles"] } - -[target.'cfg(all(not(target_arch = "wasm32"), any(target_os = "ios", target_os = "macos")))'.dependencies] -hal = { workspace = true, features = ["metal"] } -#Note: could also enable "vulkan" for Vulkan Portability - -[target.'cfg(all(not(target_arch = "wasm32"), unix, not(target_os = "ios"), not(target_os = "macos")))'.dependencies] -hal = { workspace = true, features = ["vulkan", "gles", "renderdoc"] } - -[target.'cfg(all(not(target_arch = "wasm32"), windows))'.dependencies] -hal = { workspace = true, features = ["vulkan", "dx12", "dx11", "renderdoc"] } - [target.'cfg(target_os = "emscripten")'.dependencies] hal = { workspace = true, features = ["emscripten"] } - -[build-dependencies] -cfg_aliases.workspace = true diff --git a/wgpu-core/build.rs b/wgpu-core/build.rs deleted file mode 100644 index 445ea245d26..00000000000 --- a/wgpu-core/build.rs +++ /dev/null @@ -1,22 +0,0 @@ -fn main() { - // Setup cfg aliases - cfg_aliases::cfg_aliases! { - // Vendors/systems - wasm: { target_arch = "wasm32" }, - apple: { any(target_os = "ios", target_os = "macos") }, - unix_wo_apple: {all(unix, not(apple))}, - - // Backends - vulkan: { all(not(wasm), any(windows, unix_wo_apple, feature = "vulkan-portability")) }, - metal: { all(not(wasm), apple) }, - dx12: { all(not(wasm), windows) }, - dx11: { all(not(wasm), windows) }, - gl: { - any( - unix_wo_apple, - feature = "angle", - wasm - ) - }, - } -} diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 86c79a9a6d2..ef3d8ee8af7 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -5407,27 +5407,27 @@ impl Global { let mut closures = UserClosures::default(); let mut all_queue_empty = true; - #[cfg(vulkan)] + #[cfg(feature = "vulkan")] { all_queue_empty = self.poll_devices::(force_wait, &mut closures)? && all_queue_empty; } - #[cfg(metal)] + #[cfg(feature = "metal")] { all_queue_empty = self.poll_devices::(force_wait, &mut closures)? && all_queue_empty; } - #[cfg(dx12)] + #[cfg(feature = "dx12")] { all_queue_empty = self.poll_devices::(force_wait, &mut closures)? && all_queue_empty; } - #[cfg(dx11)] + #[cfg(feature = "dx11")] { all_queue_empty = self.poll_devices::(force_wait, &mut closures)? && all_queue_empty; } - #[cfg(gl)] + #[cfg(feature = "gles")] { all_queue_empty = self.poll_devices::(force_wait, &mut closures)? && all_queue_empty; diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index f07010477c2..290df3c716a 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -1057,30 +1057,30 @@ impl Hub { } pub struct Hubs { - #[cfg(vulkan)] + #[cfg(feature = "vulkan")] vulkan: Hub, - #[cfg(metal)] + #[cfg(feature = "metal")] metal: Hub, - #[cfg(dx12)] + #[cfg(feature = "dx12")] dx12: Hub, - #[cfg(dx11)] + #[cfg(feature = "dx11")] dx11: Hub, - #[cfg(gl)] + #[cfg(feature = "gles")] gl: Hub, } impl Hubs { fn new(factory: &F) -> Self { Self { - #[cfg(vulkan)] + #[cfg(feature = "vulkan")] vulkan: Hub::new(factory), - #[cfg(metal)] + #[cfg(feature = "metal")] metal: Hub::new(factory), - #[cfg(dx12)] + #[cfg(feature = "dx12")] dx12: Hub::new(factory), - #[cfg(dx11)] + #[cfg(feature = "dx11")] dx11: Hub::new(factory), - #[cfg(gl)] + #[cfg(feature = "gles")] gl: Hub::new(factory), } } @@ -1089,15 +1089,15 @@ impl Hubs { #[derive(Debug)] pub struct GlobalReport { pub surfaces: StorageReport, - #[cfg(vulkan)] + #[cfg(feature = "vulkan")] pub vulkan: Option, - #[cfg(metal)] + #[cfg(feature = "metal")] pub metal: Option, - #[cfg(dx12)] + #[cfg(feature = "dx12")] pub dx12: Option, - #[cfg(dx11)] + #[cfg(feature = "dx11")] pub dx11: Option, - #[cfg(gl)] + #[cfg(feature = "gles")] pub gl: Option, } @@ -1162,31 +1162,31 @@ impl Global { pub fn generate_report(&self) -> GlobalReport { GlobalReport { surfaces: self.surfaces.data.read().generate_report(), - #[cfg(vulkan)] + #[cfg(feature = "vulkan")] vulkan: if self.instance.vulkan.is_some() { Some(self.hubs.vulkan.generate_report()) } else { None }, - #[cfg(metal)] + #[cfg(feature = "metal")] metal: if self.instance.metal.is_some() { Some(self.hubs.metal.generate_report()) } else { None }, - #[cfg(dx12)] + #[cfg(feature = "dx12")] dx12: if self.instance.dx12.is_some() { Some(self.hubs.dx12.generate_report()) } else { None }, - #[cfg(dx11)] + #[cfg(feature = "dx11")] dx11: if self.instance.dx11.is_some() { Some(self.hubs.dx11.generate_report()) } else { None }, - #[cfg(gl)] + #[cfg(feature = "gles")] gl: if self.instance.gl.is_some() { Some(self.hubs.gl.generate_report()) } else { @@ -1203,23 +1203,23 @@ impl Drop for Global { let mut surface_guard = self.surfaces.data.write(); // destroy hubs before the instance gets dropped - #[cfg(vulkan)] + #[cfg(feature = "vulkan")] { self.hubs.vulkan.clear(&mut surface_guard, true); } - #[cfg(metal)] + #[cfg(feature = "metal")] { self.hubs.metal.clear(&mut surface_guard, true); } - #[cfg(dx12)] + #[cfg(feature = "dx12")] { self.hubs.dx12.clear(&mut surface_guard, true); } - #[cfg(dx11)] + #[cfg(feature = "dx11")] { self.hubs.dx11.clear(&mut surface_guard, true); } - #[cfg(gl)] + #[cfg(feature = "gles")] { self.hubs.gl.clear(&mut surface_guard, true); } @@ -1261,7 +1261,7 @@ impl HalApi for hal::api::Empty { } } -#[cfg(vulkan)] +#[cfg(feature = "vulkan")] impl HalApi for hal::api::Vulkan { const VARIANT: Backend = Backend::Vulkan; fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance { @@ -1285,7 +1285,7 @@ impl HalApi for hal::api::Vulkan { } } -#[cfg(metal)] +#[cfg(feature = "metal")] impl HalApi for hal::api::Metal { const VARIANT: Backend = Backend::Metal; fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance { @@ -1309,7 +1309,7 @@ impl HalApi for hal::api::Metal { } } -#[cfg(dx12)] +#[cfg(feature = "dx12")] impl HalApi for hal::api::Dx12 { const VARIANT: Backend = Backend::Dx12; fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance { @@ -1333,7 +1333,7 @@ impl HalApi for hal::api::Dx12 { } } -#[cfg(dx11)] +#[cfg(feature = "dx11")] impl HalApi for hal::api::Dx11 { const VARIANT: Backend = Backend::Dx11; fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance { @@ -1357,7 +1357,7 @@ impl HalApi for hal::api::Dx11 { } } -#[cfg(gl)] +#[cfg(feature = "gles")] impl HalApi for hal::api::Gles { const VARIANT: Backend = Backend::Gl; fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance { diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index f1419c78d0c..5b10d738406 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -54,15 +54,15 @@ fn downlevel_default_limits_less_than_default_limits() { pub struct Instance { #[allow(dead_code)] pub name: String, - #[cfg(vulkan)] + #[cfg(feature = "vulkan")] pub vulkan: Option>, - #[cfg(metal)] + #[cfg(feature = "metal")] pub metal: Option>, - #[cfg(dx12)] + #[cfg(feature = "dx12")] pub dx12: Option>, - #[cfg(dx11)] + #[cfg(feature = "dx11")] pub dx11: Option>, - #[cfg(gl)] + #[cfg(feature = "gles")] pub gl: Option>, } @@ -87,15 +87,15 @@ impl Instance { Self { name: name.to_string(), - #[cfg(vulkan)] + #[cfg(feature = "vulkan")] vulkan: init(hal::api::Vulkan, backends), - #[cfg(metal)] + #[cfg(feature = "metal")] metal: init(hal::api::Metal, backends), - #[cfg(dx12)] + #[cfg(feature = "dx12")] dx12: init(hal::api::Dx12, backends), - #[cfg(dx11)] + #[cfg(feature = "dx11")] dx11: init(hal::api::Dx11, backends), - #[cfg(gl)] + #[cfg(feature = "gles")] gl: init(hal::api::Gles, backends), } } @@ -112,30 +112,30 @@ impl Instance { } } } - #[cfg(vulkan)] + #[cfg(feature = "vulkan")] destroy(hal::api::Vulkan, &self.vulkan, surface.vulkan); - #[cfg(metal)] + #[cfg(feature = "metal")] destroy(hal::api::Metal, &self.metal, surface.metal); - #[cfg(dx12)] + #[cfg(feature = "dx12")] destroy(hal::api::Dx12, &self.dx12, surface.dx12); - #[cfg(dx11)] + #[cfg(feature = "dx11")] destroy(hal::api::Dx11, &self.dx11, surface.dx11); - #[cfg(gl)] + #[cfg(feature = "gles")] destroy(hal::api::Gles, &self.gl, surface.gl); } } pub struct Surface { pub(crate) presentation: Option, - #[cfg(vulkan)] + #[cfg(feature = "vulkan")] pub vulkan: Option>, - #[cfg(metal)] + #[cfg(feature = "metal")] pub metal: Option>, - #[cfg(dx12)] + #[cfg(feature = "dx12")] pub dx12: Option>, - #[cfg(dx11)] + #[cfg(feature = "dx11")] pub dx11: Option>, - #[cfg(gl)] + #[cfg(feature = "gles")] pub gl: Option>, } @@ -451,15 +451,15 @@ impl Global { let surface = Surface { presentation: None, - #[cfg(vulkan)] + #[cfg(feature = "vulkan")] vulkan: init::(&self.instance.vulkan, display_handle, window_handle), - #[cfg(metal)] + #[cfg(feature = "metal")] metal: init::(&self.instance.metal, display_handle, window_handle), - #[cfg(dx12)] + #[cfg(feature = "dx12")] dx12: init::(&self.instance.dx12, display_handle, window_handle), - #[cfg(dx11)] + #[cfg(feature = "dx11")] dx11: init::(&self.instance.dx11, display_handle, window_handle), - #[cfg(gl)] + #[cfg(feature = "gles")] gl: init::(&self.instance.gl, display_handle, window_handle), }; @@ -468,7 +468,7 @@ impl Global { id.0 } - #[cfg(metal)] + #[cfg(feature = "metal")] pub fn instance_create_surface_metal( &self, layer: *mut std::ffi::c_void, @@ -486,9 +486,9 @@ impl Global { }, //acquired_texture: None, }), - #[cfg(vulkan)] + #[cfg(feature = "vulkan")] vulkan: None, - #[cfg(gl)] + #[cfg(feature = "gles")] gl: None, }; @@ -551,7 +551,7 @@ impl Global { Ok(id.0) } - #[cfg(dx12)] + #[cfg(feature = "dx12")] /// # Safety /// /// The visual must be valid and able to be used to make a swapchain with. @@ -564,13 +564,13 @@ impl Global { let surface = Surface { presentation: None, - #[cfg(vulkan)] + #[cfg(feature = "vulkan")] vulkan: None, dx12: self.instance.dx12.as_ref().map(|inst| HalSurface { raw: unsafe { inst.create_surface_from_visual(visual as _) }, }), dx11: None, - #[cfg(gl)] + #[cfg(feature = "gles")] gl: None, }; @@ -623,25 +623,25 @@ impl Global { let mut adapters = Vec::new(); - #[cfg(vulkan)] + #[cfg(feature = "vulkan")] self.enumerate( hal::api::Vulkan, &self.instance.vulkan, &inputs, &mut adapters, ); - #[cfg(metal)] + #[cfg(feature = "metal")] self.enumerate( hal::api::Metal, &self.instance.metal, &inputs, &mut adapters, ); - #[cfg(dx12)] + #[cfg(feature = "dx12")] self.enumerate(hal::api::Dx12, &self.instance.dx12, &inputs, &mut adapters); - #[cfg(dx11)] + #[cfg(feature = "dx11")] self.enumerate(hal::api::Dx11, &self.instance.dx11, &inputs, &mut adapters); - #[cfg(gl)] + #[cfg(feature = "gles")] self.enumerate(hal::api::Gles, &self.instance.gl, &inputs, &mut adapters); adapters @@ -724,7 +724,7 @@ impl Global { .transpose()?; let mut device_types = Vec::new(); - #[cfg(vulkan)] + #[cfg(feature = "vulkan")] let (id_vulkan, adapters_vk) = gather( hal::api::Vulkan, self.instance.vulkan.as_ref(), @@ -733,7 +733,7 @@ impl Global { desc.force_fallback_adapter, &mut device_types, ); - #[cfg(metal)] + #[cfg(feature = "metal")] let (id_metal, adapters_metal) = gather( hal::api::Metal, self.instance.metal.as_ref(), @@ -742,7 +742,7 @@ impl Global { desc.force_fallback_adapter, &mut device_types, ); - #[cfg(dx12)] + #[cfg(feature = "dx12")] let (id_dx12, adapters_dx12) = gather( hal::api::Dx12, self.instance.dx12.as_ref(), @@ -751,7 +751,7 @@ impl Global { desc.force_fallback_adapter, &mut device_types, ); - #[cfg(dx11)] + #[cfg(feature = "dx11")] let (id_dx11, adapters_dx11) = gather( hal::api::Dx11, self.instance.dx11.as_ref(), @@ -760,7 +760,7 @@ impl Global { desc.force_fallback_adapter, &mut device_types, ); - #[cfg(gl)] + #[cfg(feature = "gles")] let (id_gl, adapters_gl) = gather( hal::api::Gles, self.instance.gl.as_ref(), @@ -813,23 +813,23 @@ impl Global { }; let mut selected = preferred_gpu.unwrap_or(0); - #[cfg(vulkan)] + #[cfg(feature = "vulkan")] if let Some(id) = self.select(&mut selected, id_vulkan, adapters_vk) { return Ok(id); } - #[cfg(metal)] + #[cfg(feature = "metal")] if let Some(id) = self.select(&mut selected, id_metal, adapters_metal) { return Ok(id); } - #[cfg(dx12)] + #[cfg(feature = "dx12")] if let Some(id) = self.select(&mut selected, id_dx12, adapters_dx12) { return Ok(id); } - #[cfg(dx11)] + #[cfg(feature = "dx11")] if let Some(id) = self.select(&mut selected, id_dx11, adapters_dx11) { return Ok(id); } - #[cfg(gl)] + #[cfg(feature = "gles")] if let Some(id) = self.select(&mut selected, id_gl, adapters_gl) { return Ok(id); } @@ -853,15 +853,15 @@ impl Global { let fid = A::hub(self).adapters.prepare(input); match A::VARIANT { - #[cfg(vulkan)] + #[cfg(feature = "vulkan")] Backend::Vulkan => fid.assign(Adapter::new(hal_adapter), &mut token).0, - #[cfg(metal)] + #[cfg(feature = "metal")] Backend::Metal => fid.assign(Adapter::new(hal_adapter), &mut token).0, - #[cfg(dx12)] + #[cfg(feature = "dx12")] Backend::Dx12 => fid.assign(Adapter::new(hal_adapter), &mut token).0, - #[cfg(dx11)] + #[cfg(feature = "dx11")] Backend::Dx11 => fid.assign(Adapter::new(hal_adapter), &mut token).0, - #[cfg(gl)] + #[cfg(feature = "gles")] Backend::Gl => fid.assign(Adapter::new(hal_adapter), &mut token).0, _ => unreachable!(), } diff --git a/wgpu-core/src/lib.rs b/wgpu-core/src/lib.rs index 86f6c469aab..43ae55ba864 100644 --- a/wgpu-core/src/lib.rs +++ b/wgpu-core/src/lib.rs @@ -278,26 +278,36 @@ platform supports."; // evaluated when the macro is used; we've just moved the `#[cfg]` into a macro // used by `wgpu-core` itself. -/// Define an exported macro named `$public` that expands to a call if the -/// configuration predicate `$condition` is true, or to a panic otherwise. +/// Define an exported macro named `$public` that expands to an expression if +/// the feature `$feature` is enabled, or to a panic otherwise. +/// +/// For a call like this: +/// +/// define_backend_caller! { name, hidden_name, feature } +/// +/// define a macro `name`, used like this: +/// +/// name!(expr) +/// +/// that expands to `expr` if `feature` is enabled, or a panic otherwise. /// /// Because of odd technical limitations on exporting macros expanded by other /// macros, you must supply a both a public-facing name for the macro and a -/// private name, which is never used outside this macro. For details: +/// hidden name, which is never used outside this macro. For details: /// macro_rules! define_backend_caller { - { $public:ident, $private:ident if $condition:meta } => { - #[cfg( $condition )] + { $public:ident, $private:ident if $feature:literal } => { + #[cfg(feature = $feature )] #[macro_export] macro_rules! $private { - ( $backend:literal, $call:expr ) => ( $call ) + ( $call:expr ) => ( $call ) } - #[cfg(not( $condition ))] + #[cfg(not(feature = $feature ))] #[macro_export] macro_rules! $private { - ( $backend:literal, $call:expr ) => ( - panic!("Unexpected backend {:?}", $backend) + ( $call:expr ) => ( + panic!("Identifier refers to disabled backend feature {:?}", $feature) ) } @@ -305,37 +315,17 @@ macro_rules! define_backend_caller { } } -define_backend_caller! { - gfx_if_vulkan, gfx_if_vulkan_hidden - if any( - all(not(target_arch = "wasm32"), not(target_os = "ios"), not(target_os = "macos")), - feature = "vulkan-portability" - ) -} - -define_backend_caller! { - gfx_if_metal, gfx_if_metal_hidden - if all(not(target_arch = "wasm32"), any(target_os = "ios", target_os = "macos")) -} - -define_backend_caller! { - gfx_if_dx12, gfx_if_dx12_hidden - if all(not(target_arch = "wasm32"), windows) -} - -define_backend_caller! { - gfx_if_dx11, gfx_if_dx11_hidden - if all(not(target_arch = "wasm32"), windows) -} - -define_backend_caller! { - gfx_if_gles, gfx_if_gles_hidden - if any( - all(unix, not(target_os = "macos"), not(target_os = "ios")), - feature = "angle", - target_arch = "wasm32" - ) -} +// Define a macro for each `gfx_select!` match arm. For example, +// +// gfx_if_vulkan!(expr) +// +// expands to `expr` if the `"vulkan"` feature is enabled, or to a panic +// otherwise. +define_backend_caller! { gfx_if_vulkan, gfx_if_vulkan_hidden if "vulkan" } +define_backend_caller! { gfx_if_metal, gfx_if_metal_hidden if "metal" } +define_backend_caller! { gfx_if_dx12, gfx_if_dx12_hidden if "dx12" } +define_backend_caller! { gfx_if_dx11, gfx_if_dx11_hidden if "dx11" } +define_backend_caller! { gfx_if_gles, gfx_if_gles_hidden if "gles" } /// Dispatch on an [`Id`]'s backend to a backend-generic method. /// @@ -386,11 +376,11 @@ define_backend_caller! { macro_rules! gfx_select { ($id:expr => $global:ident.$method:ident( $($param:expr),* )) => { match $id.backend() { - wgt::Backend::Vulkan => $crate::gfx_if_vulkan!("Vulkan", $global.$method::<$crate::api::Vulkan>( $($param),* )), - wgt::Backend::Metal => $crate::gfx_if_metal!("Metal", $global.$method::<$crate::api::Metal>( $($param),* )), - wgt::Backend::Dx12 => $crate::gfx_if_dx12!("Dx12", $global.$method::<$crate::api::Dx12>( $($param),* )), - wgt::Backend::Dx11 => $crate::gfx_if_dx11!("Dx11", $global.$method::<$crate::api::Dx11>( $($param),* )), - wgt::Backend::Gl => $crate::gfx_if_gles!("Gles", $global.$method::<$crate::api::Gles>( $($param),+ )), + wgt::Backend::Vulkan => $crate::gfx_if_vulkan!($global.$method::<$crate::api::Vulkan>( $($param),* )), + wgt::Backend::Metal => $crate::gfx_if_metal!($global.$method::<$crate::api::Metal>( $($param),* )), + wgt::Backend::Dx12 => $crate::gfx_if_dx12!($global.$method::<$crate::api::Dx12>( $($param),* )), + wgt::Backend::Dx11 => $crate::gfx_if_dx11!($global.$method::<$crate::api::Dx11>( $($param),* )), + wgt::Backend::Gl => $crate::gfx_if_gles!($global.$method::<$crate::api::Gles>( $($param),+ )), other => panic!("Unexpected backend {:?}", other), } }; diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index aa8bbcada98..9fee2782c3d 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -27,7 +27,7 @@ rustdoc-args = ["--cfg", "docsrs"] [lib] [features] -default = ["gles"] +default = [] metal = ["naga/msl-out", "block", "foreign-types"] vulkan = ["naga/spv-out", "ash", "gpu-alloc", "gpu-descriptor", "libloading", "smallvec"] gles = ["naga/glsl-out", "glow", "egl", "libloading"] diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index b688e326d69..dcce62899d5 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -49,6 +49,15 @@ clippy::pattern_type_mismatch, )] +#[cfg(not(any( + feature = "dx11", + feature = "dx12", + feature = "gles", + feature = "metal", + feature = "vulkan" +)))] +compile_error!("No back ends enabled in `wgpu-hal`. Enable at least one backend feature."); + #[cfg(all(feature = "metal", not(any(target_os = "macos", target_os = "ios"))))] compile_error!("Metal API enabled on non-Apple OS. If your project is not using resolver=\"2\" in Cargo.toml, it should."); #[cfg(all(feature = "dx12", not(windows)))] diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 57bafc566a8..93c5a773ace 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -88,20 +88,49 @@ emscripten = ["webgl"] vulkan-portability = ["wgc/vulkan-portability"] expose-ids = [] -[target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgc] +# wgpu-core is always available as an optional dependency, "wgc". +# Whenever wgpu-core is selected, we want the GLES backend and raw +# window handle support. +[dependencies.wgc] +optional = true workspace = true -features = ["raw-window-handle"] +features = ["raw-window-handle", "gles"] -[target.'cfg(target_arch = "wasm32")'.dependencies.wgc] +# wgpu-core is required whenever not targeting web APIs directly. +# Whenever wgpu-core is selected, we want the GLES backend and raw +# window handle support. +[target.'cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))'.dependencies.wgc] workspace = true -features = ["raw-window-handle"] -optional = true +features = ["raw-window-handle", "gles"] -[dependencies.wgt] +# We want the wgpu-core Metal backend on macOS and iOS. +# (We should consider also enabling "vulkan" for Vulkan Portability.) +[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.wgc] workspace = true +features = ["metal"] -[target.'cfg(not(target_arch = "wasm32"))'.dependencies.hal] +# We want the wgpu-core Direct3D backends on Windows. +[target.'cfg(windows)'.dependencies.wgc] workspace = true +features = ["dx11", "dx12"] + +# We want the wgpu-core Vulkan backend on Unix (but not Emscripten) and Windows. +[target.'cfg(any(windows, all(unix, not(target_arch = "emscripten"))))'.dependencies.wgc] +workspace = true +features = ["vulkan"] + +[dependencies.wgt] +workspace = true + +# We need wgpu-hal unless we're targeting the web APIs. +[target.'cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))'.dependencies] +hal = { workspace = true } + +[target.'cfg(all(not(target_arch = "wasm32"), unix, not(target_os = "ios"), not(target_os = "macos")))'.dependencies] +hal = { workspace = true, features = ["renderdoc"] } + +[target.'cfg(windows)'.dependencies] +hal = { workspace = true, features = ["renderdoc"] } [target.'cfg(target_arch = "wasm32")'.dependencies.hal] workspace = true