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 4bbd51a6a1..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" @@ -594,7 +588,7 @@ dependencies = [ [[package]] name = "deno_webgpu" -version = "0.63.0" +version = "0.81.0" dependencies = [ "deno_core", "serde", @@ -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