Skip to content

Commit

Permalink
Make wgpu-core users responsible for choosing back ends.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jimblandy committed Dec 3, 2022
1 parent d51b803 commit 6100d15
Show file tree
Hide file tree
Showing 13 changed files with 247 additions and 188 deletions.
13 changes: 10 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 0 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 19 additions & 1 deletion deno_webgpu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
31 changes: 15 additions & 16 deletions wgpu-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand All @@ -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
Expand Down Expand Up @@ -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
22 changes: 0 additions & 22 deletions wgpu-core/build.rs

This file was deleted.

10 changes: 5 additions & 5 deletions wgpu-core/src/device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5407,27 +5407,27 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let mut closures = UserClosures::default();
let mut all_queue_empty = true;

#[cfg(vulkan)]
#[cfg(feature = "vulkan")]
{
all_queue_empty = self.poll_devices::<hal::api::Vulkan>(force_wait, &mut closures)?
&& all_queue_empty;
}
#[cfg(metal)]
#[cfg(feature = "metal")]
{
all_queue_empty =
self.poll_devices::<hal::api::Metal>(force_wait, &mut closures)? && all_queue_empty;
}
#[cfg(dx12)]
#[cfg(feature = "dx12")]
{
all_queue_empty =
self.poll_devices::<hal::api::Dx12>(force_wait, &mut closures)? && all_queue_empty;
}
#[cfg(dx11)]
#[cfg(feature = "dx11")]
{
all_queue_empty =
self.poll_devices::<hal::api::Dx11>(force_wait, &mut closures)? && all_queue_empty;
}
#[cfg(gl)]
#[cfg(feature = "gles")]
{
all_queue_empty =
self.poll_devices::<hal::api::Gles>(force_wait, &mut closures)? && all_queue_empty;
Expand Down
60 changes: 30 additions & 30 deletions wgpu-core/src/hub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1057,30 +1057,30 @@ impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> {
}

pub struct Hubs<F: GlobalIdentityHandlerFactory> {
#[cfg(vulkan)]
#[cfg(feature = "vulkan")]
vulkan: Hub<hal::api::Vulkan, F>,
#[cfg(metal)]
#[cfg(feature = "metal")]
metal: Hub<hal::api::Metal, F>,
#[cfg(dx12)]
#[cfg(feature = "dx12")]
dx12: Hub<hal::api::Dx12, F>,
#[cfg(dx11)]
#[cfg(feature = "dx11")]
dx11: Hub<hal::api::Dx11, F>,
#[cfg(gl)]
#[cfg(feature = "gles")]
gl: Hub<hal::api::Gles, F>,
}

impl<F: GlobalIdentityHandlerFactory> Hubs<F> {
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),
}
}
Expand All @@ -1089,15 +1089,15 @@ impl<F: GlobalIdentityHandlerFactory> Hubs<F> {
#[derive(Debug)]
pub struct GlobalReport {
pub surfaces: StorageReport,
#[cfg(vulkan)]
#[cfg(feature = "vulkan")]
pub vulkan: Option<HubReport>,
#[cfg(metal)]
#[cfg(feature = "metal")]
pub metal: Option<HubReport>,
#[cfg(dx12)]
#[cfg(feature = "dx12")]
pub dx12: Option<HubReport>,
#[cfg(dx11)]
#[cfg(feature = "dx11")]
pub dx11: Option<HubReport>,
#[cfg(gl)]
#[cfg(feature = "gles")]
pub gl: Option<HubReport>,
}

Expand Down Expand Up @@ -1162,31 +1162,31 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
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 {
Expand All @@ -1203,23 +1203,23 @@ impl<G: GlobalIdentityHandlerFactory> Drop for Global<G> {
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);
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down
Loading

0 comments on commit 6100d15

Please sign in to comment.