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}