gfx-rs / wgpu

A cross-platform, safe, pure-Rust graphics API.
https://wgpu.rs
Apache License 2.0
12.03k stars 872 forks source link

Add a default feature for wgpu that enables Vulkan & GLES on Windows & Linux #3514

Open teoxoy opened 1 year ago

teoxoy commented 1 year ago

We currently only enable backends based on the target platform with the only exception being GLES which is always available.

We should expose a new feature flag (enabled by default) that covers the GLES and DX11 backends so that users not interested in those backends can avoid compiling them in their binaries.

Feature name ideas:

See background for this: https://github.com/gfx-rs/wgpu/issues/1221#issuecomment-1430067962

daxpedda commented 8 months ago

I was recently looking into this but the first roadblock I hit is that we can't differentiate between a new gles crate feature and the current angle crate feature, both enable wgc/gles.

A solution could be to introduce target-specific features in wgpu-core and wgpu-hal that are no-op on certain platforms. E.g. gles-native (no-op on MacOS) and gles-angle (no-op on everything but MacOS). This proposal would be similar to https://github.com/gfx-rs/wgpu/pull/3466.

I'd be happy to make a PR!

cwfitzgerald commented 8 months ago

I think we're moving in the direction of every backend being feature flagged. We have all the infrastructure in place, we just haven't lifted this to the wgpu level.

Distinguishing between angle and native would be useful!

daxpedda commented 8 months ago

So after playing around with it a bit I was so unsatisfied it doesn't make sense to me to proceed like that. The issue basically boils down to Cargo not being able to connect crate features that activate optional dependencies to specific targets.

Introducing gles-native and gles-angle we can use cfgs to guard code to specific targets, but the dependencies these features activate will be active nevertheless. E.g. if we use default = ["gles-native"], OpenGL won't work on MacOS, but the dependencies will still be present.

So the only good solution I can come up with to this problem is to create a separate crate that adds these defaults.

[package]
name = "wgpu-default-features"

# We want the wgpu-core Metal backend on macOS and iOS.
[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.wgc]
workspace = true
features = ["metal"]

# We want the wgpu-core Direct3D backends and OpenGL (via WGL) on Windows.
[target.'cfg(windows)'.dependencies.wgc]
workspace = true
features = ["dx11", "dx12", "gles"]

# We want the wgpu-core Vulkan backend on Unix (but not emscripten, macOS, iOS) and Windows.
[target.'cfg(any(windows, all(unix, not(target_os = "emscripten"), not(target_os = "ios"), not(target_os = "macos"))))'.dependencies.wgc]
workspace = true
features = ["vulkan"]

# We want the wgpu-core GLES backend on Unix (but not macOS, iOS).
[target.'cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))'.dependencies.wgc]
workspace = true
features = ["gles"]

And then we can use default ["dep:wgpu-default-features"] in wgpu.

Just for completeness, not actually proposing this: we could abandon default features.

daxpedda commented 8 months ago

Cc https://github.com/rust-lang/cargo/issues/1197. Left a user story there as well.

Wumpf commented 8 months ago

cont' conversation thread from https://github.com/gfx-rs/wgpu/pull/4815#issuecomment-1837096793 to quickly recap (plz correct me if needed): I suggested going all in on a style like gles-linux, gles-windows, gles-mac which is then translated to just gles in the code via https://docs.rs/cfg_aliases/latest/cfg_aliases/ As @daxpedda points out (and described here already!) this doesn't quite work since for instance gles-linux = ["wgc/gles"] would drag inwgc/gles for on Mac no matter what.

It's pretty awful, but it might be better than the alternative to just hand this problem on to wgc in turn? I.e. gles-linux = ["wgc/gles-linux"]. It seems to me that this is the least invasive situation and gives the same feature (literally) to the few direct users for wgpu-core where the problem would bubble up otherwise in the exact same way.

daxpedda commented 8 months ago

It's pretty awful, but it might be better than the alternative to just hand this problem on to wgc in turn?

We would have to go further into hal though, because in wgc we are having the exact same problem: gles-linux = ["hal/gles"]. Looking at hal, the gles feature activates the following dependencies:

Both naga/glsl-out and glow are not target specific dependencies, so we would be hitting the same problem again in hal as well: enabling hal/gles-linux would still bring in these dependencies no matter the target.

teoxoy commented 8 months ago

Why is it an issue that the dependencies will be present on the dev machine? They won't be compiled for the targets that don't support them.

Introducing gles-native and gles-angle we can use cfgs to guard code to specific targets, but the dependencies these features activate will be active nevertheless.

What does "active" mean in this context?

daxpedda commented 8 months ago

Why is it an issue that the dependencies will be present on the dev machine? They won't be compiled for the targets that don't support them.

Dead code elimination is not perfect, especially with things that rely on FFI and linked libraries, I don't have any data on that though. But it also does increase compile time, which is not insignificant when looking at the size and amount of dependencies we are talking about here. E.g. I know it was reported somewhere that MoltenVK is a problem because of linking, which is why it was removed from the default set in wgpu.

Introducing gles-native and gles-angle we can use cfgs to guard code to specific targets, but the dependencies these features activate will be active nevertheless.

What does "active" mean in this context?

I should probably stick with the word "enable". It means that a feature that enables a dependency pulls it in, it becomes part of the dependency graph and has to be compiled and such.

9SMTM6 commented 2 weeks ago

Note that this currently prevents the usage of pipeline-overridable constants on linux, since these don't seem to be supported on glsl-out.

Unsure if they will ever be supported on that backend, if not then I'd say this gains another strong reason to happen.

Wumpf commented 2 weeks ago

@9SMTM6 that's a completely orthogonal issue and not a known one I think: Pipeline overridable constants should work everywhere just fine starting with wgpu 0.20.0. Please open a new issue, ideally with a code snippet reproducing the problem. This issue here is about having no easy opt out of the GLES backend when it's unwanted

9SMTM6 commented 2 weeks ago

@Wumpf I have just realized that too, since I've gotten around to patching out the glsl backend.

Sorry for that, it made sense to me at that point, but evidently my pipeline is too complex for me to be able to properly attribute reason. I did check whether I only had wgpu 20.1+ with cargo tree, but as I said, with the glsl backend patched out it still doesn't work. And the way the error surfaced did not really make sense.

At this point I think the issue lies with naga_oil, I found part of the verbiage there, but I'll have to test more before I make a issue out of that ;-P.