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#[derive(Clone, Debug)]
12pub struct InstanceDescriptor {
13    /// Which `Backends` to enable.
14    pub backends: Backends,
15    /// Flags to tune the behavior of the instance.
16    pub flags: InstanceFlags,
17    /// Options the control the behavior of various backends.
18    pub backend_options: BackendOptions,
19}
20
21impl Default for InstanceDescriptor {
22    fn default() -> Self {
23        Self {
24            backends: Backends::all(),
25            flags: InstanceFlags::default(),
26            backend_options: BackendOptions::default(),
27        }
28    }
29}
30
31impl InstanceDescriptor {
32    /// Choose instance options entirely from environment variables.
33    ///
34    /// This is equivalent to calling `from_env` on every field.
35    #[must_use]
36    pub fn from_env_or_default() -> Self {
37        Self::default().with_env()
38    }
39
40    /// Takes the given options, modifies them based on the environment variables, and returns the result.
41    ///
42    /// This is equivalent to calling `with_env` on every field.
43    #[must_use]
44    pub fn with_env(self) -> Self {
45        let backends = self.backends.with_env();
46        let flags = self.flags.with_env();
47        let backend_options = self.backend_options.with_env();
48        Self {
49            backends,
50            flags,
51            backend_options,
52        }
53    }
54}
55
56bitflags::bitflags! {
57    /// Instance debugging flags.
58    ///
59    /// These are not part of the WebGPU standard.
60    ///
61    /// Defaults to enabling debugging-related flags if the build configuration has `debug_assertions`.
62    #[repr(transparent)]
63    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
64    pub struct InstanceFlags: u32 {
65        /// Generate debug information in shaders and objects.
66        ///
67        /// When `Self::from_env()` is used takes value from `WGPU_DEBUG` environment variable.
68        const DEBUG = 1 << 0;
69        /// Enable validation, if possible.
70        ///
71        /// When `Self::from_env()` is used takes value from `WGPU_VALIDATION` environment variable.
72        const VALIDATION = 1 << 1;
73        /// Don't pass labels to wgpu-hal.
74        ///
75        /// When `Self::from_env()` is used takes value from `WGPU_DISCARD_HAL_LABELS` environment variable.
76        const DISCARD_HAL_LABELS = 1 << 2;
77        /// Whether wgpu should expose adapters that run on top of non-compliant adapters.
78        ///
79        /// Turning this on might mean that some of the functionality provided by the wgpu
80        /// adapter/device is not working or is broken. It could be that all the functionality
81        /// wgpu currently exposes works but we can't tell for sure since we have no additional
82        /// transparency into what is working and what is not on the underlying adapter.
83        ///
84        /// This mainly applies to a Vulkan driver's compliance version. If the major compliance version
85        /// is `0`, then the driver is ignored. This flag allows that driver to be enabled for testing.
86        ///
87        /// When `Self::from_env()` is used takes value from `WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER` environment variable.
88        const ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER = 1 << 3;
89        /// Enable GPU-based validation. Implies [`Self::VALIDATION`]. Currently, this only changes
90        /// behavior on the DX12 and Vulkan backends.
91        ///
92        /// Supported platforms:
93        ///
94        /// - D3D12; called ["GPU-based validation", or
95        ///   "GBV"](https://web.archive.org/web/20230206120404/https://learn.microsoft.com/en-us/windows/win32/direct3d12/using-d3d12-debug-layer-gpu-based-validation)
96        /// - Vulkan, via the `VK_LAYER_KHRONOS_validation` layer; called ["GPU-Assisted
97        ///   Validation"](https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/e45aeb85079e0835694cb8f03e6681fd18ae72c9/docs/gpu_validation.md#gpu-assisted-validation)
98        ///
99        /// When `Self::from_env()` is used takes value from `WGPU_GPU_BASED_VALIDATION` environment variable.
100        const GPU_BASED_VALIDATION = 1 << 4;
101
102        /// Validate indirect buffer content prior to issuing indirect draws/dispatches.
103        ///
104        /// When `Self::from_env()` is used takes value from `WGPU_VALIDATION_INDIRECT_CALL` environment variable.
105        const VALIDATION_INDIRECT_CALL = 1 << 5;
106
107        /// Enable automatic timestamp normalization. This means that in [`CommandEncoder::resolve_query_set`][rqs],
108        /// the timestamps will automatically be normalized to be in nanoseconds instead of the raw timestamp values.
109        ///
110        /// This is disabled by default because it introduces a compute shader into the resolution of query sets.
111        ///
112        /// This can be useful for users that need to read timestamps on the gpu, as the normalization
113        /// can be a hassle to do manually. When this is enabled, the timestamp period returned by the queue
114        /// will always be `1.0`.
115        ///
116        /// [rqs]: ../wgpu/struct.CommandEncoder.html#method.resolve_query_set
117        const AUTOMATIC_TIMESTAMP_NORMALIZATION = 1 << 6;
118    }
119}
120
121impl Default for InstanceFlags {
122    fn default() -> Self {
123        Self::from_build_config()
124    }
125}
126
127impl InstanceFlags {
128    /// Enable recommended debugging and validation flags.
129    #[must_use]
130    pub fn debugging() -> Self {
131        InstanceFlags::DEBUG | InstanceFlags::VALIDATION | InstanceFlags::VALIDATION_INDIRECT_CALL
132    }
133
134    /// Enable advanced debugging and validation flags (potentially very slow).
135    #[must_use]
136    pub fn advanced_debugging() -> Self {
137        Self::debugging() | InstanceFlags::GPU_BASED_VALIDATION
138    }
139
140    /// Infer decent defaults from the build type.
141    ///
142    /// If `cfg!(debug_assertions)` is true, then this returns [`Self::debugging()`].
143    /// Otherwise, it returns [`Self::empty()`].
144    #[must_use]
145    pub fn from_build_config() -> Self {
146        if cfg!(debug_assertions) {
147            return InstanceFlags::debugging();
148        }
149
150        InstanceFlags::VALIDATION_INDIRECT_CALL
151    }
152
153    /// Derive defaults from environment variables. See [`Self::with_env()`] for more information.
154    #[must_use]
155    pub fn from_env_or_default() -> Self {
156        Self::default().with_env()
157    }
158
159    /// Takes the given flags, modifies them based on the environment variables, and returns the result.
160    ///
161    /// - If an environment variable is set to anything but "0", the corresponding flag is set.
162    /// - If the value is "0", the flag is unset.
163    /// - If the environment variable is not present, then the flag retains its initial value.
164    ///
165    /// For example `let flags = InstanceFlags::debugging().with_env();` with `WGPU_VALIDATION=0`
166    /// does not contain [`InstanceFlags::VALIDATION`].
167    ///
168    /// The environment variables are named after the flags prefixed with "WGPU_". For example:
169    /// - `WGPU_DEBUG`
170    /// - `WGPU_VALIDATION`
171    /// - `WGPU_DISCARD_HAL_LABELS`
172    /// - `WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER`
173    /// - `WGPU_GPU_BASED_VALIDATION`
174    /// - `WGPU_VALIDATION_INDIRECT_CALL`
175    #[must_use]
176    pub fn with_env(mut self) -> Self {
177        fn env(key: &str) -> Option<bool> {
178            crate::env::var(key).map(|s| match s.as_str() {
179                "0" => false,
180                _ => true,
181            })
182        }
183
184        if let Some(bit) = env("WGPU_VALIDATION") {
185            self.set(Self::VALIDATION, bit);
186        }
187
188        if let Some(bit) = env("WGPU_DEBUG") {
189            self.set(Self::DEBUG, bit);
190        }
191        if let Some(bit) = env("WGPU_DISCARD_HAL_LABELS") {
192            self.set(Self::DISCARD_HAL_LABELS, bit);
193        }
194        if let Some(bit) = env("WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER") {
195            self.set(Self::ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER, bit);
196        }
197        if let Some(bit) = env("WGPU_GPU_BASED_VALIDATION") {
198            self.set(Self::GPU_BASED_VALIDATION, bit);
199        }
200        if let Some(bit) = env("WGPU_VALIDATION_INDIRECT_CALL") {
201            self.set(Self::VALIDATION_INDIRECT_CALL, bit);
202        }
203
204        self
205    }
206}
207
208/// Options that are passed to a given backend.
209///
210/// Part of [`InstanceDescriptor`].
211#[derive(Clone, Debug, Default)]
212pub struct BackendOptions {
213    /// Options for the OpenGL/OpenGLES backend, [`Backend::Gl`].
214    pub gl: GlBackendOptions,
215    /// Options for the DX12 backend, [`Backend::Dx12`].
216    pub dx12: Dx12BackendOptions,
217    /// Options for the noop backend, [`Backend::Noop`].
218    pub noop: NoopBackendOptions,
219}
220
221impl BackendOptions {
222    /// Choose backend options by calling `from_env` on every field.
223    ///
224    /// See those methods for more information.
225    #[must_use]
226    pub fn from_env_or_default() -> Self {
227        Self {
228            gl: GlBackendOptions::from_env_or_default(),
229            dx12: Dx12BackendOptions::from_env_or_default(),
230            noop: NoopBackendOptions::from_env_or_default(),
231        }
232    }
233
234    /// Takes the given options, modifies them based on the environment variables, and returns the result.
235    ///
236    /// This is equivalent to calling `with_env` on every field.
237    #[must_use]
238    pub fn with_env(self) -> Self {
239        Self {
240            gl: self.gl.with_env(),
241            dx12: self.dx12.with_env(),
242            noop: self.noop.with_env(),
243        }
244    }
245}
246
247/// Configuration for the OpenGL/OpenGLES backend.
248///
249/// Part of [`BackendOptions`].
250#[derive(Clone, Debug, Default)]
251pub struct GlBackendOptions {
252    /// Which OpenGL ES 3 minor version to request, if using OpenGL ES.
253    pub gles_minor_version: Gles3MinorVersion,
254    /// Behavior of OpenGL fences. Affects how `on_completed_work_done` and `device.poll` behave.
255    pub fence_behavior: GlFenceBehavior,
256}
257
258impl GlBackendOptions {
259    /// Choose OpenGL backend options by calling `from_env` on every field.
260    ///
261    /// See those methods for more information.
262    #[must_use]
263    pub fn from_env_or_default() -> Self {
264        let gles_minor_version = Gles3MinorVersion::from_env().unwrap_or_default();
265        Self {
266            gles_minor_version,
267            fence_behavior: GlFenceBehavior::Normal,
268        }
269    }
270
271    /// Takes the given options, modifies them based on the environment variables, and returns the result.
272    ///
273    /// This is equivalent to calling `with_env` on every field.
274    #[must_use]
275    pub fn with_env(self) -> Self {
276        let gles_minor_version = self.gles_minor_version.with_env();
277        let short_circuit_fences = self.fence_behavior.with_env();
278        Self {
279            gles_minor_version,
280            fence_behavior: short_circuit_fences,
281        }
282    }
283}
284
285/// Configuration for the DX12 backend.
286///
287/// Part of [`BackendOptions`].
288#[derive(Clone, Debug, Default)]
289pub struct Dx12BackendOptions {
290    /// Which DX12 shader compiler to use.
291    pub shader_compiler: Dx12Compiler,
292}
293
294impl Dx12BackendOptions {
295    /// Choose DX12 backend options by calling `from_env` on every field.
296    ///
297    /// See those methods for more information.
298    #[must_use]
299    pub fn from_env_or_default() -> Self {
300        let compiler = Dx12Compiler::from_env().unwrap_or_default();
301        Self {
302            shader_compiler: compiler,
303        }
304    }
305
306    /// Takes the given options, modifies them based on the environment variables, and returns the result.
307    ///
308    /// This is equivalent to calling `with_env` on every field.
309    #[must_use]
310    pub fn with_env(self) -> Self {
311        let shader_compiler = self.shader_compiler.with_env();
312        Self { shader_compiler }
313    }
314}
315
316/// Configuration for the noop backend.
317///
318/// Part of [`BackendOptions`].
319#[derive(Clone, Debug, Default)]
320pub struct NoopBackendOptions {
321    /// Whether to allow the noop backend to be used.
322    ///
323    /// The noop backend stubs out all operations except for buffer creation and mapping, so
324    /// it must not be used when not expected. Therefore, it will not be used unless explicitly
325    /// enabled.
326    pub enable: bool,
327}
328
329impl NoopBackendOptions {
330    /// Choose whether the noop backend is enabled from the environment.
331    ///
332    /// It will be enabled if the environment variable `WGPU_NOOP_BACKEND` has the value `1`
333    /// and not otherwise. Future versions may assign other meanings to other values.
334    #[must_use]
335    pub fn from_env_or_default() -> Self {
336        Self {
337            enable: Self::enable_from_env().unwrap_or(false),
338        }
339    }
340
341    /// Takes the given options, modifies them based on the environment variables, and returns the
342    /// result.
343    ///
344    /// See [`from_env_or_default()`](Self::from_env_or_default) for the interpretation.
345    #[must_use]
346    pub fn with_env(self) -> Self {
347        Self {
348            enable: Self::enable_from_env().unwrap_or(self.enable),
349        }
350    }
351
352    fn enable_from_env() -> Option<bool> {
353        let value = crate::env::var("WGPU_NOOP_BACKEND")?;
354        match value.as_str() {
355            "1" => Some(true),
356            "0" => Some(false),
357            _ => None,
358        }
359    }
360}
361
362/// DXC shader model.
363#[derive(Clone, Debug)]
364#[allow(missing_docs)]
365pub enum DxcShaderModel {
366    V6_0,
367    V6_1,
368    V6_2,
369    V6_3,
370    V6_4,
371    V6_5,
372    V6_6,
373    V6_7,
374}
375
376/// Selects which DX12 shader compiler to use.
377///
378/// If the `DynamicDxc` option is selected, but `dxcompiler.dll` and `dxil.dll` files aren't found,
379/// then this will fall back to the Fxc compiler at runtime and log an error.
380#[derive(Clone, Debug, Default)]
381pub enum Dx12Compiler {
382    /// The Fxc compiler (default) is old, slow and unmaintained.
383    ///
384    /// However, it doesn't require any additional .dlls to be shipped with the application.
385    #[default]
386    Fxc,
387    /// The Dxc compiler is new, fast and maintained.
388    ///
389    /// However, it requires both `dxcompiler.dll` and `dxil.dll` to be shipped with the application.
390    /// These files can be downloaded from <https://github.com/microsoft/DirectXShaderCompiler/releases>.
391    ///
392    /// Minimum supported version: [v1.5.2010](https://github.com/microsoft/DirectXShaderCompiler/releases/tag/v1.5.2010)
393    ///
394    /// It also requires WDDM 2.1 (Windows 10 version 1607).
395    DynamicDxc {
396        /// Path to `dxcompiler.dll`.
397        dxc_path: String,
398        /// Path to `dxil.dll`.
399        dxil_path: String,
400        /// Maximum shader model the given dll supports.
401        max_shader_model: DxcShaderModel,
402    },
403    /// The statically-linked variant of Dxc.
404    ///
405    /// The `static-dxc` feature is required for this setting to be used successfully on DX12.
406    /// Not available on `windows-aarch64-pc-*` targets.
407    StaticDxc,
408}
409
410impl Dx12Compiler {
411    /// Helper function to construct a `DynamicDxc` variant with default paths.
412    ///
413    /// The dll must support at least shader model 6.5.
414    pub fn default_dynamic_dxc() -> Self {
415        Self::DynamicDxc {
416            dxc_path: String::from("dxcompiler.dll"),
417            dxil_path: String::from("dxil.dll"),
418            max_shader_model: DxcShaderModel::V6_5,
419        }
420    }
421
422    /// Choose which DX12 shader compiler to use from the environment variable `WGPU_DX12_COMPILER`.
423    ///
424    /// Valid values, case insensitive:
425    /// - `Fxc`
426    /// - `Dxc` or `DynamicDxc`
427    /// - `StaticDxc`
428    #[must_use]
429    pub fn from_env() -> Option<Self> {
430        let value = crate::env::var("WGPU_DX12_COMPILER")
431            .as_deref()?
432            .to_lowercase();
433        match value.as_str() {
434            "dxc" | "dynamicdxc" => Some(Self::default_dynamic_dxc()),
435            "staticdxc" => Some(Self::StaticDxc),
436            "fxc" => Some(Self::Fxc),
437            _ => None,
438        }
439    }
440
441    /// Takes the given compiler, modifies it based on the `WGPU_DX12_COMPILER` environment variable, and returns the result.
442    ///
443    /// See `from_env` for more information.
444    #[must_use]
445    pub fn with_env(self) -> Self {
446        if let Some(compiler) = Self::from_env() {
447            compiler
448        } else {
449            self
450        }
451    }
452}
453
454/// Selects which OpenGL ES 3 minor version to request.
455///
456/// When using ANGLE as an OpenGL ES/EGL implementation, explicitly requesting `Version1` can provide a non-conformant ES 3.1 on APIs like D3D11.
457#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
458pub enum Gles3MinorVersion {
459    /// No explicit minor version is requested, the driver automatically picks the highest available.
460    #[default]
461    Automatic,
462
463    /// Request an ES 3.0 context.
464    Version0,
465
466    /// Request an ES 3.1 context.
467    Version1,
468
469    /// Request an ES 3.2 context.
470    Version2,
471}
472
473impl Gles3MinorVersion {
474    /// Choose which minor OpenGL ES version to use from the environment variable `WGPU_GLES_MINOR_VERSION`.
475    ///
476    /// Possible values are `0`, `1`, `2` or `automatic`. Case insensitive.
477    ///
478    /// Use with `unwrap_or_default()` to get the default value if the environment variable is not set.
479    #[must_use]
480    pub fn from_env() -> Option<Self> {
481        let value = crate::env::var("WGPU_GLES_MINOR_VERSION")
482            .as_deref()?
483            .to_lowercase();
484        match value.as_str() {
485            "automatic" => Some(Self::Automatic),
486            "0" => Some(Self::Version0),
487            "1" => Some(Self::Version1),
488            "2" => Some(Self::Version2),
489            _ => None,
490        }
491    }
492
493    /// Takes the given compiler, modifies it based on the `WGPU_GLES_MINOR_VERSION` environment variable, and returns the result.
494    ///
495    /// See `from_env` for more information.
496    #[must_use]
497    pub fn with_env(self) -> Self {
498        if let Some(compiler) = Self::from_env() {
499            compiler
500        } else {
501            self
502        }
503    }
504}
505
506/// Dictate the behavior of fences in OpenGL.
507#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
508pub enum GlFenceBehavior {
509    /// Fences in OpenGL behave normally. If you don't know what to pick, this is what you want.
510    #[default]
511    Normal,
512    /// Fences in OpenGL are short-circuited to always return `true` immediately.
513    ///
514    /// This solves a very specific issue that arose due to a bug in wgpu-core that made
515    /// many WebGL programs work when they "shouldn't" have. If you have code that is trying
516    /// to call `device.poll(wgpu::PollType::Wait)` on WebGL, you need to enable this option
517    /// for the "Wait" to behave how you would expect.
518    ///
519    /// Previously all `poll(Wait)` acted like the OpenGL fences were signalled even if they weren't.
520    /// See <https://github.com/gfx-rs/wgpu/issues/4589> for more information.
521    ///
522    /// When this is set `Queue::on_completed_work_done` will always return the next time the device
523    /// is maintained, not when the work is actually done on the GPU.
524    AutoFinish,
525}
526
527impl GlFenceBehavior {
528    /// Returns true if the fence behavior is `AutoFinish`.
529    pub fn is_auto_finish(&self) -> bool {
530        matches!(self, Self::AutoFinish)
531    }
532
533    /// Returns true if the fence behavior is `Normal`.
534    pub fn is_normal(&self) -> bool {
535        matches!(self, Self::Normal)
536    }
537
538    /// Choose which minor OpenGL ES version to use from the environment variable `WGPU_GL_FENCE_BEHAVIOR`.
539    ///
540    /// Possible values are `Normal` or `AutoFinish`. Case insensitive.
541    ///
542    /// Use with `unwrap_or_default()` to get the default value if the environment variable is not set.
543    #[must_use]
544    pub fn from_env() -> Option<Self> {
545        let value = crate::env::var("WGPU_GL_FENCE_BEHAVIOR")
546            .as_deref()?
547            .to_lowercase();
548        match value.as_str() {
549            "normal" => Some(Self::Normal),
550            "autofinish" => Some(Self::AutoFinish),
551            _ => None,
552        }
553    }
554
555    /// Takes the given compiler, modifies it based on the `WGPU_GL_FENCE_BEHAVIOR` environment variable, and returns the result.
556    ///
557    /// See `from_env` for more information.
558    #[must_use]
559    pub fn with_env(self) -> Self {
560        if let Some(fence) = Self::from_env() {
561            fence
562        } else {
563            self
564        }
565    }
566}