From 857cfa3626232f56fd586c1651980a2126ef6da8 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Tue, 6 Dec 2022 10:52:56 -0800 Subject: [PATCH 1/2] Update workspace Cargo.lock for new deno_webgpu version. --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 4bbd51a6a1..b474ddf09c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -594,7 +594,7 @@ dependencies = [ [[package]] name = "deno_webgpu" -version = "0.63.0" +version = "0.81.0" dependencies = [ "deno_core", "serde", From 0a71de521a54df5dfdcbffdbd98d577afe54e26a Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Thu, 1 Dec 2022 09:40:17 -0800 Subject: [PATCH 2/2] 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 and emscripten, 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 | 37 +++++++------ 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 | 78 ++++++++++++--------------- wgpu-hal/src/lib.rs | 9 ++++ wgpu/Cargo.toml | 47 ++++++++++++++--- 12 files changed, 252 insertions(+), 189 deletions(-) delete mode 100644 wgpu-core/build.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c287b927c..5820963e17 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 7b29d6c68f..71bcdd2cd6 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 `emscripten` and `renderdoc` features +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 b474ddf09c..af15368ccb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -253,12 +253,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" @@ -2835,7 +2829,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 e8e200b6ae..4a47a9418e 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 c92865b73d..85156b2c24 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -17,6 +17,21 @@ 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"] + +# Compile for the Emscripten POSIX-in-a-web-page emulation environment. +emscripten = ["hal/emscripten"] + # 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 +47,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 @@ -59,22 +77,3 @@ 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 445ea245d2..0000000000 --- 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 86c79a9a6d..ef3d8ee8af 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 f07010477c..290df3c716 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 f1419c78d0..5b10d73840 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 f34025ab6b..c8b3fb7296 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 both a public-facing name for the macro and a /// private 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) ) } @@ -306,37 +316,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. /// @@ -387,11 +377,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/src/lib.rs b/wgpu-hal/src/lib.rs index b688e326d6..dcce62899d 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 57bafc566a..ff598434f3 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -88,20 +88,53 @@ 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"] + +# 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"] -[target.'cfg(not(target_arch = "wasm32"))'.dependencies.hal] +[target.'cfg(target_os = "emscripten")'.dependencies.wgc] workspace = true +features = ["emscripten"] + +[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