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