Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there any chance that I can choose to enable what backend will be compiled into the binary? #1221

Closed
xhebox opened this issue Feb 17, 2021 · 20 comments
Labels
area: ecosystem Help the connected projects grow and prosper help required We need community help to make this happen. type: question Further information is requested

Comments

@xhebox
Copy link

xhebox commented Feb 17, 2021

Is your feature request related to a problem? Please describe.
I've tried gfx-hal, and that is good library. But wgpu is much easier to use than gfx. I prefer wgpu and I know clearly I only want to use vulkan. Despite what backend flags I passed to init the instance, gl backend is also compiled.

Describe the solution you'd like
Some features passed from wgpu-rs to wgpu, so that I can choose what I want to use.

Describe alternatives you've considered
None

Additional context
None

@kvark
Copy link
Member

kvark commented Feb 17, 2021

Are you concerned about the code size for the GL backend that becomes a part of the binary? It would be interesting to make a test, say with your application, by compile-time disabling GL and seeing how it affected the size. This would be done by checking out wgpu and adding a patch section to your Cargo toml.

@kvark kvark added area: ecosystem Help the connected projects grow and prosper help required We need community help to make this happen. type: question Further information is requested labels Feb 17, 2021
@xhebox
Copy link
Author

xhebox commented Feb 17, 2021

Yes, it is around 0.7MB using cargo-bloat. Another big library is spirv_cross. This is what I got under windows, after removing gl and dx11:

cargo bloat --release --crates

 File  .text     Size Crate
23.3%  34.3%   1.7MiB spirv_cross
22.2%  32.6%   1.6MiB std
11.8%  17.3% 877.4KiB [Unknown]
10.7%  15.7% 795.2KiB wgpu_core
 0.1%   0.1%   4.4KiB wepoll_sys
68.0% 100.0%   4.9MiB .text section size, the file size is 7.3MiB

I'll get the output under linux later.

@kvark
Copy link
Member

kvark commented Feb 17, 2021

SPIRV-Cross has just become an optional dependency in #1220, so maybe this is fine now?
Note that there is going to be a bit of a delay before wgpu-rs can consider it to be optional.

@xhebox
Copy link
Author

xhebox commented Feb 17, 2021

OK, I remembered it wrong... Basically the largest one is spirv_cross. Of course, this result is with lto = true. This is the result under linux:

15.3%  21.2% 758.8KiB wgpu
13.7%  19.0% 678.7KiB spirv_cross
 9.0%  12.5% 446.7KiB std
 8.1%  11.2% 401.0KiB wgpu_core
 7.0%   9.7% 346.9KiB naga
 3.2%   4.4% 156.9KiB [Unknown]
 2.8%   3.9% 138.8KiB wgpu_lut
 2.5%   3.4% 122.4KiB gfx_backend_gl
 1.8%   2.6%  91.3KiB inplace_it
 1.7%   2.3%  83.4KiB hashbrown
 1.1%   1.5%  52.8KiB gfx_backend_vulkan
 0.8%   1.2%  41.7KiB gpu_descriptor
 0.7%   1.0%  35.2KiB ash
 0.5%   0.7%  24.7KiB spirv_headers
 0.4%   0.6%  21.1KiB async_io
 0.4%   0.6%  20.6KiB gfx_hal
 0.4%   0.5%  18.0KiB async_global_executor
 0.3%   0.4%  14.8KiB glow
 0.3%   0.4%  14.1KiB parking_lot
 0.2%   0.3%  11.0KiB miniz_oxide
 1.4%   1.9%  68.9KiB And 26 more crates. Use -n N to show more.

This what I got without lto:

14.7%  23.8% 972.8KiB wgpu
10.3%  16.7% 680.9KiB spirv_cross
 6.1%   9.9% 403.6KiB naga
 5.4%   8.7% 357.4KiB std
 5.4%   8.7% 355.3KiB wgpu_core
 4.2%   6.7% 275.7KiB inplace_it
 2.8%   4.6% 186.7KiB wgpu_lut
 2.4%   3.9% 157.5KiB gfx_backend_gl
 2.1%   3.5% 141.0KiB [Unknown]
 1.3%   2.1%  85.7KiB hashbrown
 1.0%   1.6%  66.3KiB gfx_backend_vulkan
 0.8%   1.3%  54.1KiB ash
 0.5%   0.8%  32.1KiB async_global_executor
 0.5%   0.8%  31.3KiB glow
 0.4%   0.7%  29.8KiB async_io
 0.3%   0.6%  23.2KiB gpu_descriptor
 0.3%   0.5%  20.9KiB gpu_alloc
 0.3%   0.5%  20.9KiB gfx_hal
 0.2%   0.3%  13.5KiB spirv_headers
 0.2%   0.3%  13.3KiB parking_lot
 1.5%   2.4%  96.6KiB And 36 more crates. Use -n N to show more.
61.5% 100.0%   4.0MiB .text section size, the file size is 6.5MiB

Well, I guess that I found that spirv_cross is used by other backends. So I want to disable other backends. I won't close the issue. It is indeed possible that other backends will involve some unused dependencies.

@kvark
Copy link
Member

kvark commented Feb 17, 2021

This is very informative, thank you!
Would you mind doing a local patch to wgpu-rs that doesn't enable "cross" feature in wpu-core? I'm curious to see the numbers when this feature isn't enabled.

@xhebox
Copy link
Author

xhebox commented Feb 17, 2021

Here it is :)

[profile.release]
panic = "abort"
strip = "debuginfo"
lto = true

20.0%  26.7% 804.9KiB wgpu
12.1%  16.2% 487.0KiB std
10.3%  13.8% 416.0KiB naga
10.0%  13.4% 403.4KiB wgpu_core
 3.9%   5.3% 158.9KiB gfx_backend_gl
 3.4%   4.5% 136.5KiB wgpu_lut
 3.3%   4.4% 132.6KiB inplace_it
 2.4%   3.2%  97.4KiB hashbrown
 1.3%   1.8%  53.3KiB gfx_backend_vulkan
 1.0%   1.4%  41.3KiB gpu_descriptor
 0.9%   1.2%  35.2KiB ash
 0.7%   0.9%  28.0KiB spirv_headers
 0.5%   0.7%  21.1KiB async_io
 0.5%   0.7%  20.6KiB gfx_hal
 0.5%   0.6%  18.2KiB async_global_executor
 0.4%   0.6%  16.8KiB [Unknown]
 0.4%   0.5%  14.8KiB glow
 0.4%   0.5%  14.1KiB parking_lot
 0.3%   0.4%  11.0KiB miniz_oxide
 0.2%   0.3%   8.3KiB smallvec
 1.5%   2.0%  61.4KiB And 26 more crates. Use -n N to show more.
74.7% 100.0%   2.9MiB .text section size, the file size is 3.9MiB

I believe that wgpu can be made smaller somehow. You could also use cargo bloat to track the largest part in wgpu. link here.

@Shatur
Copy link

Shatur commented Dec 12, 2021

It would be great to control backends. In Bevy, for example, wgpu is a public API. And to be able to run the same game logic on the server, I need to build Bevy with wgpu, but without backends: bevyengine/bevy#3155 (comment)

@kvark
Copy link
Member

kvark commented Dec 14, 2021

If backends can be enabled individually with features, how can we make sure that people can just use "auto" mode - the logic that we have now? I.e. introducing features would immediately require the users to complicate their cargo manifests with something like this:

[target.'cfg(target_arch = "wasm32")'.dependencies]
wgpu = { version = "0.11", features = ["gles"] }

[target.'cfg(all(not(target_arch = "wasm32"), any(target_os = "ios", target_os = "macos")))'.dependencies]
wgpu = { version = "0.11", features = ["metal"] }

[target.'cfg(all(not(target_arch = "wasm32"), unix, not(target_os = "ios"), not(target_os = "macos")))'.dependencies]
wgpu = { version = "0.11", features = ["vulkan", "gles", "renderdoc"] }

[target.'cfg(all(not(target_arch = "wasm32"), windows))'.dependencies]
wgpu = { version = "0.11", features = ["vulkan", "dx12", "renderdoc"] }

I don't think our users are going to be excited for this...

@Shatur it's clear you don't want to run the same rendering logic on client and server. So wgpu use in the logic you do want to run is rather accidental, is it?

@Shatur
Copy link

Shatur commented Dec 14, 2021

I.e. introducing features would immediately require the users to complicate their cargo manifests with something like this:

Totally agree, I understand why we have prereconfigured backends.

it's clear you don't want to run the same rendering logic on client and server. So wgpu use in the logic you do want to run is rather accidental, is it?

It would be great to avoid having wgpu on server. But for relatively complex games, the server uses exactly the same logic as the client. So in Bevy we could do the following:

  1. Guard all wgpu usage with compile-time checks. But this make code very ugly, see Add headless renderer bevyengine/bevy#3155 (comment)
  2. Add additional API over wgpu that "fakes" wgpu if wgpu is disabled in features. But it is very difficult to maintain and it's basically mirroring of wgpu code.
  3. Use wgpu as a public API by simply removing all rendering backends from the server. This is how it done in Godot.

@cart suggested to use the approach number 3, but it currently impossible due to preconfigured backends for specific platforms. So I decided to ask 😄 Is it possible to move this preconfigured features to default-features to let users opt-out them?

@kvark
Copy link
Member

kvark commented Dec 14, 2021

Main blocker is that default features can't be platform dependent. I think it's rust-lang/cargo#1197, although Rust issues are sometimes hard to navigate... If it was possible, we'd take it in a heartbeat.

There is another possible solution just for your case - via backends of wgpu-rs itself (as opposed to wgpu-core). It currently has the "web" backend and the wgpu-core backend. It needs also to have a "native header" backend, linking to an implementation to webgpu-headers. So we could add a "dummy" backend there.

Problem is - this would only help your case but not @xhebox or other peoples similar needs. So I can't recommend this path.

@Shatur
Copy link

Shatur commented Dec 14, 2021

So we could add a "dummy" backend there.

Hm... Yes, it would solve the problem.

Problem is - this would only help your case but not @xhebox or other peoples similar needs. So I can't recommend this path.

Agree, it would be better to solve the problem globally via backend configuration. But now I'm not sure if there is an elegant solution. We could move out automatic backend selection into a separate crate that depends on wgpu, but it looks dirty. The dummy backend seems like a more clean solution as to me.

@kvark
Copy link
Member

kvark commented Dec 14, 2021

The dummy backend for your specific case is ultimately better than other alternatives, since the whole wgpu-core gets compiled out from the server. I filed #2291

@Shatur
Copy link

Shatur commented Dec 14, 2021

You are right, a dummy backend for wgpu is much better for servers then just disabling graphical backends and could be a separate feature. Thanks!

@aloucks
Copy link
Contributor

aloucks commented Dec 18, 2021

I believe WGPU used to work in the way that @xhebox is asking for. Each backend was a compile time feature. It was kind of a pain to switch back and forth between backends while testing changes. Now we've moved to the opposite extreme where everything is compiled into the binary at all times and there is no way to exclude the backends that you don't need or care about.

I think the situation is overall better now, but I do see still a use case for wanting to remove extra backends if you know you're not going to target them.

Perhaps the suggestion above about having the backends as default features that you may opt-out of is the ideal middle ground.

@kvark
Copy link
Member

kvark commented Dec 18, 2021

@aloucks we can't follow this suggestion because default features in cargo today can't be platform-dependent...

@aloucks
Copy link
Contributor

aloucks commented Dec 18, 2021

@kvark I don't think they need to be.

I was able to set metal as a default feature and then adjust the config guards to alias empty to metal when not on an apple platform. I could build and run examples on Windows 10. There's probably a bit more work involved to expose it cleanly from the base wgpu crate, but I think it's doable in theory.

I don't think this is terribly high priority to fix or anything, but I'd always be happy to have a way to reduce compile time :)

$ git diff -p
diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml
index 43e850ba..238e90ab 100644
--- a/wgpu-hal/Cargo.toml
+++ b/wgpu-hal/Cargo.toml
@@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0"
 [lib]
 
 [features]
-default = []
+default = ["metal"]
 metal = ["naga/msl-out", "block", "foreign-types"]
 vulkan = ["naga/spv-out", "ash", "gpu-alloc", "gpu-descriptor", "libloading", "inplace_it"]
 gles = ["naga/glsl-out", "glow", "egl", "libloading"]
diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs
index 4b292a3b..e12ebe63 100644
--- a/wgpu-hal/src/lib.rs
+++ b/wgpu-hal/src/lib.rs
@@ -47,8 +47,6 @@
     clippy::pattern_type_mismatch,
 )]
 
-#[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)))]
 compile_error!("DX12 API enabled on non-Windows OS. If your project is not using resolver=\"2\" in Cargo.toml, it should.");
 
@@ -57,8 +55,10 @@ mod dx12;
 mod empty;
 #[cfg(all(feature = "gles"))]
 mod gles;
-#[cfg(all(feature = "metal"))]
+#[cfg(all(feature = "metal", any(target_os = "macos", target_os = "ios")))]
 mod metal;
+#[cfg(not(all(feature = "metal", any(target_os = "macos", target_os = "ios"))))]
+use empty as metal;
 #[cfg(feature = "vulkan")]
 mod vulkan;

@kvark
Copy link
Member

kvark commented Dec 18, 2021

@aloucks we should probably discuss this on the matrix if you are able to.
So far, I don't see how this would work, still.

metal = ["naga/msl-out", "block", "foreign-types"]

If metal is in defaults, then these dependencies are enabled for all platforms, which is highly undesirable.

@teoxoy
Copy link
Member

teoxoy commented Feb 14, 2023

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

wgpu/wgpu/Cargo.toml

Lines 121 to 133 in 581b22e

[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"), not(target_os = "ios"), not(target_os = "macos"))))'.dependencies.wgc]
workspace = true
features = ["vulkan"]

I think this behavior makes sense, additionally we can expose a feature flag compat (mapping to a future WebGPU Compat - there has been some talk about this in the group) that covers DX11 and GLES.

@xhebox @aloucks does it sound like a satisfactory solution?

@xhebox
Copy link
Author

xhebox commented Feb 15, 2023

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

wgpu/wgpu/Cargo.toml

Lines 121 to 133 in 581b22e

[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"), not(target_os = "ios"), not(target_os = "macos"))))'.dependencies.wgc]
workspace = true
features = ["vulkan"]

I think this behavior makes sense, additionally we can expose a feature flag compat (mapping to a future WebGPU Compat - there has been some talk about this in the group about this) that covers DX11 and GLES.

@xhebox @aloucks does it sound like a satisfactory solution?

Sounds great!

@teoxoy
Copy link
Member

teoxoy commented Feb 21, 2023

I opened a new issue to track it: #3514 since this issue is a bit old with more baggage behind it.

@teoxoy teoxoy closed this as not planned Won't fix, can't repro, duplicate, stale Feb 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: ecosystem Help the connected projects grow and prosper help required We need community help to make this happen. type: question Further information is requested
Projects
None yet
Development

No branches or pull requests

5 participants