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

Separate Out Backend Options into Individual Structs #6895

Open
wants to merge 1 commit into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 68 additions & 12 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,74 @@ let desc: ShaderModuleDescriptor = include_wgsl!(...)

By @cwfitzgerald and @rudderbucky in [#6662](https://github.com/gfx-rs/wgpu/pull/6662).

#### `wgpu::Instance::new` now takes `InstanceDescriptor` by reference

Previously `wgpu::Instance::new` took `InstanceDescriptor` by value (which is overall fairly uncommon in wgpu).
Furthermore, `InstanceDescriptor` is now cloneable.

```diff
- let instance = wgpu::Instance::new(instance_desc);
+ let instance = wgpu::Instance::new(&instance_desc);
```

By @wumpf in [#6849](https://github.com/gfx-rs/wgpu/pull/6849).

#### Environment Variable Handling Overhaul

Previously how various bits of code handled reading settings from environment variables was inconsistent and unideomatic.
We have unified it to `Type::from_env()` for all types.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found the with_env we had in a few places rather convenient as well. You'd do some settings and then instruct to be able to override it freely with environment variables.

We can take that as a separate iteration ofc

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case all from_env would just be a shortcut for default().with_env(). How that that sound to you?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine just feels a little indirect and I'm not sure I'd think of that pattern when looking at the docs maybe having both is the answer?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh both is exactly what you're suggesting

Copy link
Contributor

@kpreid kpreid Jan 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An advantage of from_env() -> Option<Self> is that the caller knows whether the environment variable was used (by seeing whether the Option is Some). This can be useful to give users hints about the usage of the variables, in particular,

  • if not set, that it is possible to change the behavior, and
  • if set, that the behavior was changed, which is useful confirmation when troubleshooting (because it separates “did the environment variable do anything? was it spelled correctly?” from “did using a different setting make any difference?”).

Some of the benefit can be gotten from logging the final value, but it’s clearer to explicitly log the provenance of the value rather than requiring the user to infer from whether it is different.

(It happens that in the only case so far I do this it's for initialize_adapter_from_env, which isn't changed in this PR and arguably shouldn’t change, but since you’re stating a general principle, I felt I should give my general counterargument.)

[Edit:] Several comments happened while I was writing, and I also see I wasn’t entirely clear. To be clear, what I’m asking for is that there should continue to be a from_env() function for each type-that-can-be-taken-from-environment, and it should continue to return Option<Self> (indicates whether the value was taken from environment) rather than Self (doesn't indicate).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re your edit: does this include compound cases (BackendOptions) or just single env-var cases?


```diff
- wgpu::util::backend_bits_from_env()
+ wgpu::Backends::from_env()

- wgpu::util::power_preference_from_env()
+ wgpu::PowerPreference::from_env()

- wgpu::util::dx12_shader_compiler_from_env()
+ wgpu::Dx12Compiler::from_env()

- wgpu::util::gles_minor_version_from_env()
+ wgpu::Gles3MinorVersion::from_env()

- wgpu::util::instance_descriptor_from_env()
+ wgpu::InstanceDescriptor::from_env()

- wgpu::util::parse_backends_from_comma_list(&str)
+ wgpu::Backends::from_comma_list(&str)
```

By @cwfitzgerald in [#6895](https://github.com/gfx-rs/wgpu/pull/6895)

#### Backend-specific instance options are now in separate structs

In order to better facilitate growing more interesting backend options, we have put them into individual structs. This allows users to more easily understand what options can be defaulted and which they care about. All of these new structs implement `from_env()` and delegate to their respective `from_env()` methods.

```diff
- let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
- backends: wgpu::Backends::all(),
- flags: wgpu::InstanceFlags::default(),
- dx12_shader_compiler: wgpu::Dx12Compiler::Dxc,
- gles_minor_version: wgpu::Gles3MinorVersion::Automatic,
- });
+ let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
+ backends: wgpu::Backends::all(),
+ flags: wgpu::InstanceFlags::default(),
+ backend_options: wgpu::BackendOptions {
+ dx12: wgpu::Dx12BackendOptions {
+ shader_compiler: wgpu::Dx12ShaderCompiler::Dxc,
+ },
+ gl: wgpu::GlBackendOptions {
+ gles_minor_version: wgpu::Gles3MinorVersion::Automatic,
+ },
Comment on lines +131 to +137
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

love it!

+ },
+ });
```

If you do not need any of these options, or only need one backend's info use the `default()` impl to fill out the remaining feelds.

By @cwfitzgerald in [#6895](https://github.com/gfx-rs/wgpu/pull/6895)

#### The `diagnostic(…);` directive is now supported in WGSL

Naga now parses `diagnostic(…);` directives according to the WGSL spec. This allows users to control certain lints, similar to Rust's `allow`, `warn`, and `deny` attributes. For example, in standard WGSL (but, notably, not Naga yet—see <https://github.com/gfx-rs/wgpu/issues/4369>) this snippet would emit a uniformity error:
Expand Down Expand Up @@ -125,18 +193,6 @@ There are some limitations to keep in mind with this new functionality:

By @ErichDonGubler in [#6456](https://github.com/gfx-rs/wgpu/pull/6456), [#6148](https://github.com/gfx-rs/wgpu/pull/6148), [#6533](https://github.com/gfx-rs/wgpu/pull/6533), [#6353](https://github.com/gfx-rs/wgpu/pull/6353), [#6537](https://github.com/gfx-rs/wgpu/pull/6537).

#### `wgpu::Instance::new` now takes `InstanceDescriptor` by reference

Previously `wgpu::Instance::new` took `InstanceDescriptor` by value (which is overall fairly uncommon in wgpu).
Furthermore, `InstanceDescriptor` is now cloneable.

```diff
- let instance = wgpu::Instance::new(instance_desc);
+ let instance = wgpu::Instance::new(&instance_desc);
```

By @wumpf in [#6849](https://github.com/gfx-rs/wgpu/pull/6849).

#### New Features

##### Naga
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

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

7 changes: 2 additions & 5 deletions benches/benches/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,8 @@ impl DeviceState {
};

let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
backends: wgpu::util::backend_bits_from_env().unwrap_or(base_backend),
flags: wgpu::InstanceFlags::empty(),
dx12_shader_compiler: wgpu::util::dx12_shader_compiler_from_env()
.unwrap_or(wgpu::Dx12Compiler::Fxc),
gles_minor_version: wgpu::Gles3MinorVersion::Automatic,
backends: wgpu::Backends::from_env().unwrap_or(base_backend),
..wgpu::InstanceDescriptor::from_env()
});

let adapter = block_on(wgpu::util::initialize_adapter_from_env_or_default(
Expand Down
12 changes: 9 additions & 3 deletions deno_webgpu/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ pub fn op_webgpu_request_adapter(

let backends = std::env::var("DENO_WEBGPU_BACKEND").map_or_else(
|_| wgpu_types::Backends::all(),
|s| wgpu_core::instance::parse_backends_from_comma_list(&s),
|s| wgpu_types::Backends::from_comma_list(&s),
);
let instance = if let Some(instance) = state.try_borrow::<Instance>() {
instance
Expand All @@ -391,8 +391,14 @@ pub fn op_webgpu_request_adapter(
&wgpu_types::InstanceDescriptor {
backends,
flags: wgpu_types::InstanceFlags::from_build_config(),
dx12_shader_compiler: wgpu_types::Dx12Compiler::Fxc,
gles_minor_version: wgpu_types::Gles3MinorVersion::default(),
backend_options: wgpu_types::BackendOptions {
dx12: wgpu_types::Dx12BackendOptions {
shader_compiler: wgpu_types::Dx12Compiler::Fxc,
},
gl: wgpu_types::GlBackendOptions {
gles_minor_version: wgpu_types::Gles3MinorVersion::default(),
},
},
},
)));
state.borrow::<Instance>()
Expand Down
2 changes: 1 addition & 1 deletion examples/src/framework.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ impl ExampleContext {
async fn init_async<E: Example>(surface: &mut SurfaceWrapper, window: Arc<Window>) -> Self {
log::info!("Initializing wgpu...");

let instance = wgpu::Instance::new(&wgpu::util::instance_descriptor_from_env());
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::from_env());
surface.pre_adapter(&instance, window);

let adapter = get_adapter_with_capabilities_or_from_env(
Expand Down
2 changes: 1 addition & 1 deletion examples/src/hello_triangle/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
size.width = size.width.max(1);
size.height = size.height.max(1);

let instance = wgpu::Instance::new(&wgpu::util::instance_descriptor_from_env());
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::from_env());

let surface = instance.create_surface(&window).unwrap();
let adapter = instance
Expand Down
8 changes: 1 addition & 7 deletions examples/src/timestamp_queries/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,7 @@ impl Queries {
#[cfg_attr(test, allow(unused))]
async fn run() {
// Instantiates instance of wgpu
let backends = wgpu::util::backend_bits_from_env().unwrap_or_default();
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
backends,
flags: wgpu::InstanceFlags::from_build_config().with_env(),
dx12_shader_compiler: wgpu::Dx12Compiler::default(),
gles_minor_version: wgpu::Gles3MinorVersion::default(),
});
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::from_env());

// `request_adapter` instantiates the general connection to the GPU
let adapter = instance
Expand Down
10 changes: 1 addition & 9 deletions player/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,15 +199,7 @@ impl Corpus {
for test_path in &corpus.tests {
println!("\t\tTest '{test_path:?}'");

let global = wgc::global::Global::new(
"test",
&wgt::InstanceDescriptor {
backends: backend.into(),
flags: wgt::InstanceFlags::debugging(),
dx12_shader_compiler: wgt::Dx12Compiler::Fxc,
gles_minor_version: wgt::Gles3MinorVersion::default(),
},
);
let global = wgc::global::Global::new("test", &wgt::InstanceDescriptor::from_env());
let adapter = match global.request_adapter(
&wgc::instance::RequestAdapterOptions {
power_preference: wgt::PowerPreference::None,
Expand Down
12 changes: 8 additions & 4 deletions tests/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,18 @@ pub fn initialize_instance(backends: wgpu::Backends, force_fxc: bool) -> Instanc
let dx12_shader_compiler = if force_fxc {
wgpu::Dx12Compiler::Fxc
} else {
wgpu::util::dx12_shader_compiler_from_env().unwrap_or(wgpu::Dx12Compiler::StaticDxc)
wgpu::Dx12Compiler::from_env().unwrap_or(wgpu::Dx12Compiler::StaticDxc)
};
let gles_minor_version = wgpu::util::gles_minor_version_from_env().unwrap_or_default();
let gles_minor_version = wgpu::Gles3MinorVersion::from_env().unwrap_or_default();
Instance::new(&wgpu::InstanceDescriptor {
backends,
flags: wgpu::InstanceFlags::debugging().with_env(),
dx12_shader_compiler,
gles_minor_version,
backend_options: wgpu::BackendOptions {
dx12: wgpu::Dx12BackendOptions {
shader_compiler: dx12_shader_compiler,
},
gl: wgpu::GlBackendOptions { gles_minor_version },
},
})
}

Expand Down
2 changes: 1 addition & 1 deletion tests/src/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ pub fn main() -> MainResult {
GpuReport::from_json(config_text).context("Could not parse .gpuconfig JSON")?;

// Filter out the adapters that are not part of WGPU_BACKEND.
let wgpu_backends = wgpu::util::backend_bits_from_env().unwrap_or(wgpu::Backends::all());
let wgpu_backends = wgpu::Backends::from_env().unwrap_or_default();
report
.devices
.retain(|report| wgpu_backends.contains(wgpu::Backends::from(report.info.backend)));
Expand Down
43 changes: 6 additions & 37 deletions wgpu-core/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,12 @@ impl Instance {
let hal_desc = hal::InstanceDescriptor {
name: "wgpu",
flags: instance_desc.flags,
dx12_shader_compiler: instance_desc.dx12_shader_compiler.clone(),
gles_minor_version: instance_desc.gles_minor_version,
dx12_shader_compiler: instance_desc
.backend_options
.dx12
.shader_compiler
.clone(),
gles_minor_version: instance_desc.backend_options.gl.gles_minor_version,
};

use hal::Instance as _;
Expand Down Expand Up @@ -969,38 +973,3 @@ impl Global {
Ok((device_id, queue_id))
}
}

/// Generates a set of backends from a comma separated list of case-insensitive backend names.
///
/// Whitespace is stripped, so both 'gl, dx12' and 'gl,dx12' are valid.
///
/// Always returns WEBGPU on wasm over webgpu.
///
/// Names:
/// - vulkan = "vulkan" or "vk"
/// - dx12 = "dx12" or "d3d12"
/// - metal = "metal" or "mtl"
/// - gles = "opengl" or "gles" or "gl"
/// - webgpu = "webgpu"
pub fn parse_backends_from_comma_list(string: &str) -> Backends {
let mut backends = Backends::empty();
for backend in string.to_lowercase().split(',') {
backends |= match backend.trim() {
"vulkan" | "vk" => Backends::VULKAN,
"dx12" | "d3d12" => Backends::DX12,
"metal" | "mtl" => Backends::METAL,
"opengl" | "gles" | "gl" => Backends::GL,
"webgpu" => Backends::BROWSER_WEBGPU,
b => {
log::warn!("unknown backend string '{}'", b);
continue;
}
}
}

if backends.is_empty() {
log::warn!("no valid backend strings found!");
}

backends
}
10 changes: 4 additions & 6 deletions wgpu-info/src/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@ pub struct GpuReport {

impl GpuReport {
pub fn generate() -> Self {
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
backends: wgpu::util::backend_bits_from_env().unwrap_or_default(),
flags: wgpu::InstanceFlags::debugging().with_env(),
dx12_shader_compiler: wgpu::util::dx12_shader_compiler_from_env()
.unwrap_or(wgpu::Dx12Compiler::StaticDxc),
gles_minor_version: wgpu::util::gles_minor_version_from_env().unwrap_or_default(),
let instance = wgpu::Instance::new(&{
let mut desc = wgpu::InstanceDescriptor::from_env();
desc.flags = wgpu::InstanceFlags::debugging().with_env();
desc
});
let adapters = instance.enumerate_adapters(wgpu::Backends::all());

Expand Down
1 change: 1 addition & 0 deletions wgpu-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(web_sys_unstable_apis)'] }

[dependencies]
bitflags = { workspace = true, features = ["serde"] }
log.workspace = true
serde = { workspace = true, features = ["derive"], optional = true }

[target.'cfg(target_arch = "wasm32")'.dependencies]
Expand Down
Loading
Loading