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    /// Whether to wait for the latency waitable object before acquiring the next swapchain image.
363    pub latency_waitable_object: Dx12UseFrameLatencyWaitableObject,
364}
365
366impl Dx12BackendOptions {
367    /// Choose DX12 backend options by calling `from_env` on every field.
368    ///
369    /// See those methods for more information.
370    #[must_use]
371    pub fn from_env_or_default() -> Self {
372        let compiler = Dx12Compiler::from_env().unwrap_or_default();
373        let latency_waitable_object =
374            Dx12UseFrameLatencyWaitableObject::from_env().unwrap_or_default();
375        Self {
376            shader_compiler: compiler,
377            latency_waitable_object,
378        }
379    }
380
381    /// Takes the given options, modifies them based on the environment variables, and returns the result.
382    ///
383    /// This is equivalent to calling `with_env` on every field.
384    #[must_use]
385    pub fn with_env(self) -> Self {
386        let shader_compiler = self.shader_compiler.with_env();
387        let latency_waitable_object = self.latency_waitable_object.with_env();
388
389        Self {
390            shader_compiler,
391            latency_waitable_object,
392        }
393    }
394}
395
396/// Configuration for the noop backend.
397///
398/// Part of [`BackendOptions`].
399#[derive(Clone, Debug, Default)]
400pub struct NoopBackendOptions {
401    /// Whether to allow the noop backend to be used.
402    ///
403    /// The noop backend stubs out all operations except for buffer creation and mapping, so
404    /// it must not be used when not expected. Therefore, it will not be used unless explicitly
405    /// enabled.
406    pub enable: bool,
407}
408
409impl NoopBackendOptions {
410    /// Choose whether the noop backend is enabled from the environment.
411    ///
412    /// It will be enabled if the environment variable `WGPU_NOOP_BACKEND` has the value `1`
413    /// and not otherwise. Future versions may assign other meanings to other values.
414    #[must_use]
415    pub fn from_env_or_default() -> Self {
416        Self {
417            enable: Self::enable_from_env().unwrap_or(false),
418        }
419    }
420
421    /// Takes the given options, modifies them based on the environment variables, and returns the
422    /// result.
423    ///
424    /// See [`from_env_or_default()`](Self::from_env_or_default) for the interpretation.
425    #[must_use]
426    pub fn with_env(self) -> Self {
427        Self {
428            enable: Self::enable_from_env().unwrap_or(self.enable),
429        }
430    }
431
432    fn enable_from_env() -> Option<bool> {
433        let value = crate::env::var("WGPU_NOOP_BACKEND")?;
434        match value.as_str() {
435            "1" => Some(true),
436            "0" => Some(false),
437            _ => None,
438        }
439    }
440}
441
442/// DXC shader model.
443#[derive(Clone, Debug)]
444#[allow(missing_docs)]
445pub enum DxcShaderModel {
446    V6_0,
447    V6_1,
448    V6_2,
449    V6_3,
450    V6_4,
451    V6_5,
452    V6_6,
453    V6_7,
454}
455
456/// Selects which DX12 shader compiler to use.
457#[derive(Clone, Debug, Default)]
458pub enum Dx12Compiler {
459    /// The Fxc compiler (default) is old, slow and unmaintained.
460    ///
461    /// However, it doesn't require any additional .dlls to be shipped with the application.
462    #[default]
463    Fxc,
464    /// The Dxc compiler is new, fast and maintained.
465    ///
466    /// However, it requires `dxcompiler.dll` to be shipped with the application.
467    /// These files can be downloaded from <https://github.com/microsoft/DirectXShaderCompiler/releases>.
468    ///
469    /// Minimum supported version: [v1.8.2502](https://github.com/microsoft/DirectXShaderCompiler/releases/tag/v1.8.2502)
470    ///
471    /// It also requires WDDM 2.1 (Windows 10 version 1607).
472    DynamicDxc {
473        /// Path to `dxcompiler.dll`.
474        dxc_path: String,
475        /// Maximum shader model the given dll supports.
476        max_shader_model: DxcShaderModel,
477    },
478    /// The statically-linked variant of Dxc.
479    ///
480    /// The `static-dxc` feature is required for this setting to be used successfully on DX12.
481    /// Not available on `windows-aarch64-pc-*` targets.
482    StaticDxc,
483}
484
485impl Dx12Compiler {
486    /// Helper function to construct a `DynamicDxc` variant with default paths.
487    ///
488    /// The dll must support at least shader model 6.8.
489    pub fn default_dynamic_dxc() -> Self {
490        Self::DynamicDxc {
491            dxc_path: String::from("dxcompiler.dll"),
492            max_shader_model: DxcShaderModel::V6_7, // should be 6.8 but the variant is missing
493        }
494    }
495
496    /// Choose which DX12 shader compiler to use from the environment variable `WGPU_DX12_COMPILER`.
497    ///
498    /// Valid values, case insensitive:
499    /// - `Fxc`
500    /// - `Dxc` or `DynamicDxc`
501    /// - `StaticDxc`
502    #[must_use]
503    pub fn from_env() -> Option<Self> {
504        let value = crate::env::var("WGPU_DX12_COMPILER")
505            .as_deref()?
506            .to_lowercase();
507        match value.as_str() {
508            "dxc" | "dynamicdxc" => Some(Self::default_dynamic_dxc()),
509            "staticdxc" => Some(Self::StaticDxc),
510            "fxc" => Some(Self::Fxc),
511            _ => None,
512        }
513    }
514
515    /// Takes the given compiler, modifies it based on the `WGPU_DX12_COMPILER` environment variable, and returns the result.
516    ///
517    /// See `from_env` for more information.
518    #[must_use]
519    pub fn with_env(self) -> Self {
520        if let Some(compiler) = Self::from_env() {
521            compiler
522        } else {
523            self
524        }
525    }
526}
527
528/// Whether and how to use a waitable handle obtained from `GetFrameLatencyWaitableObject`.
529#[derive(Clone, Debug, Default)]
530pub enum Dx12UseFrameLatencyWaitableObject {
531    /// Do not obtain a waitable handle and do not wait for it. The swapchain will
532    /// be created without the `DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT` flag.
533    None,
534    /// Obtain a waitable handle and wait for it before acquiring the next swapchain image.
535    #[default]
536    Wait,
537    /// Create the swapchain with the `DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT` flag and
538    /// obtain a waitable handle, but do not wait for it before acquiring the next swapchain image.
539    /// This is useful if the application wants to wait for the waitable object itself.
540    DontWait,
541}
542
543impl Dx12UseFrameLatencyWaitableObject {
544    /// Choose whether to use a frame latency waitable object from the environment variable `WGPU_DX12_USE_FRAME_LATENCY_WAITABLE_OBJECT`.
545    ///
546    /// Valid values, case insensitive:
547    /// - `None`
548    /// - `Wait`
549    /// - `DontWait`
550    #[must_use]
551    pub fn from_env() -> Option<Self> {
552        let value = crate::env::var("WGPU_DX12_USE_FRAME_LATENCY_WAITABLE_OBJECT")
553            .as_deref()?
554            .to_lowercase();
555        match value.as_str() {
556            "none" => Some(Self::None),
557            "wait" => Some(Self::Wait),
558            "dontwait" => Some(Self::DontWait),
559            _ => None,
560        }
561    }
562
563    /// Takes the given setting, modifies it based on the `WGPU_DX12_USE_FRAME_LATENCY_WAITABLE_OBJECT` environment variable, and returns the result.
564    ///
565    /// See `from_env` for more information.
566    #[must_use]
567    pub fn with_env(self) -> Self {
568        if let Some(compiler) = Self::from_env() {
569            compiler
570        } else {
571            self
572        }
573    }
574}
575
576/// Selects which OpenGL ES 3 minor version to request.
577///
578/// When using ANGLE as an OpenGL ES/EGL implementation, explicitly requesting `Version1` can provide a non-conformant ES 3.1 on APIs like D3D11.
579#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
580pub enum Gles3MinorVersion {
581    /// No explicit minor version is requested, the driver automatically picks the highest available.
582    #[default]
583    Automatic,
584
585    /// Request an ES 3.0 context.
586    Version0,
587
588    /// Request an ES 3.1 context.
589    Version1,
590
591    /// Request an ES 3.2 context.
592    Version2,
593}
594
595impl Gles3MinorVersion {
596    /// Choose which minor OpenGL ES version to use from the environment variable `WGPU_GLES_MINOR_VERSION`.
597    ///
598    /// Possible values are `0`, `1`, `2` or `automatic`. Case insensitive.
599    ///
600    /// Use with `unwrap_or_default()` to get the default value if the environment variable is not set.
601    #[must_use]
602    pub fn from_env() -> Option<Self> {
603        let value = crate::env::var("WGPU_GLES_MINOR_VERSION")
604            .as_deref()?
605            .to_lowercase();
606        match value.as_str() {
607            "automatic" => Some(Self::Automatic),
608            "0" => Some(Self::Version0),
609            "1" => Some(Self::Version1),
610            "2" => Some(Self::Version2),
611            _ => None,
612        }
613    }
614
615    /// Takes the given compiler, modifies it based on the `WGPU_GLES_MINOR_VERSION` environment variable, and returns the result.
616    ///
617    /// See `from_env` for more information.
618    #[must_use]
619    pub fn with_env(self) -> Self {
620        if let Some(compiler) = Self::from_env() {
621            compiler
622        } else {
623            self
624        }
625    }
626}
627
628/// Dictate the behavior of fences in OpenGL.
629#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
630pub enum GlFenceBehavior {
631    /// Fences in OpenGL behave normally. If you don't know what to pick, this is what you want.
632    #[default]
633    Normal,
634    /// Fences in OpenGL are short-circuited to always return `true` immediately.
635    ///
636    /// This solves a very specific issue that arose due to a bug in wgpu-core that made
637    /// many WebGL programs work when they "shouldn't" have. If you have code that is trying
638    /// to call `device.poll(wgpu::PollType::Wait)` on WebGL, you need to enable this option
639    /// for the "Wait" to behave how you would expect.
640    ///
641    /// Previously all `poll(Wait)` acted like the OpenGL fences were signalled even if they weren't.
642    /// See <https://github.com/gfx-rs/wgpu/issues/4589> for more information.
643    ///
644    /// When this is set `Queue::on_completed_work_done` will always return the next time the device
645    /// is maintained, not when the work is actually done on the GPU.
646    AutoFinish,
647}
648
649impl GlFenceBehavior {
650    /// Returns true if the fence behavior is `AutoFinish`.
651    pub fn is_auto_finish(&self) -> bool {
652        matches!(self, Self::AutoFinish)
653    }
654
655    /// Returns true if the fence behavior is `Normal`.
656    pub fn is_normal(&self) -> bool {
657        matches!(self, Self::Normal)
658    }
659
660    /// Choose which minor OpenGL ES version to use from the environment variable `WGPU_GL_FENCE_BEHAVIOR`.
661    ///
662    /// Possible values are `Normal` or `AutoFinish`. Case insensitive.
663    ///
664    /// Use with `unwrap_or_default()` to get the default value if the environment variable is not set.
665    #[must_use]
666    pub fn from_env() -> Option<Self> {
667        let value = crate::env::var("WGPU_GL_FENCE_BEHAVIOR")
668            .as_deref()?
669            .to_lowercase();
670        match value.as_str() {
671            "normal" => Some(Self::Normal),
672            "autofinish" => Some(Self::AutoFinish),
673            _ => None,
674        }
675    }
676
677    /// Takes the given compiler, modifies it based on the `WGPU_GL_FENCE_BEHAVIOR` environment variable, and returns the result.
678    ///
679    /// See `from_env` for more information.
680    #[must_use]
681    pub fn with_env(self) -> Self {
682        if let Some(fence) = Self::from_env() {
683            fence
684        } else {
685            self
686        }
687    }
688}