wgpu_types/
backend.rs

1//! [`Backend`], [`Backends`], and backend-specific options.
2
3use alloc::string::{String, ToString};
4use core::{hash::Hash, str::FromStr};
5
6use macro_rules_attribute::derive;
7
8#[cfg(any(feature = "serde", test))]
9use serde::{Deserialize, Serialize};
10
11use crate::{link_to_wgpu_docs, ConstDefault};
12
13#[cfg(doc)]
14use crate::InstanceDescriptor;
15
16/// Backends supported by wgpu.
17///
18/// See also [`Backends`].
19#[repr(u8)]
20#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub enum Backend {
23    /// Dummy backend, which may be used for testing.
24    ///
25    /// It performs no rendering or computation, but allows creation of stub GPU resource types,
26    /// so that code which manages GPU resources can be tested without an available GPU.
27    /// Specifically, the following operations are implemented:
28    ///
29    /// * Enumerating adapters will always return one noop adapter, which can be used to create
30    ///   devices.
31    /// * Buffers may be created, written, mapped, and copied to other buffers.
32    /// * Command encoders may be created, but only buffer operations are useful.
33    ///
34    /// Other resources can be created but are nonfunctional; notably,
35    ///
36    /// * Render passes and compute passes are not executed.
37    /// * Textures may be created, but do not store any texels.
38    /// * There are no compatible surfaces.
39    ///
40    /// An adapter using the noop backend can only be obtained if [`NoopBackendOptions`]
41    /// enables it, in addition to the ordinary requirement of [`Backends::NOOP`] being set.
42    /// This ensures that applications not desiring a non-functional backend will not receive it.
43    Noop = 0,
44
45    /// Vulkan API (Windows, Linux, Android, MacOS via `vulkan-portability`/MoltenVK)
46    Vulkan = 1,
47
48    /// Metal API (Apple platforms)
49    Metal = 2,
50
51    /// Direct3D-12 (Windows)
52    Dx12 = 3,
53
54    /// OpenGL 3.3+, OpenGL ES 3.0+, WebGL2.
55    ///
56    /// - On Windows, this is normally OpenGL. If you build with
57    ///   `cfg(windows_angle)` to use ANGLE instead, then this is OpenGL ES.
58    ///
59    /// - On Linux, we create a full OpenGL context if possible (Mesa offers
60    ///   it), but if that fails we fall back to OpenGL ES.
61    ///
62    /// - On Android and macOS with ANGLE, we get OpenGL ES.
63    ///
64    /// - When running in a web browser, we get WebGL2.
65    Gl = 4,
66
67    /// WebGPU in the browser
68    BrowserWebGpu = 5,
69}
70
71impl Backend {
72    /// Array of all [`Backend`] values, corresponding to [`Backends::all()`].
73    pub const ALL: [Backend; Backends::all().bits().count_ones() as usize] = [
74        Self::Noop,
75        Self::Vulkan,
76        Self::Metal,
77        Self::Dx12,
78        Self::Gl,
79        Self::BrowserWebGpu,
80    ];
81
82    /// Returns the string name of the backend.
83    #[must_use]
84    pub const fn to_str(self) -> &'static str {
85        match self {
86            Backend::Noop => "noop",
87            Backend::Vulkan => "vulkan",
88            Backend::Metal => "metal",
89            Backend::Dx12 => "dx12",
90            Backend::Gl => "gl",
91            Backend::BrowserWebGpu => "webgpu",
92        }
93    }
94}
95
96impl core::fmt::Display for Backend {
97    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
98        f.write_str(self.to_str())
99    }
100}
101
102bitflags::bitflags! {
103    /// Represents the backends that wgpu will use.
104    #[repr(transparent)]
105    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
106    #[cfg_attr(feature = "serde", serde(transparent))]
107    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
108    pub struct Backends: u32 {
109        /// [`Backend::Noop`].
110        const NOOP = 1 << Backend::Noop as u32;
111
112        /// [`Backend::Vulkan`].
113        /// Supported on Windows, Linux/Android, and macOS/iOS via Vulkan Portability (with the Vulkan feature enabled)
114        const VULKAN = 1 << Backend::Vulkan as u32;
115
116        /// [`Backend::Gl`].
117        /// Supported on Linux/Android, the web through webassembly via WebGL, and
118        /// Windows through native OpenGL by default or ANGLE with `cfg(windows_angle)`.
119        const GL = 1 << Backend::Gl as u32;
120
121        /// [`Backend::Metal`].
122        /// Supported on macOS and iOS.
123        const METAL = 1 << Backend::Metal as u32;
124
125        /// [`Backend::Dx12`].
126        /// Supported on Windows 10 and later
127        const DX12 = 1 << Backend::Dx12 as u32;
128
129        /// [`Backend::BrowserWebGpu`].
130        /// Supported when targeting the web through WebAssembly with the `webgpu` feature enabled.
131        ///
132        /// The WebGPU backend is special in several ways:
133        /// It is not not implemented by `wgpu_core` and instead by the higher level `wgpu` crate.
134        /// Whether WebGPU is targeted is decided upon the creation of the `wgpu::Instance`,
135        /// *not* upon adapter creation. See `wgpu::Instance::new`.
136        const BROWSER_WEBGPU = 1 << Backend::BrowserWebGpu as u32;
137
138        /// All the apis that wgpu offers first tier of support for.
139        ///
140        /// * [`Backends::VULKAN`]
141        /// * [`Backends::METAL`]
142        /// * [`Backends::DX12`]
143        /// * [`Backends::BROWSER_WEBGPU`]
144        const PRIMARY = Self::VULKAN.bits()
145            | Self::METAL.bits()
146            | Self::DX12.bits()
147            | Self::BROWSER_WEBGPU.bits();
148
149        /// All the apis that wgpu offers second tier of support for. These may
150        /// be unsupported/still experimental.
151        ///
152        /// * [`Backends::GL`]
153        const SECONDARY = Self::GL.bits();
154    }
155}
156
157impl Default for Backends {
158    fn default() -> Self {
159        Self::all()
160    }
161}
162
163impl From<Backend> for Backends {
164    fn from(backend: Backend) -> Self {
165        Self::from_bits(1 << backend as u32).unwrap()
166    }
167}
168
169impl Backends {
170    /// Gets a set of backends from the environment variable `WGPU_BACKEND`.
171    ///
172    /// See [`Self::from_comma_list()`] for the format of the string.
173    pub fn from_env() -> Option<Self> {
174        let env = crate::env::var("WGPU_BACKEND")?;
175        Some(Self::from_comma_list(&env))
176    }
177
178    /// Takes the given options, modifies them based on the `WGPU_BACKEND` environment variable, and returns the result.
179    pub fn with_env(&self) -> Self {
180        if let Some(env) = Self::from_env() {
181            env
182        } else {
183            *self
184        }
185    }
186
187    /// Generates a set of backends from a comma separated list of case-insensitive backend names.
188    ///
189    /// Whitespace is stripped, so both 'gl, dx12' and 'gl,dx12' are valid.
190    ///
191    /// Always returns WEBGPU on wasm over webgpu.
192    ///
193    /// Names:
194    /// - vulkan = "vulkan" or "vk"
195    /// - dx12   = "dx12" or "d3d12"
196    /// - metal  = "metal" or "mtl"
197    /// - gles   = "opengl" or "gles" or "gl"
198    /// - webgpu = "webgpu"
199    pub fn from_comma_list(string: &str) -> Self {
200        let mut backends = Self::empty();
201        for backend in string.to_lowercase().split(',') {
202            backends |= match backend.trim() {
203                "vulkan" | "vk" => Self::VULKAN,
204                "dx12" | "d3d12" => Self::DX12,
205                "metal" | "mtl" => Self::METAL,
206                "opengl" | "gles" | "gl" => Self::GL,
207                "webgpu" => Self::BROWSER_WEBGPU,
208                "noop" => Self::NOOP,
209                b => {
210                    log::warn!("unknown backend string '{b}'");
211                    continue;
212                }
213            }
214        }
215
216        if backends.is_empty() {
217            log::warn!("no valid backend strings found!");
218        }
219
220        backends
221    }
222}
223
224/// Options that are passed to a given backend.
225///
226/// Part of [`InstanceDescriptor`].
227#[derive(Clone, Debug, Eq, PartialEq, ConstDefault!)]
228pub struct BackendOptions {
229    /// Options for the OpenGL/OpenGLES backend, [`Backend::Gl`].
230    pub gl: GlBackendOptions,
231    /// Options for the DX12 backend, [`Backend::Dx12`].
232    pub dx12: Dx12BackendOptions,
233    /// Options for the noop backend, [`Backend::Noop`].
234    pub noop: NoopBackendOptions,
235}
236
237impl BackendOptions {
238    /// Choose backend options by calling `from_env` on every field.
239    ///
240    /// See those methods for more information.
241    #[must_use]
242    pub fn from_env_or_default() -> Self {
243        Self {
244            gl: GlBackendOptions::from_env_or_default(),
245            dx12: Dx12BackendOptions::from_env_or_default(),
246            noop: NoopBackendOptions::from_env_or_default(),
247        }
248    }
249
250    /// Takes the given options, modifies them based on the environment variables, and returns the result.
251    ///
252    /// This is equivalent to calling `with_env` on every field.
253    #[must_use]
254    pub fn with_env(self) -> Self {
255        Self {
256            gl: self.gl.with_env(),
257            dx12: self.dx12.with_env(),
258            noop: self.noop.with_env(),
259        }
260    }
261}
262
263/// Configuration for the OpenGL/OpenGLES backend.
264///
265/// Part of [`BackendOptions`].
266#[derive(Clone, Debug, Eq, PartialEq, ConstDefault!)]
267pub struct GlBackendOptions {
268    /// Which OpenGL ES 3 minor version to request, if using OpenGL ES.
269    pub gles_minor_version: Gles3MinorVersion,
270    /// Behavior of OpenGL fences. Affects how `on_completed_work_done` and `device.poll` behave.
271    pub fence_behavior: GlFenceBehavior,
272    /// Controls whether debug functions (`glPushDebugGroup`, `glPopDebugGroup`,
273    /// `glObjectLabel`, etc.) are enabled when supported by the driver.
274    ///
275    /// By default ([`GlDebugFns::Auto`]), debug functions are automatically
276    /// disabled on devices with known bugs (e.g., Mali GPUs can crash in
277    /// `glPushDebugGroup`). Use [`GlDebugFns::ForceEnabled`] to override this
278    /// behavior, or [`GlDebugFns::Disabled`] to disable debug functions entirely.
279    ///
280    /// See also [`InstanceFlags::DISCARD_HAL_LABELS`], which prevents debug
281    /// markers and labels from being sent to *any* backend, but without the
282    /// driver-specific bug workarounds provided here.
283    ///
284    /// [`InstanceFlags::DISCARD_HAL_LABELS`]: crate::InstanceFlags::DISCARD_HAL_LABELS
285    pub debug_fns: GlDebugFns,
286}
287
288impl GlBackendOptions {
289    /// Choose OpenGL backend options by calling `from_env` on every field.
290    ///
291    /// See those methods for more information.
292    #[must_use]
293    pub fn from_env_or_default() -> Self {
294        let gles_minor_version = Gles3MinorVersion::from_env().unwrap_or_default();
295        let debug_fns = GlDebugFns::from_env().unwrap_or_default();
296        Self {
297            gles_minor_version,
298            fence_behavior: GlFenceBehavior::Normal,
299            debug_fns,
300        }
301    }
302
303    /// Takes the given options, modifies them based on the environment variables, and returns the result.
304    ///
305    /// This is equivalent to calling `with_env` on every field.
306    #[must_use]
307    pub fn with_env(self) -> Self {
308        let gles_minor_version = self.gles_minor_version.with_env();
309        let fence_behavior = self.fence_behavior.with_env();
310        let debug_fns = self.debug_fns.with_env();
311        Self {
312            gles_minor_version,
313            fence_behavior,
314            debug_fns,
315        }
316    }
317}
318
319/// Controls whether OpenGL debug functions are enabled.
320///
321/// Debug functions include `glPushDebugGroup`, `glPopDebugGroup`, `glObjectLabel`, etc.
322/// These are useful for debugging but can cause crashes on some buggy drivers.
323#[derive(Clone, Copy, Debug, PartialEq, Eq, ConstDefault!)]
324pub enum GlDebugFns {
325    /// Automatically decide whether to enable debug functions.
326    ///
327    /// Debug functions will be enabled if supported by the driver, unless
328    /// running on a device known to have buggy debug function implementations
329    /// (e.g., Mali GPUs which can crash in `glPushDebugGroup`).
330    ///
331    /// This is the default behavior.
332    #[custom(default)]
333    Auto,
334    /// Force enable debug functions if supported by the driver.
335    ///
336    /// This ignores any device-specific workarounds and enables debug functions
337    /// on all devices that support them, including those with known bugs.
338    ForceEnabled,
339    /// Disable debug functions entirely.
340    ///
341    /// Debug functions will not be used even if supported by the driver.
342    Disabled,
343}
344
345impl GlDebugFns {
346    /// Choose debug functions setting from the environment variable `WGPU_GL_DEBUG_FNS`.
347    ///
348    /// Possible values (case insensitive):
349    /// - `auto` - automatically decide based on device
350    /// - `forceenabled`, `force_enabled`, or `enabled` - force enable
351    /// - `disabled` - disable entirely
352    ///
353    /// Use with `unwrap_or_default()` to get the default value if the environment variable is not set.
354    #[must_use]
355    pub fn from_env() -> Option<Self> {
356        let value = crate::env::var("WGPU_GL_DEBUG_FNS")
357            .as_deref()?
358            .to_lowercase();
359        match value.as_str() {
360            "auto" => Some(Self::Auto),
361            "forceenabled" | "force_enabled" | "enabled" => Some(Self::ForceEnabled),
362            "disabled" => Some(Self::Disabled),
363            _ => None,
364        }
365    }
366
367    /// Takes the given setting, modifies it based on the `WGPU_GL_DEBUG_FNS` environment variable, and returns the result.
368    ///
369    /// See `from_env` for more information.
370    #[must_use]
371    pub fn with_env(self) -> Self {
372        if let Some(debug_fns) = Self::from_env() {
373            debug_fns
374        } else {
375            self
376        }
377    }
378}
379
380/// Used to force wgpu to expose certain features on passthrough shaders even when
381/// those features aren't present on runtime-compiled shaders
382#[derive(Clone, Debug, Eq, PartialEq, ConstDefault!)]
383pub struct ForceShaderModelToken {
384    inner: Option<DxcShaderModel>,
385}
386impl ForceShaderModelToken {
387    /// Creates an unsafe token, opting you in to seeing features that you may not necessarily use
388    /// on standard runtime-compiled shaders.
389    /// # Safety
390    /// Do not make use in runtime-compiled shaders of any features that may not be supported by the FXC or DXC
391    /// version you use.
392    pub const unsafe fn with_shader_model(sm: DxcShaderModel) -> Self {
393        Self { inner: Some(sm) }
394    }
395
396    /// Returns the shader model version, if any, in this token.
397    pub const fn get(&self) -> Option<DxcShaderModel> {
398        self.inner
399    }
400}
401
402/// Behavior when the Agility SDK fails to load.
403///
404/// See [`Dx12AgilitySDK`] for details on the Agility SDK.
405#[derive(Clone, Copy, Debug, ConstDefault!, PartialEq, Eq)]
406pub enum Dx12AgilitySDKLoadFailure {
407    /// Log a warning and fall back to the system-installed D3D12 runtime.
408    ///
409    /// This is the default behavior and is appropriate for most applications.
410    #[custom(default)]
411    Fallback,
412    /// Fail instance creation entirely if the Agility SDK cannot be loaded.
413    ///
414    /// Use this in environments where you are shipping the Agility SDK alongside your application
415    /// and want to ensure that it is being loaded correctly.
416    Error,
417}
418
419impl Dx12AgilitySDKLoadFailure {
420    /// Read the load failure behavior from the environment variable
421    /// `WGPU_DX12_AGILITY_SDK_REQUIRE`.
422    ///
423    /// When set to `1`, returns [`Error`](Self::Error).
424    /// When set to `0`, returns [`Fallback`](Self::Fallback).
425    #[must_use]
426    pub fn from_env() -> Option<Self> {
427        let value = crate::env::var("WGPU_DX12_AGILITY_SDK_REQUIRE")?;
428        match value.as_str() {
429            "1" => Some(Self::Error),
430            "0" => Some(Self::Fallback),
431            _ => None,
432        }
433    }
434
435    /// Takes the given setting, modifies it based on the
436    /// `WGPU_DX12_AGILITY_SDK_REQUIRE` environment variable, and returns the result.
437    ///
438    /// See [`from_env`](Self::from_env) for more information.
439    #[must_use]
440    pub fn with_env(self) -> Self {
441        if let Some(v) = Self::from_env() {
442            v
443        } else {
444            self
445        }
446    }
447}
448
449/// Configuration for loading a specific [DirectX 12 Agility SDK] runtime.
450///
451/// The Agility SDK allows applications to ship a newer version of the D3D12 runtime
452/// (`D3D12Core.dll`) alongside the application, enabling access to the latest D3D12
453/// features without waiting for the OS to update its built-in runtime. This is the
454/// standard way for games and applications to adopt new D3D12 functionality on older
455/// Windows versions.
456///
457/// Downloads and release notes are available at the [DirectX 12 Agility SDK] page.
458///
459/// wgpu loads the Agility SDK via the [Independent Devices API], which allows
460/// specifying the SDK path and version at runtime without requiring exported constants
461/// or developer mode. The [`sdk_version`](Self::sdk_version) must match the version of
462/// the `D3D12Core.dll` in the provided path exactly, or loading will fail, irrespective of
463/// the OS's built-in runtime version.
464///
465/// If the shipped SDK is older than the system runtime, the system runtime will be used.
466/// This allows applications to ship a minimum SDK version while still benefiting from SDK updates on the user's system.
467///
468/// If the Agility SDK fails to load (version mismatch, missing DLL, unsupported OS,
469/// etc.), the behavior is controlled by [`on_load_failure`](Self::on_load_failure).
470/// By default, wgpu logs a warning and falls back to the system-installed D3D12 runtime.
471/// Set it to [`Error`](Dx12AgilitySDKLoadFailure::Error) to fail instance creation instead
472/// (useful in CI/testing).
473///
474/// ## OS requirements
475///
476/// The Independent Devices API requires a Windows update from August/September 2023
477/// or newer:
478///
479/// - [Windows 11 21H2+ (KB5029332)][win11-21h2]
480/// - [Windows 10 22H2+ (KB5029331)][win10-22h2]
481/// - [Windows Server 2022+ (KB5030216)][server-2022]
482///
483/// On older OS builds the Agility SDK will not load and wgpu will log a warning and
484/// fall back to the system runtime (or error, per [`on_load_failure`](Self::on_load_failure)).
485///
486/// [DirectX 12 Agility SDK]: https://devblogs.microsoft.com/directx/directx12agility/
487/// [Independent Devices API]: https://devblogs.microsoft.com/directx/d3d12-independent-devices/
488/// [win11-21h2]: https://support.microsoft.com/en-us/topic/august-22-2023-kb5029332-os-build-22000-2360-preview-8f8aec64-77b4-4225-9a0f-f0153204ae28
489/// [win10-22h2]: https://support.microsoft.com/en-gb/topic/august-22-2023-kb5029331-os-build-19045-3393-preview-9f6c1dbd-0ee6-469b-af24-f9d0bf35ca18
490/// [server-2022]: https://support.microsoft.com/en-au/topic/september-12-2023-kb5030216-os-build-20348-1970-34d4aff3-fd05-4270-b288-4ab6379c7f81
491#[derive(Clone, Debug, Eq, PartialEq)]
492pub struct Dx12AgilitySDK {
493    /// The Agility SDK version number (e.g., 614 for SDK version 1.614.0).
494    ///
495    /// This must match the version of the `D3D12Core.dll` at [`sdk_path`](Self::sdk_path)
496    /// exactly, or the runtime will fail to load.
497    pub sdk_version: u32,
498    /// Path to the directory containing the Agility SDK's `D3D12Core.dll`.
499    pub sdk_path: String,
500    /// What to do if the Agility SDK fails to load.
501    ///
502    /// Defaults to [`Fallback`](Dx12AgilitySDKLoadFailure::Fallback).
503    ///
504    /// Can also be set via the `WGPU_DX12_AGILITY_SDK_REQUIRE` environment variable
505    /// (`1` for [`Error`](Dx12AgilitySDKLoadFailure::Error),
506    /// `0` for [`Fallback`](Dx12AgilitySDKLoadFailure::Fallback)).
507    pub on_load_failure: Dx12AgilitySDKLoadFailure,
508}
509
510impl Dx12AgilitySDK {
511    /// Read Agility SDK configuration from environment variables.
512    ///
513    /// Reads `WGPU_DX12_AGILITY_SDK_PATH`, `WGPU_DX12_AGILITY_SDK_VERSION`,
514    /// and `WGPU_DX12_AGILITY_SDK_REQUIRE`.
515    /// Both path and version must be set for this to return `Some`.
516    #[must_use]
517    pub fn from_env() -> Option<Self> {
518        let sdk_path = crate::env::var("WGPU_DX12_AGILITY_SDK_PATH")?;
519        let sdk_version_str = crate::env::var("WGPU_DX12_AGILITY_SDK_VERSION")?;
520        let sdk_version = sdk_version_str.parse::<u32>().ok()?;
521        let on_load_failure = Dx12AgilitySDKLoadFailure::from_env().unwrap_or_default();
522        Some(Self {
523            sdk_version,
524            sdk_path,
525            on_load_failure,
526        })
527    }
528
529    /// Takes the given configuration, overrides fields with environment variables if present,
530    /// and returns the result.
531    ///
532    /// Reads `WGPU_DX12_AGILITY_SDK_PATH`, `WGPU_DX12_AGILITY_SDK_VERSION`,
533    /// and `WGPU_DX12_AGILITY_SDK_REQUIRE`.
534    /// Each variable overrides the corresponding field independently.
535    #[must_use]
536    pub fn with_env(mut self) -> Self {
537        if let Some(sdk_path) = crate::env::var("WGPU_DX12_AGILITY_SDK_PATH") {
538            self.sdk_path = sdk_path;
539        }
540        if let Some(sdk_version_str) = crate::env::var("WGPU_DX12_AGILITY_SDK_VERSION") {
541            if let Ok(sdk_version) = sdk_version_str.parse::<u32>() {
542                self.sdk_version = sdk_version;
543            }
544        }
545        self.on_load_failure = self.on_load_failure.with_env();
546        self
547    }
548}
549
550/// Configuration for the DX12 backend.
551///
552/// Part of [`BackendOptions`].
553#[derive(Clone, Debug, Eq, PartialEq, ConstDefault!)]
554pub struct Dx12BackendOptions {
555    /// Which DX12 shader compiler to use.
556    pub shader_compiler: Dx12Compiler,
557    /// Presentation system to use.
558    pub presentation_system: Dx12SwapchainKind,
559    /// Whether to wait for the latency waitable object before acquiring the next swapchain image.
560    pub latency_waitable_object: Dx12UseFrameLatencyWaitableObject,
561    /// For use with passthrough shaders. Expose features as if this shader model is present, even if you do not
562    /// intend to ship DXC with your app.
563    ///
564    /// This does not override the device's shader model version, only the external shader compiler's version.
565    pub force_shader_model: ForceShaderModelToken,
566    /// Optional Agility SDK configuration for using the Independent Devices API.
567    ///
568    /// When set, wgpu will attempt to load the specified D3D12 runtime via the
569    /// Independent Devices API. If the API is unavailable or the configuration is
570    /// invalid, it falls back to the system-installed D3D12 runtime.
571    ///
572    /// Can also be set via `WGPU_DX12_AGILITY_SDK_PATH` and `WGPU_DX12_AGILITY_SDK_VERSION`
573    /// environment variables.
574    pub agility_sdk: Option<Dx12AgilitySDK>,
575}
576
577impl Dx12BackendOptions {
578    /// Choose DX12 backend options by calling `from_env` on every field.
579    ///
580    /// See those methods for more information.
581    #[must_use]
582    pub fn from_env_or_default() -> Self {
583        let compiler = Dx12Compiler::from_env().unwrap_or_default();
584        let presentation_system = Dx12SwapchainKind::from_env().unwrap_or_default();
585        let latency_waitable_object =
586            Dx12UseFrameLatencyWaitableObject::from_env().unwrap_or_default();
587        let agility_sdk = Dx12AgilitySDK::from_env();
588        Self {
589            shader_compiler: compiler,
590            presentation_system,
591            latency_waitable_object,
592            force_shader_model: ForceShaderModelToken::default(),
593            agility_sdk,
594        }
595    }
596
597    /// Takes the given options, modifies them based on the environment variables, and returns the result.
598    ///
599    /// This is equivalent to calling `with_env` on every field.
600    #[must_use]
601    pub fn with_env(self) -> Self {
602        let shader_compiler = self.shader_compiler.with_env();
603        let presentation_system = self.presentation_system.with_env();
604        let latency_waitable_object = self.latency_waitable_object.with_env();
605        let agility_sdk = self
606            .agility_sdk
607            .map(|s| s.with_env())
608            .or_else(Dx12AgilitySDK::from_env);
609        Self {
610            shader_compiler,
611            presentation_system,
612            latency_waitable_object,
613            force_shader_model: ForceShaderModelToken::default(),
614            agility_sdk,
615        }
616    }
617}
618
619/// Configuration for the noop backend.
620///
621/// Part of [`BackendOptions`].
622#[derive(Clone, Debug, Eq, PartialEq, ConstDefault!)]
623pub struct NoopBackendOptions {
624    /// Whether to allow the noop backend to be used.
625    ///
626    /// The noop backend stubs out all operations except for buffer creation and mapping, so
627    /// it must not be used when not expected. Therefore, it will not be used unless explicitly
628    /// enabled.
629    pub enable: bool,
630
631    /// Specify the reported limits values. If `None`, reports maximally permissive limits.
632    pub limits: Option<crate::Limits>,
633
634    /// Specify the reported feature support. If `None`, reports support for all features.
635    pub features: Option<crate::Features>,
636
637    /// Specify the reported device type. If `None`, uses [`crate::DeviceType::Other`].
638    pub device_type: Option<crate::DeviceType>,
639
640    /// Specify the reported minimum subgroup size.
641    pub subgroup_min_size: Option<u32>,
642
643    /// Specify the reported maximum subgroup size.
644    pub subgroup_max_size: Option<u32>,
645}
646
647impl NoopBackendOptions {
648    /// Enable the noop backend.
649    pub fn enabled() -> Self {
650        Self {
651            enable: true,
652            ..Default::default()
653        }
654    }
655
656    /// Choose whether the noop backend is enabled from the environment.
657    ///
658    /// It will be enabled if the environment variable `WGPU_NOOP_BACKEND` has the value `1`
659    /// and not otherwise. Future versions may assign other meanings to other values.
660    #[must_use]
661    pub fn from_env_or_default() -> Self {
662        Self {
663            enable: Self::enable_from_env().unwrap_or(false),
664            ..Default::default()
665        }
666    }
667
668    /// Takes the given options, modifies them based on the environment variables, and returns the
669    /// result.
670    ///
671    /// See [`from_env_or_default()`](Self::from_env_or_default) for the interpretation.
672    #[must_use]
673    pub fn with_env(self) -> Self {
674        Self {
675            enable: Self::enable_from_env().unwrap_or(self.enable),
676            ..self
677        }
678    }
679
680    fn enable_from_env() -> Option<bool> {
681        let value = crate::env::var("WGPU_NOOP_BACKEND")?;
682        match value.as_str() {
683            "1" => Some(true),
684            "0" => Some(false),
685            _ => None,
686        }
687    }
688}
689
690#[derive(Clone, Debug, ConstDefault!, Copy, PartialEq, Eq)]
691/// Selects which kind of swapchain to use on DX12.
692pub enum Dx12SwapchainKind {
693    /// Use a DXGI swapchain made directly from the window's HWND.
694    ///
695    /// This does not support transparency but has better support from developer tooling from RenderDoc.
696    #[custom(default)]
697    DxgiFromHwnd,
698    /// Use a DXGI swapchain made from a DirectComposition visual made automatically from the window's HWND.
699    ///
700    /// This creates a single [`IDCompositionVisual`] over the entire window that is used by the `Surface`.
701    /// If a user wants to manage the composition tree themselves, they should create their own device and
702    /// composition, and pass the relevant visual down via [`SurfaceTargetUnsafe::CompositionVisual`][CV].
703    ///
704    /// This supports transparent windows, but does not have support from RenderDoc.
705    ///
706    /// [`IDCompositionVisual`]: https://learn.microsoft.com/en-us/windows/win32/api/dcomp/nn-dcomp-idcompositionvisual
707    #[doc = link_to_wgpu_docs!(["CV"]: "struct.SurfaceTargetUnsafe.html#variant.CompositionVisual")]
708    DxgiFromVisual,
709}
710
711impl Dx12SwapchainKind {
712    /// Choose which presentation system to use from the environment variable `WGPU_DX12_PRESENTATION_SYSTEM`.
713    ///
714    /// Valid values, case insensitive:
715    /// - `DxgiFromVisual` or `Visual`
716    /// - `DxgiFromHwnd` or `Hwnd` for [`Self::DxgiFromHwnd`]
717    #[must_use]
718    pub fn from_env() -> Option<Self> {
719        let value = crate::env::var("WGPU_DX12_PRESENTATION_SYSTEM")
720            .as_deref()?
721            .to_lowercase();
722        match value.as_str() {
723            "dxgifromvisual" | "visual" => Some(Self::DxgiFromVisual),
724            "dxgifromhwnd" | "hwnd" => Some(Self::DxgiFromHwnd),
725            _ => None,
726        }
727    }
728
729    /// Takes the given presentation system, modifies it based on the `WGPU_DX12_PRESENTATION_SYSTEM` environment variable, and returns the result.
730    ///
731    /// See [`from_env`](Self::from_env) for more information.
732    #[must_use]
733    pub fn with_env(self) -> Self {
734        if let Some(presentation_system) = Self::from_env() {
735            presentation_system
736        } else {
737            self
738        }
739    }
740}
741
742/// DXC shader model.
743#[derive(Clone, Copy, Eq, PartialEq, Debug)]
744#[allow(missing_docs)]
745pub enum DxcShaderModel {
746    V6_0,
747    V6_1,
748    V6_2,
749    V6_3,
750    V6_4,
751    V6_5,
752    V6_6,
753    V6_7,
754    V6_8,
755    V6_9,
756}
757
758impl DxcShaderModel {
759    /// Get the shader model supported by a certain DXC version.
760    pub fn from_dxc_version(major: u32, minor: u32) -> Self {
761        // DXC version roughly has corresponded to shader model so far, where DXC 1.x supports SM 6.x.
762        // See discussion in https://discord.com/channels/590611987420020747/996417435374714920/1471234702206701650.
763        // Presumably DXC 2.0 and up will still support shader model 6.9.
764        if major > 1 {
765            Self::V6_9
766        } else {
767            Self::from_parts(6, minor)
768        }
769    }
770
771    /// Parse a DxcShaderModel from its version components.
772    pub fn from_parts(major: u32, minor: u32) -> Self {
773        if major > 6 || minor > 8 {
774            Self::V6_9
775        } else {
776            match minor {
777                0 => DxcShaderModel::V6_0,
778                1 => DxcShaderModel::V6_1,
779                2 => DxcShaderModel::V6_2,
780                3 => DxcShaderModel::V6_3,
781                4 => DxcShaderModel::V6_4,
782                5 => DxcShaderModel::V6_5,
783                6 => DxcShaderModel::V6_6,
784                7 => DxcShaderModel::V6_7,
785                8 => DxcShaderModel::V6_8,
786                9 => DxcShaderModel::V6_9,
787                // > 6.9
788                _ => DxcShaderModel::V6_9,
789            }
790        }
791    }
792}
793
794/// Selects which DX12 shader compiler to use.
795#[derive(Clone, Debug, Eq, PartialEq, ConstDefault!)]
796pub enum Dx12Compiler {
797    /// The Fxc compiler (default) is old, slow and unmaintained.
798    ///
799    /// However, it doesn't require any additional .dlls to be shipped with the application.
800    Fxc,
801    /// The Dxc compiler is new, fast and maintained.
802    ///
803    /// However, it requires `dxcompiler.dll` to be shipped with the application.
804    /// These files can be downloaded from <https://github.com/microsoft/DirectXShaderCompiler/releases>.
805    ///
806    /// Minimum supported version: [v1.8.2502](https://github.com/microsoft/DirectXShaderCompiler/releases/tag/v1.8.2502)
807    ///
808    /// It also requires WDDM 2.1 (Windows 10 version 1607).
809    DynamicDxc {
810        /// Path to `dxcompiler.dll`.
811        dxc_path: String,
812    },
813    /// The statically-linked variant of Dxc.
814    ///
815    /// The `static-dxc` feature is required for this setting to be used successfully on DX12.
816    /// Not available on `windows-aarch64-pc-*` targets.
817    StaticDxc,
818    /// Use statically-linked DXC if available. Otherwise check for dynamically linked DXC on the PATH. Finally, fallback to FXC.
819    #[custom(default)]
820    Auto,
821}
822
823impl Dx12Compiler {
824    /// Helper function to construct a `DynamicDxc` variant with default paths.
825    ///
826    /// The dll must support at least shader model 6.8.
827    pub fn default_dynamic_dxc() -> Self {
828        Self::DynamicDxc {
829            dxc_path: String::from("dxcompiler.dll"),
830        }
831    }
832
833    /// Choose which DX12 shader compiler to use from the environment variable `WGPU_DX12_COMPILER`.
834    ///
835    /// Valid values, case insensitive:
836    /// - `Fxc`
837    /// - `Dxc` or `DynamicDxc`
838    /// - `StaticDxc`
839    #[must_use]
840    pub fn from_env() -> Option<Self> {
841        let env = crate::env::var("WGPU_DX12_COMPILER")?;
842        env.parse().map_err(|expected_msg| {
843            log::warn!(
844                "Unknown value `{env:?}` for `WGPU_DX12_COMPILER` environment variable. {expected_msg}"
845            )
846        })
847        .ok()
848    }
849
850    /// Takes the given compiler, modifies it based on the `WGPU_DX12_COMPILER` environment variable, and returns the result.
851    ///
852    /// See `from_env` for more information.
853    #[must_use]
854    pub fn with_env(self) -> Self {
855        if let Some(compiler) = Self::from_env() {
856            compiler
857        } else {
858            self
859        }
860    }
861}
862
863impl FromStr for Dx12Compiler {
864    type Err = &'static str;
865
866    fn from_str(value: &str) -> Result<Self, Self::Err> {
867        Ok(match value.to_lowercase().as_str() {
868            "dxc" | "dynamicdxc" => Self::default_dynamic_dxc(),
869            "staticdxc" => Self::StaticDxc,
870            "fxc" => Self::Fxc,
871            "auto" => Self::Auto,
872            path => Self::DynamicDxc {
873                dxc_path: path.to_string(),
874            },
875        })
876    }
877}
878
879/// Whether and how to use a waitable handle obtained from `GetFrameLatencyWaitableObject`.
880#[derive(Clone, Debug, Eq, PartialEq, ConstDefault!)]
881pub enum Dx12UseFrameLatencyWaitableObject {
882    /// Do not obtain a waitable handle and do not wait for it. The swapchain will
883    /// be created without the `DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT` flag.
884    None,
885    /// Obtain a waitable handle and wait for it before acquiring the next swapchain image.
886    #[custom(default)]
887    Wait,
888    /// Create the swapchain with the `DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT` flag and
889    /// obtain a waitable handle, but do not wait for it before acquiring the next swapchain image.
890    /// This is useful if the application wants to wait for the waitable object itself.
891    DontWait,
892}
893
894impl Dx12UseFrameLatencyWaitableObject {
895    /// Choose whether to use a frame latency waitable object from the environment variable `WGPU_DX12_USE_FRAME_LATENCY_WAITABLE_OBJECT`.
896    ///
897    /// Valid values, case insensitive:
898    /// - `None`
899    /// - `Wait`
900    /// - `DontWait`
901    #[must_use]
902    pub fn from_env() -> Option<Self> {
903        let value = crate::env::var("WGPU_DX12_USE_FRAME_LATENCY_WAITABLE_OBJECT")
904            .as_deref()?
905            .to_lowercase();
906        match value.as_str() {
907            "none" => Some(Self::None),
908            "wait" => Some(Self::Wait),
909            "dontwait" => Some(Self::DontWait),
910            _ => None,
911        }
912    }
913
914    /// Takes the given setting, modifies it based on the `WGPU_DX12_USE_FRAME_LATENCY_WAITABLE_OBJECT` environment variable, and returns the result.
915    ///
916    /// See `from_env` for more information.
917    #[must_use]
918    pub fn with_env(self) -> Self {
919        if let Some(compiler) = Self::from_env() {
920            compiler
921        } else {
922            self
923        }
924    }
925}
926
927/// Selects which OpenGL ES 3 minor version to request.
928///
929/// When using ANGLE as an OpenGL ES/EGL implementation, explicitly requesting `Version1` can provide a non-conformant ES 3.1 on APIs like D3D11.
930#[derive(Clone, Copy, Debug, ConstDefault!, Eq, PartialEq, Hash)]
931pub enum Gles3MinorVersion {
932    /// No explicit minor version is requested, the driver automatically picks the highest available.
933    #[custom(default)]
934    Automatic,
935
936    /// Request an ES 3.0 context.
937    Version0,
938
939    /// Request an ES 3.1 context.
940    Version1,
941
942    /// Request an ES 3.2 context.
943    Version2,
944}
945
946impl Gles3MinorVersion {
947    /// Choose which minor OpenGL ES version to use from the environment variable `WGPU_GLES_MINOR_VERSION`.
948    ///
949    /// Possible values are `0`, `1`, `2` or `automatic`. Case insensitive.
950    ///
951    /// Use with `unwrap_or_default()` to get the default value if the environment variable is not set.
952    #[must_use]
953    pub fn from_env() -> Option<Self> {
954        let value = crate::env::var("WGPU_GLES_MINOR_VERSION")
955            .as_deref()?
956            .to_lowercase();
957        match value.as_str() {
958            "automatic" => Some(Self::Automatic),
959            "0" => Some(Self::Version0),
960            "1" => Some(Self::Version1),
961            "2" => Some(Self::Version2),
962            _ => None,
963        }
964    }
965
966    /// Takes the given compiler, modifies it based on the `WGPU_GLES_MINOR_VERSION` environment variable, and returns the result.
967    ///
968    /// See `from_env` for more information.
969    #[must_use]
970    pub fn with_env(self) -> Self {
971        if let Some(compiler) = Self::from_env() {
972            compiler
973        } else {
974            self
975        }
976    }
977}
978
979/// Dictate the behavior of fences in OpenGL.
980#[derive(Clone, Copy, Debug, PartialEq, Eq, ConstDefault!)]
981pub enum GlFenceBehavior {
982    /// Fences in OpenGL behave normally. If you don't know what to pick, this is what you want.
983    #[custom(default)]
984    Normal,
985    /// Fences in OpenGL are short-circuited to always return `true` immediately.
986    ///
987    /// This solves a very specific issue that arose due to a bug in wgpu-core that made
988    /// many WebGL programs work when they "shouldn't" have. If you have code that is trying
989    /// to call `device.poll(wgpu::PollType::Wait)` on WebGL, you need to enable this option
990    /// for the "Wait" to behave how you would expect.
991    ///
992    /// Previously all `poll(Wait)` acted like the OpenGL fences were signalled even if they weren't.
993    /// See <https://github.com/gfx-rs/wgpu/issues/4589> for more information.
994    ///
995    /// When this is set `Queue::on_completed_work_done` will always return the next time the device
996    /// is maintained, not when the work is actually done on the GPU.
997    AutoFinish,
998}
999
1000impl GlFenceBehavior {
1001    /// Returns true if the fence behavior is `AutoFinish`.
1002    pub fn is_auto_finish(&self) -> bool {
1003        matches!(self, Self::AutoFinish)
1004    }
1005
1006    /// Returns true if the fence behavior is `Normal`.
1007    pub fn is_normal(&self) -> bool {
1008        matches!(self, Self::Normal)
1009    }
1010
1011    /// Choose which minor OpenGL ES version to use from the environment variable `WGPU_GL_FENCE_BEHAVIOR`.
1012    ///
1013    /// Possible values are `Normal` or `AutoFinish`. Case insensitive.
1014    ///
1015    /// Use with `unwrap_or_default()` to get the default value if the environment variable is not set.
1016    #[must_use]
1017    pub fn from_env() -> Option<Self> {
1018        let value = crate::env::var("WGPU_GL_FENCE_BEHAVIOR")
1019            .as_deref()?
1020            .to_lowercase();
1021        match value.as_str() {
1022            "normal" => Some(Self::Normal),
1023            "autofinish" => Some(Self::AutoFinish),
1024            _ => None,
1025        }
1026    }
1027
1028    /// Takes the given compiler, modifies it based on the `WGPU_GL_FENCE_BEHAVIOR` environment variable, and returns the result.
1029    ///
1030    /// See `from_env` for more information.
1031    #[must_use]
1032    pub fn with_env(self) -> Self {
1033        if let Some(fence) = Self::from_env() {
1034            fence
1035        } else {
1036            self
1037        }
1038    }
1039}