wgpu_types/
instance.rs

1//! Types for dealing with Instances
2
3use alloc::string::String;
4
5use crate::Backends;
6
7#[cfg(doc)]
8use crate::{Backend, DownlevelFlags};
9
10/// Options for creating an instance.
11///
12/// If you want to allow control of instance settings via environment variables, call either
13/// [`InstanceDescriptor::from_env_or_default()`] or [`InstanceDescriptor::with_env()`]. Each type
14/// within this descriptor has its own equivalent methods, so you can select which options you want
15/// to expose to influence from the environment.
16#[derive(Clone, Debug, Default)]
17pub struct InstanceDescriptor {
18    /// Which [`Backends`] to enable.
19    ///
20    /// [`Backends::BROWSER_WEBGPU`] has an additional effect:
21    /// If it is set and a [`navigator.gpu`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/gpu)
22    /// object is present, this instance will *only* be able to create WebGPU adapters.
23    ///
24    /// ⚠️ On some browsers this check is insufficient to determine whether WebGPU is supported,
25    /// as the browser may define the `navigator.gpu` object, but be unable to create any WebGPU adapters.
26    /// For targeting _both_ WebGPU & WebGL, it is recommended to use [`crate::util::new_instance_with_webgpu_detection`](../wgpu/util/fn.new_instance_with_webgpu_detection.html).
27    ///
28    /// If you instead want to force use of WebGL, either disable the `webgpu` compile-time feature
29    /// or don't include the [`Backends::BROWSER_WEBGPU`] flag in this field.
30    /// If it is set and WebGPU support is *not* detected, the instance will use `wgpu-core`
31    /// to create adapters, meaning that if the `webgl` feature is enabled, it is able to create
32    /// a WebGL adapter.
33    pub backends: Backends,
34    /// Flags to tune the behavior of the instance.
35    pub flags: InstanceFlags,
36    /// Memory budget thresholds used by some backends.
37    pub memory_budget_thresholds: MemoryBudgetThresholds,
38    /// Options the control the behavior of specific backends.
39    pub backend_options: BackendOptions,
40}
41
42impl InstanceDescriptor {
43    /// Choose instance options entirely from environment variables.
44    ///
45    /// This is equivalent to calling `from_env` on every field.
46    #[must_use]
47    pub fn from_env_or_default() -> Self {
48        Self::default().with_env()
49    }
50
51    /// Takes the given options, modifies them based on the environment variables, and returns the result.
52    ///
53    /// This is equivalent to calling `with_env` on every field.
54    #[must_use]
55    pub fn with_env(self) -> Self {
56        let backends = self.backends.with_env();
57        let flags = self.flags.with_env();
58        let backend_options = self.backend_options.with_env();
59        Self {
60            backends,
61            flags,
62            memory_budget_thresholds: MemoryBudgetThresholds::default(),
63            backend_options,
64        }
65    }
66}
67
68bitflags::bitflags! {
69    /// Instance debugging flags.
70    ///
71    /// These are not part of the WebGPU standard.
72    ///
73    /// Defaults to enabling debugging-related flags if the build configuration has `debug_assertions`.
74    #[repr(transparent)]
75    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
76    pub struct InstanceFlags: u32 {
77        /// Generate debug information in shaders and objects.
78        ///
79        /// When `Self::from_env()` is used takes value from `WGPU_DEBUG` environment variable.
80        const DEBUG = 1 << 0;
81        /// Enable validation in the backend API, if possible:
82        ///
83        /// - On the Direct3D `dx12` backend, this calls [`ID3D12Debug::EnableDebugLayer`][dx12].
84        ///
85        /// - On the Vulkan backend, this enables the [Vulkan Validation Layer][vvl].
86        ///
87        /// - On the `gles` backend driving Windows OpenGL, this enables [debug
88        ///   output][gl:do], effectively calling `glEnable(GL_DEBUG_OUTPUT)`.
89        ///
90        /// - On non-Windows `gles` backends, this calls
91        ///   [`eglDebugMessageControlKHR`][gl:dm] to enable all debugging messages.
92        ///   If the GLES implementation is ANGLE running on Vulkan, this also
93        ///   enables the Vulkan validation layers by setting
94        ///   [`EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED`][gl:av].
95        ///
96        /// When `Self::from_env()` is used, this bit is set if the `WGPU_VALIDATION`
97        /// environment variable has any value but "0".
98        ///
99        /// [dx12]: https://learn.microsoft.com/en-us/windows/win32/api/d3d12sdklayers/nf-d3d12sdklayers-id3d12debug-enabledebuglayer
100        /// [vvl]: https://github.com/KhronosGroup/Vulkan-ValidationLayers
101        /// [gl:dm]: https://registry.khronos.org/EGL/extensions/KHR/EGL_KHR_debug.txt
102        /// [gl:do]: https://www.khronos.org/opengl/wiki/Debug_Output
103        /// [gl:av]: https://chromium.googlesource.com/angle/angle/+/HEAD/extensions/EGL_ANGLE_platform_angle.txt
104        const VALIDATION = 1 << 1;
105        /// Don't pass labels to wgpu-hal.
106        ///
107        /// When `Self::from_env()` is used takes value from `WGPU_DISCARD_HAL_LABELS` environment variable.
108        const DISCARD_HAL_LABELS = 1 << 2;
109        /// Whether wgpu should expose adapters that run on top of non-compliant adapters.
110        ///
111        /// Turning this on might mean that some of the functionality provided by the wgpu
112        /// adapter/device is not working or is broken. It could be that all the functionality
113        /// wgpu currently exposes works but we can't tell for sure since we have no additional
114        /// transparency into what is working and what is not on the underlying adapter.
115        ///
116        /// This mainly applies to a Vulkan driver's compliance version. If the major compliance version
117        /// is `0`, then the driver is ignored. This flag allows that driver to be enabled for testing.
118        ///
119        /// When `Self::from_env()` is used takes value from `WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER` environment variable.
120        const ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER = 1 << 3;
121        /// Enable GPU-based validation. Implies [`Self::VALIDATION`]. Currently, this only changes
122        /// behavior on the DX12 and Vulkan backends.
123        ///
124        /// Supported platforms:
125        ///
126        /// - D3D12; called ["GPU-based validation", or
127        ///   "GBV"](https://web.archive.org/web/20230206120404/https://learn.microsoft.com/en-us/windows/win32/direct3d12/using-d3d12-debug-layer-gpu-based-validation)
128        /// - Vulkan, via the `VK_LAYER_KHRONOS_validation` layer; called ["GPU-Assisted
129        ///   Validation"](https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/e45aeb85079e0835694cb8f03e6681fd18ae72c9/docs/gpu_validation.md#gpu-assisted-validation)
130        ///
131        /// When `Self::from_env()` is used takes value from `WGPU_GPU_BASED_VALIDATION` environment variable.
132        const GPU_BASED_VALIDATION = 1 << 4;
133
134        /// Validate indirect buffer content prior to issuing indirect draws/dispatches.
135        ///
136        /// This validation will transform indirect calls into no-ops if they are not valid:
137        ///
138        /// - When calling `dispatch_workgroups_indirect`, all 3 indirect arguments encoded in the buffer
139        /// must be less than the `max_compute_workgroups_per_dimension` device limit.
140        /// - When calling `draw_indirect`/`draw_indexed_indirect`/`multi_draw_indirect`/`multi_draw_indexed_indirect`:
141        ///   - If `Features::INDIRECT_FIRST_INSTANCE` is not enabled on the device, the `first_instance` indirect argument must be 0.
142        ///   - The `first_instance` & `instance_count` indirect arguments must form a range that fits within all bound vertex buffers with `step_mode` set to `Instance`.
143        /// - When calling `draw_indirect`/`multi_draw_indirect`:
144        ///   - The `first_vertex` & `vertex_count` indirect arguments must form a range that fits within all bound vertex buffers with `step_mode` set to `Vertex`.
145        /// - When calling `draw_indexed_indirect`/`multi_draw_indexed_indirect`:
146        ///   - The `first_index` & `index_count` indirect arguments must form a range that fits within the bound index buffer.
147        ///
148        /// __Behavior is undefined if this validation is disabled and the rules above are not satisfied.__
149        ///
150        /// Disabling this will also cause the following built-ins to not report the right values on the D3D12 backend:
151        ///
152        /// - the 3 components of `@builtin(num_workgroups)` will be 0
153        /// - the value of `@builtin(vertex_index)` will not take into account the value of the `first_vertex`/`base_vertex` argument present in the indirect buffer
154        /// - the value of `@builtin(instance_index)` will not take into account the value of the `first_instance` argument present in the indirect buffer
155        ///
156        /// When `Self::from_env()` is used takes value from `WGPU_VALIDATION_INDIRECT_CALL` environment variable.
157        const VALIDATION_INDIRECT_CALL = 1 << 5;
158
159        /// Enable automatic timestamp normalization. This means that in [`CommandEncoder::resolve_query_set`][rqs],
160        /// the timestamps will automatically be normalized to be in nanoseconds instead of the raw timestamp values.
161        ///
162        /// This is disabled by default because it introduces a compute shader into the resolution of query sets.
163        ///
164        /// This can be useful for users that need to read timestamps on the gpu, as the normalization
165        /// can be a hassle to do manually. When this is enabled, the timestamp period returned by the queue
166        /// will always be `1.0`.
167        ///
168        /// [rqs]: ../wgpu/struct.CommandEncoder.html#method.resolve_query_set
169        const AUTOMATIC_TIMESTAMP_NORMALIZATION = 1 << 6;
170    }
171}
172
173impl Default for InstanceFlags {
174    fn default() -> Self {
175        Self::from_build_config()
176    }
177}
178
179impl InstanceFlags {
180    /// Enable recommended debugging and validation flags.
181    #[must_use]
182    pub fn debugging() -> Self {
183        InstanceFlags::DEBUG | InstanceFlags::VALIDATION | InstanceFlags::VALIDATION_INDIRECT_CALL
184    }
185
186    /// Enable advanced debugging and validation flags (potentially very slow).
187    #[must_use]
188    pub fn advanced_debugging() -> Self {
189        Self::debugging() | InstanceFlags::GPU_BASED_VALIDATION
190    }
191
192    /// Infer decent defaults from the build type.
193    ///
194    /// If `cfg!(debug_assertions)` is true, then this returns [`Self::debugging()`].
195    /// Otherwise, it returns [`Self::empty()`].
196    #[must_use]
197    pub fn from_build_config() -> Self {
198        if cfg!(debug_assertions) {
199            return InstanceFlags::debugging();
200        }
201
202        InstanceFlags::VALIDATION_INDIRECT_CALL
203    }
204
205    /// Derive defaults from environment variables. See [`Self::with_env()`] for more information.
206    #[must_use]
207    pub fn from_env_or_default() -> Self {
208        Self::default().with_env()
209    }
210
211    /// Takes the given flags, modifies them based on the environment variables, and returns the result.
212    ///
213    /// - If an environment variable is set to anything but "0", the corresponding flag is set.
214    /// - If the value is "0", the flag is unset.
215    /// - If the environment variable is not present, then the flag retains its initial value.
216    ///
217    /// For example `let flags = InstanceFlags::debugging().with_env();` with `WGPU_VALIDATION=0`
218    /// does not contain [`InstanceFlags::VALIDATION`].
219    ///
220    /// The environment variables are named after the flags prefixed with "WGPU_". For example:
221    /// - `WGPU_DEBUG`
222    /// - `WGPU_VALIDATION`
223    /// - `WGPU_DISCARD_HAL_LABELS`
224    /// - `WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER`
225    /// - `WGPU_GPU_BASED_VALIDATION`
226    /// - `WGPU_VALIDATION_INDIRECT_CALL`
227    #[must_use]
228    pub fn with_env(mut self) -> Self {
229        fn env(key: &str) -> Option<bool> {
230            crate::env::var(key).map(|s| match s.as_str() {
231                "0" => false,
232                _ => true,
233            })
234        }
235
236        if let Some(bit) = env("WGPU_VALIDATION") {
237            self.set(Self::VALIDATION, bit);
238        }
239
240        if let Some(bit) = env("WGPU_DEBUG") {
241            self.set(Self::DEBUG, bit);
242        }
243        if let Some(bit) = env("WGPU_DISCARD_HAL_LABELS") {
244            self.set(Self::DISCARD_HAL_LABELS, bit);
245        }
246        if let Some(bit) = env("WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER") {
247            self.set(Self::ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER, bit);
248        }
249        if let Some(bit) = env("WGPU_GPU_BASED_VALIDATION") {
250            self.set(Self::GPU_BASED_VALIDATION, bit);
251        }
252        if let Some(bit) = env("WGPU_VALIDATION_INDIRECT_CALL") {
253            self.set(Self::VALIDATION_INDIRECT_CALL, bit);
254        }
255
256        self
257    }
258}
259
260/// Memory budget thresholds used by backends to try to avoid high memory pressure situations.
261///
262/// Currently only the D3D12 and (optionally) Vulkan backends support these options.
263#[derive(Default, Clone, Debug, Copy)]
264pub struct MemoryBudgetThresholds {
265    /// Threshold at which texture, buffer, query set and acceleration structure creation will start to return OOM errors.
266    /// This is a percent of the memory budget reported by native APIs.
267    ///
268    /// If not specified, resource creation might still return OOM errors.
269    pub for_resource_creation: Option<u8>,
270
271    /// Threshold at which devices will become lost due to memory pressure.
272    /// This is a percent of the memory budget reported by native APIs.
273    ///
274    /// If not specified, devices might still become lost due to memory pressure.
275    pub for_device_loss: Option<u8>,
276}
277
278/// Options that are passed to a given backend.
279///
280/// Part of [`InstanceDescriptor`].
281#[derive(Clone, Debug, Default)]
282pub struct BackendOptions {
283    /// Options for the OpenGL/OpenGLES backend, [`Backend::Gl`].
284    pub gl: GlBackendOptions,
285    /// Options for the DX12 backend, [`Backend::Dx12`].
286    pub dx12: Dx12BackendOptions,
287    /// Options for the noop backend, [`Backend::Noop`].
288    pub noop: NoopBackendOptions,
289}
290
291impl BackendOptions {
292    /// Choose backend options by calling `from_env` on every field.
293    ///
294    /// See those methods for more information.
295    #[must_use]
296    pub fn from_env_or_default() -> Self {
297        Self {
298            gl: GlBackendOptions::from_env_or_default(),
299            dx12: Dx12BackendOptions::from_env_or_default(),
300            noop: NoopBackendOptions::from_env_or_default(),
301        }
302    }
303
304    /// Takes the given options, modifies them based on the environment variables, and returns the result.
305    ///
306    /// This is equivalent to calling `with_env` on every field.
307    #[must_use]
308    pub fn with_env(self) -> Self {
309        Self {
310            gl: self.gl.with_env(),
311            dx12: self.dx12.with_env(),
312            noop: self.noop.with_env(),
313        }
314    }
315}
316
317/// Configuration for the OpenGL/OpenGLES backend.
318///
319/// Part of [`BackendOptions`].
320#[derive(Clone, Debug, Default)]
321pub struct GlBackendOptions {
322    /// Which OpenGL ES 3 minor version to request, if using OpenGL ES.
323    pub gles_minor_version: Gles3MinorVersion,
324    /// Behavior of OpenGL fences. Affects how `on_completed_work_done` and `device.poll` behave.
325    pub fence_behavior: GlFenceBehavior,
326}
327
328impl GlBackendOptions {
329    /// Choose OpenGL backend options by calling `from_env` on every field.
330    ///
331    /// See those methods for more information.
332    #[must_use]
333    pub fn from_env_or_default() -> Self {
334        let gles_minor_version = Gles3MinorVersion::from_env().unwrap_or_default();
335        Self {
336            gles_minor_version,
337            fence_behavior: GlFenceBehavior::Normal,
338        }
339    }
340
341    /// Takes the given options, modifies them based on the environment variables, and returns the result.
342    ///
343    /// This is equivalent to calling `with_env` on every field.
344    #[must_use]
345    pub fn with_env(self) -> Self {
346        let gles_minor_version = self.gles_minor_version.with_env();
347        let short_circuit_fences = self.fence_behavior.with_env();
348        Self {
349            gles_minor_version,
350            fence_behavior: short_circuit_fences,
351        }
352    }
353}
354
355/// Configuration for the DX12 backend.
356///
357/// Part of [`BackendOptions`].
358#[derive(Clone, Debug, Default)]
359pub struct Dx12BackendOptions {
360    /// Which DX12 shader compiler to use.
361    pub shader_compiler: Dx12Compiler,
362    /// Presentation system to use.
363    pub presentation_system: Dx12SwapchainKind,
364    /// Whether to wait for the latency waitable object before acquiring the next swapchain image.
365    pub latency_waitable_object: Dx12UseFrameLatencyWaitableObject,
366}
367
368impl Dx12BackendOptions {
369    /// Choose DX12 backend options by calling `from_env` on every field.
370    ///
371    /// See those methods for more information.
372    #[must_use]
373    pub fn from_env_or_default() -> Self {
374        let compiler = Dx12Compiler::from_env().unwrap_or_default();
375        let presentation_system = Dx12SwapchainKind::from_env().unwrap_or_default();
376        let latency_waitable_object =
377            Dx12UseFrameLatencyWaitableObject::from_env().unwrap_or_default();
378        Self {
379            shader_compiler: compiler,
380            presentation_system,
381            latency_waitable_object,
382        }
383    }
384
385    /// Takes the given options, modifies them based on the environment variables, and returns the result.
386    ///
387    /// This is equivalent to calling `with_env` on every field.
388    #[must_use]
389    pub fn with_env(self) -> Self {
390        let shader_compiler = self.shader_compiler.with_env();
391        let presentation_system = self.presentation_system.with_env();
392        let latency_waitable_object = self.latency_waitable_object.with_env();
393        Self {
394            shader_compiler,
395            presentation_system,
396            latency_waitable_object,
397        }
398    }
399}
400
401/// Configuration for the noop backend.
402///
403/// Part of [`BackendOptions`].
404#[derive(Clone, Debug, Default)]
405pub struct NoopBackendOptions {
406    /// Whether to allow the noop backend to be used.
407    ///
408    /// The noop backend stubs out all operations except for buffer creation and mapping, so
409    /// it must not be used when not expected. Therefore, it will not be used unless explicitly
410    /// enabled.
411    pub enable: bool,
412}
413
414impl NoopBackendOptions {
415    /// Choose whether the noop backend is enabled from the environment.
416    ///
417    /// It will be enabled if the environment variable `WGPU_NOOP_BACKEND` has the value `1`
418    /// and not otherwise. Future versions may assign other meanings to other values.
419    #[must_use]
420    pub fn from_env_or_default() -> Self {
421        Self {
422            enable: Self::enable_from_env().unwrap_or(false),
423        }
424    }
425
426    /// Takes the given options, modifies them based on the environment variables, and returns the
427    /// result.
428    ///
429    /// See [`from_env_or_default()`](Self::from_env_or_default) for the interpretation.
430    #[must_use]
431    pub fn with_env(self) -> Self {
432        Self {
433            enable: Self::enable_from_env().unwrap_or(self.enable),
434        }
435    }
436
437    fn enable_from_env() -> Option<bool> {
438        let value = crate::env::var("WGPU_NOOP_BACKEND")?;
439        match value.as_str() {
440            "1" => Some(true),
441            "0" => Some(false),
442            _ => None,
443        }
444    }
445}
446
447#[derive(Clone, Debug, Default, Copy, PartialEq, Eq)]
448/// Selects which kind of swapchain to use on DX12.
449pub enum Dx12SwapchainKind {
450    /// Use a DXGI swapchain made directly from the window's HWND.
451    ///
452    /// This does not support transparency but has better support from developer tooling from RenderDoc.
453    #[default]
454    DxgiFromHwnd,
455    /// Use a DXGI swapchain made from a DirectComposition visual made automatically from the window's HWND.
456    ///
457    /// This creates a single [`IDCompositionVisual`] over the entire window that is used by the `Surface`.
458    /// If a user wants to manage the composition tree themselves, they should create their own device and
459    /// composition, and pass the relevant visual down via [`SurfaceTargetUnsafe::CompositionVisual`][CV].
460    ///
461    /// This supports transparent windows, but does not have support from RenderDoc.
462    ///
463    /// [`IDCompositionVisual`]: https://learn.microsoft.com/en-us/windows/win32/api/dcomp/nn-dcomp-idcompositionvisual
464    /// [CV]: ../wgpu/struct.SurfaceTargetUnsafe.html#variant.CompositionVisual
465    DxgiFromVisual,
466}
467
468impl Dx12SwapchainKind {
469    /// Choose which presentation system to use from the environment variable `WGPU_DX12_PRESENTATION_SYSTEM`.
470    ///
471    /// Valid values, case insensitive:
472    /// - `DxgiFromVisual` or `Visual`
473    /// - `DxgiFromHwnd` or `Hwnd` for [`Self::DxgiFromHwnd`]
474    #[must_use]
475    pub fn from_env() -> Option<Self> {
476        let value = crate::env::var("WGPU_DX12_PRESENTATION_SYSTEM")
477            .as_deref()?
478            .to_lowercase();
479        match value.as_str() {
480            "dxgifromvisual" | "visual" => Some(Self::DxgiFromVisual),
481            "dxgifromhwnd" | "hwnd" => Some(Self::DxgiFromHwnd),
482            _ => None,
483        }
484    }
485
486    /// Takes the given presentation system, modifies it based on the `WGPU_DX12_PRESENTATION_SYSTEM` environment variable, and returns the result.
487    ///
488    /// See [`from_env`](Self::from_env) for more information.
489    #[must_use]
490    pub fn with_env(self) -> Self {
491        if let Some(presentation_system) = Self::from_env() {
492            presentation_system
493        } else {
494            self
495        }
496    }
497}
498
499/// DXC shader model.
500#[derive(Clone, Debug)]
501#[allow(missing_docs)]
502pub enum DxcShaderModel {
503    V6_0,
504    V6_1,
505    V6_2,
506    V6_3,
507    V6_4,
508    V6_5,
509    V6_6,
510    V6_7,
511}
512
513/// Selects which DX12 shader compiler to use.
514#[derive(Clone, Debug, Default)]
515pub enum Dx12Compiler {
516    /// The Fxc compiler (default) is old, slow and unmaintained.
517    ///
518    /// However, it doesn't require any additional .dlls to be shipped with the application.
519    #[default]
520    Fxc,
521    /// The Dxc compiler is new, fast and maintained.
522    ///
523    /// However, it requires `dxcompiler.dll` to be shipped with the application.
524    /// These files can be downloaded from <https://github.com/microsoft/DirectXShaderCompiler/releases>.
525    ///
526    /// Minimum supported version: [v1.8.2502](https://github.com/microsoft/DirectXShaderCompiler/releases/tag/v1.8.2502)
527    ///
528    /// It also requires WDDM 2.1 (Windows 10 version 1607).
529    DynamicDxc {
530        /// Path to `dxcompiler.dll`.
531        dxc_path: String,
532        /// Maximum shader model the given dll supports.
533        max_shader_model: DxcShaderModel,
534    },
535    /// The statically-linked variant of Dxc.
536    ///
537    /// The `static-dxc` feature is required for this setting to be used successfully on DX12.
538    /// Not available on `windows-aarch64-pc-*` targets.
539    StaticDxc,
540}
541
542impl Dx12Compiler {
543    /// Helper function to construct a `DynamicDxc` variant with default paths.
544    ///
545    /// The dll must support at least shader model 6.8.
546    pub fn default_dynamic_dxc() -> Self {
547        Self::DynamicDxc {
548            dxc_path: String::from("dxcompiler.dll"),
549            max_shader_model: DxcShaderModel::V6_7, // should be 6.8 but the variant is missing
550        }
551    }
552
553    /// Choose which DX12 shader compiler to use from the environment variable `WGPU_DX12_COMPILER`.
554    ///
555    /// Valid values, case insensitive:
556    /// - `Fxc`
557    /// - `Dxc` or `DynamicDxc`
558    /// - `StaticDxc`
559    #[must_use]
560    pub fn from_env() -> Option<Self> {
561        let value = crate::env::var("WGPU_DX12_COMPILER")
562            .as_deref()?
563            .to_lowercase();
564        match value.as_str() {
565            "dxc" | "dynamicdxc" => Some(Self::default_dynamic_dxc()),
566            "staticdxc" => Some(Self::StaticDxc),
567            "fxc" => Some(Self::Fxc),
568            _ => None,
569        }
570    }
571
572    /// Takes the given compiler, modifies it based on the `WGPU_DX12_COMPILER` environment variable, and returns the result.
573    ///
574    /// See `from_env` for more information.
575    #[must_use]
576    pub fn with_env(self) -> Self {
577        if let Some(compiler) = Self::from_env() {
578            compiler
579        } else {
580            self
581        }
582    }
583}
584
585/// Whether and how to use a waitable handle obtained from `GetFrameLatencyWaitableObject`.
586#[derive(Clone, Debug, Default)]
587pub enum Dx12UseFrameLatencyWaitableObject {
588    /// Do not obtain a waitable handle and do not wait for it. The swapchain will
589    /// be created without the `DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT` flag.
590    None,
591    /// Obtain a waitable handle and wait for it before acquiring the next swapchain image.
592    #[default]
593    Wait,
594    /// Create the swapchain with the `DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT` flag and
595    /// obtain a waitable handle, but do not wait for it before acquiring the next swapchain image.
596    /// This is useful if the application wants to wait for the waitable object itself.
597    DontWait,
598}
599
600impl Dx12UseFrameLatencyWaitableObject {
601    /// Choose whether to use a frame latency waitable object from the environment variable `WGPU_DX12_USE_FRAME_LATENCY_WAITABLE_OBJECT`.
602    ///
603    /// Valid values, case insensitive:
604    /// - `None`
605    /// - `Wait`
606    /// - `DontWait`
607    #[must_use]
608    pub fn from_env() -> Option<Self> {
609        let value = crate::env::var("WGPU_DX12_USE_FRAME_LATENCY_WAITABLE_OBJECT")
610            .as_deref()?
611            .to_lowercase();
612        match value.as_str() {
613            "none" => Some(Self::None),
614            "wait" => Some(Self::Wait),
615            "dontwait" => Some(Self::DontWait),
616            _ => None,
617        }
618    }
619
620    /// Takes the given setting, modifies it based on the `WGPU_DX12_USE_FRAME_LATENCY_WAITABLE_OBJECT` environment variable, and returns the result.
621    ///
622    /// See `from_env` for more information.
623    #[must_use]
624    pub fn with_env(self) -> Self {
625        if let Some(compiler) = Self::from_env() {
626            compiler
627        } else {
628            self
629        }
630    }
631}
632
633/// Selects which OpenGL ES 3 minor version to request.
634///
635/// When using ANGLE as an OpenGL ES/EGL implementation, explicitly requesting `Version1` can provide a non-conformant ES 3.1 on APIs like D3D11.
636#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
637pub enum Gles3MinorVersion {
638    /// No explicit minor version is requested, the driver automatically picks the highest available.
639    #[default]
640    Automatic,
641
642    /// Request an ES 3.0 context.
643    Version0,
644
645    /// Request an ES 3.1 context.
646    Version1,
647
648    /// Request an ES 3.2 context.
649    Version2,
650}
651
652impl Gles3MinorVersion {
653    /// Choose which minor OpenGL ES version to use from the environment variable `WGPU_GLES_MINOR_VERSION`.
654    ///
655    /// Possible values are `0`, `1`, `2` or `automatic`. Case insensitive.
656    ///
657    /// Use with `unwrap_or_default()` to get the default value if the environment variable is not set.
658    #[must_use]
659    pub fn from_env() -> Option<Self> {
660        let value = crate::env::var("WGPU_GLES_MINOR_VERSION")
661            .as_deref()?
662            .to_lowercase();
663        match value.as_str() {
664            "automatic" => Some(Self::Automatic),
665            "0" => Some(Self::Version0),
666            "1" => Some(Self::Version1),
667            "2" => Some(Self::Version2),
668            _ => None,
669        }
670    }
671
672    /// Takes the given compiler, modifies it based on the `WGPU_GLES_MINOR_VERSION` environment variable, and returns the result.
673    ///
674    /// See `from_env` for more information.
675    #[must_use]
676    pub fn with_env(self) -> Self {
677        if let Some(compiler) = Self::from_env() {
678            compiler
679        } else {
680            self
681        }
682    }
683}
684
685/// Dictate the behavior of fences in OpenGL.
686#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
687pub enum GlFenceBehavior {
688    /// Fences in OpenGL behave normally. If you don't know what to pick, this is what you want.
689    #[default]
690    Normal,
691    /// Fences in OpenGL are short-circuited to always return `true` immediately.
692    ///
693    /// This solves a very specific issue that arose due to a bug in wgpu-core that made
694    /// many WebGL programs work when they "shouldn't" have. If you have code that is trying
695    /// to call `device.poll(wgpu::PollType::Wait)` on WebGL, you need to enable this option
696    /// for the "Wait" to behave how you would expect.
697    ///
698    /// Previously all `poll(Wait)` acted like the OpenGL fences were signalled even if they weren't.
699    /// See <https://github.com/gfx-rs/wgpu/issues/4589> for more information.
700    ///
701    /// When this is set `Queue::on_completed_work_done` will always return the next time the device
702    /// is maintained, not when the work is actually done on the GPU.
703    AutoFinish,
704}
705
706impl GlFenceBehavior {
707    /// Returns true if the fence behavior is `AutoFinish`.
708    pub fn is_auto_finish(&self) -> bool {
709        matches!(self, Self::AutoFinish)
710    }
711
712    /// Returns true if the fence behavior is `Normal`.
713    pub fn is_normal(&self) -> bool {
714        matches!(self, Self::Normal)
715    }
716
717    /// Choose which minor OpenGL ES version to use from the environment variable `WGPU_GL_FENCE_BEHAVIOR`.
718    ///
719    /// Possible values are `Normal` or `AutoFinish`. Case insensitive.
720    ///
721    /// Use with `unwrap_or_default()` to get the default value if the environment variable is not set.
722    #[must_use]
723    pub fn from_env() -> Option<Self> {
724        let value = crate::env::var("WGPU_GL_FENCE_BEHAVIOR")
725            .as_deref()?
726            .to_lowercase();
727        match value.as_str() {
728            "normal" => Some(Self::Normal),
729            "autofinish" => Some(Self::AutoFinish),
730            _ => None,
731        }
732    }
733
734    /// Takes the given compiler, modifies it based on the `WGPU_GL_FENCE_BEHAVIOR` environment variable, and returns the result.
735    ///
736    /// See `from_env` for more information.
737    #[must_use]
738    pub fn with_env(self) -> Self {
739        if let Some(fence) = Self::from_env() {
740            fence
741        } else {
742            self
743        }
744    }
745}