diff --git a/CHANGELOG.md b/CHANGELOG.md index 877f91aa318..d55bd8f9897 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. + +```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, ++ }, ++ }, ++ }); +``` + +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 ) this snippet would emit a uniformity error: @@ -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 diff --git a/Cargo.lock b/Cargo.lock index ddf8906da0b..55e75296282 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4191,6 +4191,7 @@ version = "23.0.0" dependencies = [ "bitflags 2.6.0", "js-sys", + "log", "serde", "serde_json", "web-sys", diff --git a/benches/benches/root.rs b/benches/benches/root.rs index 7d9f84e6b87..4cbec17e3b2 100644 --- a/benches/benches/root.rs +++ b/benches/benches/root.rs @@ -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( diff --git a/deno_webgpu/lib.rs b/deno_webgpu/lib.rs index 4bfb2470128..56c475cd8ff 100644 --- a/deno_webgpu/lib.rs +++ b/deno_webgpu/lib.rs @@ -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 @@ -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::() diff --git a/examples/src/framework.rs b/examples/src/framework.rs index 8f8aa89f902..9c6740feb8e 100644 --- a/examples/src/framework.rs +++ b/examples/src/framework.rs @@ -268,7 +268,7 @@ impl ExampleContext { async fn init_async(surface: &mut SurfaceWrapper, window: Arc) -> 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( diff --git a/examples/src/hello_triangle/mod.rs b/examples/src/hello_triangle/mod.rs index 3a0781518b4..e062023f3db 100644 --- a/examples/src/hello_triangle/mod.rs +++ b/examples/src/hello_triangle/mod.rs @@ -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 diff --git a/examples/src/timestamp_queries/mod.rs b/examples/src/timestamp_queries/mod.rs index 1a2841f7dc9..f1eaf00e9cf 100644 --- a/examples/src/timestamp_queries/mod.rs +++ b/examples/src/timestamp_queries/mod.rs @@ -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 diff --git a/player/tests/test.rs b/player/tests/test.rs index cc3106f20d6..50e5fd67350 100644 --- a/player/tests/test.rs +++ b/player/tests/test.rs @@ -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, diff --git a/tests/src/init.rs b/tests/src/init.rs index f710cfb7cb1..67b33c0f19b 100644 --- a/tests/src/init.rs +++ b/tests/src/init.rs @@ -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 }, + }, }) } diff --git a/tests/src/native.rs b/tests/src/native.rs index afad3d46dc4..eb12d22a5f9 100644 --- a/tests/src/native.rs +++ b/tests/src/native.rs @@ -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))); diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 34fdabb6378..8eca640d9db 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -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 _; @@ -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 -} diff --git a/wgpu-info/src/report.rs b/wgpu-info/src/report.rs index 3d7d257e458..b15d28e3f89 100644 --- a/wgpu-info/src/report.rs +++ b/wgpu-info/src/report.rs @@ -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()); diff --git a/wgpu-types/Cargo.toml b/wgpu-types/Cargo.toml index 5db7cf1f5f9..000439a655e 100644 --- a/wgpu-types/Cargo.toml +++ b/wgpu-types/Cargo.toml @@ -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] diff --git a/wgpu-types/src/instance.rs b/wgpu-types/src/instance.rs new file mode 100644 index 00000000000..7c4a87150a4 --- /dev/null +++ b/wgpu-types/src/instance.rs @@ -0,0 +1,330 @@ +//! Types for dealing with Instances + +use std::path::PathBuf; + +use crate::Backends; + +/// Options for creating an instance. +#[derive(Clone, Debug)] +pub struct InstanceDescriptor { + /// Which `Backends` to enable. + pub backends: Backends, + /// Flags to tune the behavior of the instance. + pub flags: InstanceFlags, + /// Options the control the behavior of various backends. + pub backend_options: BackendOptions, +} + +impl Default for InstanceDescriptor { + fn default() -> Self { + Self { + backends: Backends::all(), + flags: InstanceFlags::default(), + backend_options: BackendOptions::default(), + } + } +} + +impl InstanceDescriptor { + /// Choose instance options entirely from environment variables. + /// + /// This is equivalent to calling `from_env` on every field. + #[must_use] + pub fn from_env() -> Self { + let backends = Backends::from_env().unwrap_or_default(); + let flags = InstanceFlags::from_env(); + let backend_options = BackendOptions::from_env(); + Self { + backends, + flags, + backend_options, + } + } +} + +bitflags::bitflags! { + /// Instance debugging flags. + /// + /// These are not part of the webgpu standard. + /// + /// Defaults to enabling debugging-related flags if the build configuration has `debug_assertions`. + #[repr(transparent)] + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] + pub struct InstanceFlags: u32 { + /// Generate debug information in shaders and objects. + /// + /// When `Self::from_env()` is used takes value from `WGPU_DEBUG` environment variable. + const DEBUG = 1 << 0; + /// Enable validation, if possible. + /// + /// When `Self::from_env()` is used takes value from `WGPU_VALIDATION` environment variable. + const VALIDATION = 1 << 1; + /// Don't pass labels to wgpu-hal. + /// + /// When `Self::from_env()` is used takes value from `WGPU_DISCARD_HAL_LABELS` environment variable. + const DISCARD_HAL_LABELS = 1 << 2; + /// Whether wgpu should expose adapters that run on top of non-compliant adapters. + /// + /// Turning this on might mean that some of the functionality provided by the wgpu + /// adapter/device is not working or is broken. It could be that all the functionality + /// wgpu currently exposes works but we can't tell for sure since we have no additional + /// transparency into what is working and what is not on the underlying adapter. + /// + /// This mainly applies to a Vulkan driver's compliance version. If the major compliance version + /// is `0`, then the driver is ignored. This flag allows that driver to be enabled for testing. + /// + /// When `Self::from_env()` is used takes value from `WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER` environment variable. + const ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER = 1 << 3; + /// Enable GPU-based validation. Implies [`Self::VALIDATION`]. Currently, this only changes + /// behavior on the DX12 and Vulkan backends. + /// + /// Supported platforms: + /// + /// - D3D12; called ["GPU-based validation", or + /// "GBV"](https://web.archive.org/web/20230206120404/https://learn.microsoft.com/en-us/windows/win32/direct3d12/using-d3d12-debug-layer-gpu-based-validation) + /// - Vulkan, via the `VK_LAYER_KHRONOS_validation` layer; called ["GPU-Assisted + /// Validation"](https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/e45aeb85079e0835694cb8f03e6681fd18ae72c9/docs/gpu_validation.md#gpu-assisted-validation) + /// + /// When `Self::from_env()` is used takes value from `WGPU_GPU_BASED_VALIDATION` environment variable. + const GPU_BASED_VALIDATION = 1 << 4; + } +} + +impl Default for InstanceFlags { + fn default() -> Self { + Self::from_build_config() + } +} + +impl InstanceFlags { + /// Enable recommended debugging and validation flags. + #[must_use] + pub fn debugging() -> Self { + InstanceFlags::DEBUG | InstanceFlags::VALIDATION + } + + /// Enable advanced debugging and validation flags (potentially very slow). + #[must_use] + pub fn advanced_debugging() -> Self { + Self::debugging() | InstanceFlags::GPU_BASED_VALIDATION + } + + /// Infer decent defaults from the build type. + /// + /// If cfg!(debug_assertions) is true, then this returns [`Self::debugging()`]. + /// Otherwise, it returns [`Self::empty()`]. + #[must_use] + pub fn from_build_config() -> Self { + if cfg!(debug_assertions) { + return InstanceFlags::debugging(); + } + + InstanceFlags::empty() + } + + /// Derive defaults from environment variables. See [`Self::with_env()`] for more information. + #[must_use] + pub fn from_env() -> Self { + Self::default().with_env() + } + + /// Takes the given flags, modifies them based on the environment variables, and returns the result. + /// + /// - If an environment variable is set to anything but "0", the corresponding flag is set. + /// - If the value is "0", the flag is unset. + /// - If the environment variable is not present, then the flag retains its initial value. + /// + /// For example `let flags = InstanceFlags::debugging().with_env();` with `WGPU_VALIDATION=0` + /// does not contain `InstanceFlags::VALIDATION`. + /// + /// The environment variables are named after the flags prefixed with "WGPU_". For example: + /// - `WGPU_DEBUG` + /// - `WGPU_VALIDATION` + /// - `WGPU_DISCARD_HAL_LABELS` + /// - `WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER` + /// - `WGPU_GPU_BASED_VALIDATION` + #[must_use] + pub fn with_env(mut self) -> Self { + fn env(key: &str) -> Option { + std::env::var(key).ok().map(|s| match s.as_str() { + "0" => false, + _ => true, + }) + } + + if let Some(bit) = env("WGPU_VALIDATION") { + self.set(Self::VALIDATION, bit); + } + if let Some(bit) = env("WGPU_DEBUG") { + self.set(Self::DEBUG, bit); + } + if let Some(bit) = env("WGPU_DISCARD_HAL_LABELS") { + self.set(Self::DISCARD_HAL_LABELS, bit); + } + if let Some(bit) = env("WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER") { + self.set(Self::ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER, bit); + } + if let Some(bit) = env("WGPU_GPU_BASED_VALIDATION") { + self.set(Self::GPU_BASED_VALIDATION, bit); + } + + self + } +} + +/// Options that are passed to a given backend. +#[derive(Clone, Debug, Default)] +pub struct BackendOptions { + /// Options for the OpenGL/OpenGLES backend. + pub gl: GlBackendOptions, + /// Options for the DX12 backend. + pub dx12: Dx12BackendOptions, +} + +impl BackendOptions { + /// Choose backend options by calling `from_env` on every field. + /// + /// See those methods for more information. + #[must_use] + pub fn from_env() -> Self { + let gl = GlBackendOptions::from_env(); + let dx12 = Dx12BackendOptions::from_env(); + Self { gl, dx12 } + } +} + +/// Configuration for the OpenGL/OpenGLES backend. +#[derive(Clone, Debug, Default)] +pub struct GlBackendOptions { + /// Which OpenGL ES 3 minor version to request, if using OpenGL ES. + pub gles_minor_version: Gles3MinorVersion, +} + +impl GlBackendOptions { + /// Choose OpenGL backend options by calling `from_env` on every field. + /// + /// See those methods for more information. + #[must_use] + pub fn from_env() -> Self { + let gles_minor_version = Gles3MinorVersion::from_env().unwrap_or_default(); + Self { gles_minor_version } + } +} + +/// Configuration for the DX12 backend. +#[derive(Clone, Debug, Default)] +pub struct Dx12BackendOptions { + /// Which DX12 shader compiler to use. + pub shader_compiler: Dx12Compiler, +} + +impl Dx12BackendOptions { + /// Choose DX12 backend options by calling `from_env` on every field. + /// + /// See those methods for more information. + #[must_use] + pub fn from_env() -> Self { + let compiler = Dx12Compiler::from_env().unwrap_or_default(); + Self { + shader_compiler: compiler, + } + } +} + +/// Selects which DX12 shader compiler to use. +/// +/// If the `DynamicDxc` option is selected, but `dxcompiler.dll` and `dxil.dll` files aren't found, +/// then this will fall back to the Fxc compiler at runtime and log an error. +#[derive(Clone, Debug, Default)] +pub enum Dx12Compiler { + /// The Fxc compiler (default) is old, slow and unmaintained. + /// + /// However, it doesn't require any additional .dlls to be shipped with the application. + #[default] + Fxc, + /// The Dxc compiler is new, fast and maintained. + /// + /// However, it requires both `dxcompiler.dll` and `dxil.dll` to be shipped with the application. + /// These files can be downloaded from . + /// + /// Minimum supported version: [v1.5.2010](https://github.com/microsoft/DirectXShaderCompiler/releases/tag/v1.5.2010) + /// + /// It also requires WDDM 2.1 (Windows 10 version 1607). + DynamicDxc { + /// Path to `dxcompiler.dll`. + dxc_path: PathBuf, + /// Path to `dxil.dll`. + dxil_path: PathBuf, + }, + /// The statically-linked variant of Dxc. + /// + /// The `static-dxc` feature is required for this setting to be used successfully on DX12. + /// Not available on `windows-aarch64-pc-*` targets. + StaticDxc, +} + +impl Dx12Compiler { + /// Choose which DX12 shader compiler to use from the environment variable `WGPU_DX12_COMPILER`. + /// + /// Valid values, case insensitive: + /// - `Fxc` + /// - `Dxc` or `DynamicDxc` + /// - `StaticDxc` + #[must_use] + pub fn from_env() -> Option { + let value = std::env::var("WGPU_DX12_COMPILER") + .as_deref() + .ok()? + .to_lowercase(); + match value.as_str() { + "dxc" | "dynamicdxc" => Some(Self::DynamicDxc { + dxc_path: PathBuf::from("dxcompiler.dll"), + dxil_path: PathBuf::from("dxil.dll"), + }), + "staticdxc" => Some(Self::StaticDxc), + "fxc" => Some(Self::Fxc), + _ => None, + } + } +} + +/// Selects which OpenGL ES 3 minor version to request. +/// +/// When using ANGLE as an OpenGL ES/EGL implementation, explicitly requesting `Version1` can provide a non-conformant ES 3.1 on APIs like D3D11. +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)] +pub enum Gles3MinorVersion { + /// No explicit minor version is requested, the driver automatically picks the highest available. + #[default] + Automatic, + + /// Request an ES 3.0 context. + Version0, + + /// Request an ES 3.1 context. + Version1, + + /// Request an ES 3.2 context. + Version2, +} + +impl Gles3MinorVersion { + /// Choose which minor OpenGL ES version to use from the environment variable `WGPU_GLES_MINOR_VERSION`. + /// + /// Possible values are `0`, `1`, `2` or `automatic`. Case insensitive. + /// + /// Use with `unwrap_or_default()` to get the default value if the environment variable is not set. + #[must_use] + pub fn from_env() -> Option { + let value = std::env::var("WGPU_GLES_MINOR_VERSION") + .as_deref() + .ok()? + .to_lowercase(); + match value.as_str() { + "automatic" => Some(Self::Automatic), + "0" => Some(Self::Version0), + "1" => Some(Self::Version1), + "2" => Some(Self::Version2), + _ => None, + } + } +} diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index de3d1eceb55..d4f9dc375ee 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -14,14 +14,15 @@ use serde::Deserialize; use serde::Serialize; use std::hash::{Hash, Hasher}; use std::mem::size_of; -use std::path::PathBuf; use std::{num::NonZeroU32, ops::Range}; pub mod assertions; mod counters; +pub mod instance; pub mod math; pub use counters::*; +pub use instance::*; /// Integral type used for buffer offsets. pub type BufferAddress = u64; @@ -112,6 +113,19 @@ pub enum PowerPreference { HighPerformance = 2, } +impl PowerPreference { + /// Get a power preference from the environment variable `WGPU_POWER_PREF`. + pub fn from_env() -> Option { + let env = std::env::var("WGPU_POWER_PREF").ok()?; + match env.to_lowercase().as_str() { + "low" => Some(Self::LowPower), + "high" => Some(Self::HighPerformance), + "none" => Some(Self::None), + _ => None, + } + } +} + bitflags::bitflags! { /// Represents the backends that wgpu will use. #[repr(transparent)] @@ -165,6 +179,51 @@ impl From for Backends { } } +impl Backends { + /// Gets a set of backends from the environment variable `WGPU_BACKEND`. + /// + /// See [`Self::from_comma_list()`] for the format of the string. + pub fn from_env() -> Option { + let env = std::env::var("WGPU_BACKEND").ok()?; + Some(Self::from_comma_list(&env)) + } + + /// 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 from_comma_list(string: &str) -> Self { + let mut backends = Self::empty(); + for backend in string.to_lowercase().split(',') { + backends |= match backend.trim() { + "vulkan" | "vk" => Self::VULKAN, + "dx12" | "d3d12" => Self::DX12, + "metal" | "mtl" => Self::METAL, + "opengl" | "gles" | "gl" => Self::GL, + "webgpu" => Self::BROWSER_WEBGPU, + b => { + log::warn!("unknown backend string '{}'", b); + continue; + } + } + } + + if backends.is_empty() { + log::warn!("no valid backend strings found!"); + } + + backends + } +} + /// Options for requesting adapter. /// /// Corresponds to [WebGPU `GPURequestAdapterOptions`]( @@ -995,113 +1054,6 @@ impl Features { } } -bitflags::bitflags! { - /// Instance debugging flags. - /// - /// These are not part of the webgpu standard. - /// - /// Defaults to enabling debugging-related flags if the build configuration has `debug_assertions`. - #[repr(transparent)] - #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] - pub struct InstanceFlags: u32 { - /// Generate debug information in shaders and objects. - const DEBUG = 1 << 0; - /// Enable validation, if possible. - const VALIDATION = 1 << 1; - /// Don't pass labels to wgpu-hal. - const DISCARD_HAL_LABELS = 1 << 2; - /// Whether wgpu should expose adapters that run on top of non-compliant adapters. - /// - /// Turning this on might mean that some of the functionality provided by the wgpu - /// adapter/device is not working or is broken. It could be that all the functionality - /// wgpu currently exposes works but we can't tell for sure since we have no additional - /// transparency into what is working and what is not on the underlying adapter. - /// - /// This mainly applies to a Vulkan driver's compliance version. If the major compliance version - /// is `0`, then the driver is ignored. This flag allows that driver to be enabled for testing. - const ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER = 1 << 3; - /// Enable GPU-based validation. Implies [`Self::VALIDATION`]. Currently, this only changes - /// behavior on the DX12 and Vulkan backends. - /// - /// Supported platforms: - /// - /// - D3D12; called ["GPU-based validation", or - /// "GBV"](https://web.archive.org/web/20230206120404/https://learn.microsoft.com/en-us/windows/win32/direct3d12/using-d3d12-debug-layer-gpu-based-validation) - /// - Vulkan, via the `VK_LAYER_KHRONOS_validation` layer; called ["GPU-Assisted - /// Validation"](https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/e45aeb85079e0835694cb8f03e6681fd18ae72c9/docs/gpu_validation.md#gpu-assisted-validation) - const GPU_BASED_VALIDATION = 1 << 4; - } -} - -impl Default for InstanceFlags { - fn default() -> Self { - Self::from_build_config() - } -} - -impl InstanceFlags { - /// Enable recommended debugging and validation flags. - #[must_use] - pub fn debugging() -> Self { - InstanceFlags::DEBUG | InstanceFlags::VALIDATION - } - - /// Enable advanced debugging and validation flags (potentially very slow). - #[must_use] - pub fn advanced_debugging() -> Self { - Self::debugging() | InstanceFlags::GPU_BASED_VALIDATION - } - - /// Infer good defaults from the build type - /// - /// Returns the default flags and add debugging flags if the build configuration has `debug_assertions`. - #[must_use] - pub fn from_build_config() -> Self { - if cfg!(debug_assertions) { - return InstanceFlags::debugging(); - } - - InstanceFlags::empty() - } - - /// Returns this set of flags, affected by environment variables. - /// - /// The presence of an environment variable implies that the corresponding flag should be set - /// unless the value is "0" in which case the flag is unset. If the environment variable is - /// not present, then the flag is unaffected. - /// - /// For example `let flags = InstanceFlags::debugging().with_env();` with `WGPU_VALIDATION=0` - /// does not contain `InstanceFlags::VALIDATION`. - /// - /// The environment variables are named after the flags prefixed with "WGPU_". For example: - /// - WGPU_DEBUG - /// - WGPU_VALIDATION - #[must_use] - pub fn with_env(mut self) -> Self { - fn env(key: &str) -> Option { - std::env::var(key).ok().map(|s| match s.as_str() { - "0" => false, - _ => true, - }) - } - - if let Some(bit) = env("WGPU_VALIDATION") { - self.set(Self::VALIDATION, bit); - } - if let Some(bit) = env("WGPU_DEBUG") { - self.set(Self::DEBUG, bit); - } - if let Some(bit) = env("WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER") { - self.set(Self::ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER, bit); - } - if let Some(bit) = env("WGPU_GPU_BASED_VALIDATION") { - self.set(Self::GPU_BASED_VALIDATION, bit); - } - - self - } -} - /// Represents the sets of limits an adapter/device supports. /// /// We provide three different defaults. @@ -7681,84 +7633,6 @@ impl Default for ShaderRuntimeChecks { } } -/// Selects which DX12 shader compiler to use. -/// -/// If the `Dxc` option is selected, but `dxcompiler.dll` and `dxil.dll` files aren't found, -/// then this will fall back to the Fxc compiler at runtime and log an error. -/// -/// `wgpu::utils::init::dx12_shader_compiler_from_env` can be used to set the compiler -/// from the `WGPU_DX12_SHADER_COMPILER` environment variable, but this should only be used for testing. -#[derive(Clone, Debug, Default)] -pub enum Dx12Compiler { - /// The Fxc compiler (default) is old, slow and unmaintained. - /// - /// However, it doesn't require any additional .dlls to be shipped with the application. - #[default] - Fxc, - /// The Dxc compiler is new, fast and maintained. - /// - /// However, it requires both `dxcompiler.dll` and `dxil.dll` to be shipped with the application. - /// These files can be downloaded from . - /// - /// Minimum supported version: [v1.5.2010](https://github.com/microsoft/DirectXShaderCompiler/releases/tag/v1.5.2010) - /// - /// It also requires WDDM 2.1 (Windows 10 version 1607). - DynamicDxc { - /// Path to `dxcompiler.dll`. - dxc_path: PathBuf, - /// Path to `dxil.dll`. - dxil_path: PathBuf, - }, - /// The statically-linked variant of Dxc. - /// - /// The `static-dxc` feature is required for this setting to be used successfully on DX12. - /// Not available on `windows-aarch64-pc-*` targets. - StaticDxc, -} - -/// Selects which OpenGL ES 3 minor version to request. -/// -/// When using ANGLE as an OpenGL ES/EGL implementation, explicitly requesting `Version1` can provide a non-conformant ES 3.1 on APIs like D3D11. -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)] -pub enum Gles3MinorVersion { - /// No explicit minor version is requested, the driver automatically picks the highest available. - #[default] - Automatic, - - /// Request an ES 3.0 context. - Version0, - - /// Request an ES 3.1 context. - Version1, - - /// Request an ES 3.2 context. - Version2, -} - -/// Options for creating an instance. -#[derive(Clone, Debug)] -pub struct InstanceDescriptor { - /// Which `Backends` to enable. - pub backends: Backends, - /// Flags to tune the behavior of the instance. - pub flags: InstanceFlags, - /// Which DX12 shader compiler to use. - pub dx12_shader_compiler: Dx12Compiler, - /// Which OpenGL ES 3 minor version to request. Will be ignored if OpenGL is available. - pub gles_minor_version: Gles3MinorVersion, -} - -impl Default for InstanceDescriptor { - fn default() -> Self { - Self { - backends: Backends::all(), - flags: InstanceFlags::default(), - dx12_shader_compiler: Dx12Compiler::default(), - gles_minor_version: Gles3MinorVersion::default(), - } - } -} - #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] /// Descriptor for all size defining attributes of a single triangle geometry inside a bottom level acceleration structure. diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 56813441ed0..18bf801f7ec 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -46,20 +46,20 @@ pub mod util; pub use api::*; pub use wgt::{ - AdapterInfo, AddressMode, AstcBlock, AstcChannel, Backend, Backends, BindGroupLayoutEntry, - BindingType, BlendComponent, BlendFactor, BlendOperation, BlendState, BufferAddress, - BufferBindingType, BufferSize, BufferUsages, Color, ColorTargetState, ColorWrites, - CommandBufferDescriptor, CompareFunction, CompositeAlphaMode, CoreCounters, DepthBiasState, - DepthStencilState, DeviceLostReason, DeviceType, DownlevelCapabilities, DownlevelFlags, - Dx12Compiler, DynamicOffset, Extent3d, Face, Features, FilterMode, FrontFace, - Gles3MinorVersion, HalCounters, ImageSubresourceRange, IndexFormat, InstanceDescriptor, - InstanceFlags, InternalCounters, Limits, MaintainResult, MemoryHints, MultisampleState, - Origin2d, Origin3d, PipelineStatisticsTypes, PolygonMode, PowerPreference, - PredefinedColorSpace, PresentMode, PresentationTimestamp, PrimitiveState, PrimitiveTopology, - PushConstantRange, QueryType, RenderBundleDepthStencil, SamplerBindingType, SamplerBorderColor, - ShaderLocation, ShaderModel, ShaderRuntimeChecks, ShaderStages, StencilFaceState, - StencilOperation, StencilState, StorageTextureAccess, SurfaceCapabilities, SurfaceStatus, - TexelCopyBufferLayout, TextureAspect, TextureDimension, TextureFormat, + AdapterInfo, AddressMode, AstcBlock, AstcChannel, Backend, BackendOptions, Backends, + BindGroupLayoutEntry, BindingType, BlendComponent, BlendFactor, BlendOperation, BlendState, + BufferAddress, BufferBindingType, BufferSize, BufferUsages, Color, ColorTargetState, + ColorWrites, CommandBufferDescriptor, CompareFunction, CompositeAlphaMode, CoreCounters, + DepthBiasState, DepthStencilState, DeviceLostReason, DeviceType, DownlevelCapabilities, + DownlevelFlags, Dx12BackendOptions, Dx12Compiler, DynamicOffset, Extent3d, Face, Features, + FilterMode, FrontFace, GlBackendOptions, Gles3MinorVersion, HalCounters, ImageSubresourceRange, + IndexFormat, InstanceDescriptor, InstanceFlags, InternalCounters, Limits, MaintainResult, + MemoryHints, MultisampleState, Origin2d, Origin3d, PipelineStatisticsTypes, PolygonMode, + PowerPreference, PredefinedColorSpace, PresentMode, PresentationTimestamp, PrimitiveState, + PrimitiveTopology, PushConstantRange, QueryType, RenderBundleDepthStencil, SamplerBindingType, + SamplerBorderColor, ShaderLocation, ShaderModel, ShaderRuntimeChecks, ShaderStages, + StencilFaceState, StencilOperation, StencilState, StorageTextureAccess, SurfaceCapabilities, + SurfaceStatus, TexelCopyBufferLayout, TextureAspect, TextureDimension, TextureFormat, TextureFormatFeatureFlags, TextureFormatFeatures, TextureSampleType, TextureUsages, TextureViewDimension, VertexAttribute, VertexFormat, VertexStepMode, WasmNotSend, WasmNotSendSync, WasmNotSync, COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, diff --git a/wgpu/src/util/init.rs b/wgpu/src/util/init.rs index cdb700aaf6b..36acc5dfdf9 100644 --- a/wgpu/src/util/init.rs +++ b/wgpu/src/util/init.rs @@ -1,41 +1,4 @@ -use wgt::{Backends, PowerPreference, RequestAdapterOptions}; - -use crate::{Adapter, Instance, Surface}; - -#[cfg(wgpu_core)] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub use wgc::instance::parse_backends_from_comma_list; -/// Just return ALL, if wgpu_core is not enabled. -#[cfg(not(wgpu_core))] -pub fn parse_backends_from_comma_list(_string: &str) -> Backends { - Backends::all() -} - -/// Get a set of backend bits from the environment variable WGPU_BACKEND. -pub fn backend_bits_from_env() -> Option { - std::env::var("WGPU_BACKEND") - .as_deref() - .map(str::to_lowercase) - .ok() - .as_deref() - .map(parse_backends_from_comma_list) -} - -/// Get a power preference from the environment variable WGPU_POWER_PREF -pub fn power_preference_from_env() -> Option { - Some( - match std::env::var("WGPU_POWER_PREF") - .as_deref() - .map(str::to_lowercase) - .as_deref() - { - Ok("low") => PowerPreference::LowPower, - Ok("high") => PowerPreference::HighPerformance, - Ok("none") => PowerPreference::None, - _ => return None, - }, - ) -} +use crate::{Adapter, Instance, RequestAdapterOptions, Surface}; /// Initialize the adapter obeying the WGPU_ADAPTER_NAME environment variable. #[cfg(native)] @@ -48,7 +11,7 @@ pub fn initialize_adapter_from_env( .map(str::to_lowercase) .ok()?; - let adapters = instance.enumerate_adapters(Backends::all()); + let adapters = instance.enumerate_adapters(wgpu::Backends::all()); let mut chosen_adapter = None; for adapter in adapters { @@ -88,7 +51,7 @@ pub async fn initialize_adapter_from_env_or_default( None => { instance .request_adapter(&RequestAdapterOptions { - power_preference: power_preference_from_env().unwrap_or_default(), + power_preference: crate::PowerPreference::from_env().unwrap_or_default(), force_fallback_adapter: false, compatible_surface, }) @@ -97,65 +60,6 @@ pub async fn initialize_adapter_from_env_or_default( } } -/// Choose which DX12 shader compiler to use from the environment variable `WGPU_DX12_COMPILER`. -/// -/// Possible values are `dxc` and `fxc`. Case insensitive. -pub fn dx12_shader_compiler_from_env() -> Option { - Some( - match std::env::var("WGPU_DX12_COMPILER") - .as_deref() - .map(str::to_lowercase) - .as_deref() - { - Ok("dxc") => wgt::Dx12Compiler::DynamicDxc { - dxc_path: std::path::PathBuf::from("dxcompiler.dll"), - dxil_path: std::path::PathBuf::from("dxil.dll"), - }, - #[cfg(static_dxc)] - Ok("static-dxc") => wgt::Dx12Compiler::StaticDxc, - Ok("fxc") => wgt::Dx12Compiler::Fxc, - _ => return None, - }, - ) -} - -/// Choose which minor OpenGL ES version to use from the environment variable `WGPU_GLES_MINOR_VERSION`. -/// -/// Possible values are `0`, `1`, `2` or `automatic`. Case insensitive. -pub fn gles_minor_version_from_env() -> Option { - Some( - match std::env::var("WGPU_GLES_MINOR_VERSION") - .as_deref() - .map(str::to_lowercase) - .as_deref() - { - Ok("automatic") => wgt::Gles3MinorVersion::Automatic, - Ok("0") => wgt::Gles3MinorVersion::Version0, - Ok("1") => wgt::Gles3MinorVersion::Version1, - Ok("2") => wgt::Gles3MinorVersion::Version2, - _ => return None, - }, - ) -} - -/// Get an instance descriptor from the following environment variables: -/// -/// - WGPU_BACKEND -/// - WGPU_DEBUG -/// - WGPU_VALIDATION -/// - WGPU_DX12_COMPILER -/// - WGPU_GLES_MINOR_VERSION -/// -/// If variables are missing, falls back to default or build config values -pub fn instance_descriptor_from_env() -> wgt::InstanceDescriptor { - wgt::InstanceDescriptor { - backends: backend_bits_from_env().unwrap_or_default(), - flags: wgt::InstanceFlags::from_build_config().with_env(), - dx12_shader_compiler: dx12_shader_compiler_from_env().unwrap_or_default(), - gles_minor_version: gles_minor_version_from_env().unwrap_or_default(), - } -} - /// Determines whether the [`Backends::BROWSER_WEBGPU`] backend is supported. /// /// The result can only be true if this is called from the main thread or a dedicated worker.