1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// SPDX-License-Identifier: MPL-2.0
// SPDX-FileCopyrightText: 2026 FernTech
//! The flags every wgpu instance in this workspace is built with.
//!
//! Two instances exist: the one [`crate::test_support`] opens for offscreen
//! work, and the one `teksilo-platform` opens for windows. They have to agree
//! about this, so the rule lives here, in the crate both can reach, rather
//! than at either call site.
/// The `InstanceFlags` to build a wgpu instance with: wgpu's own defaults,
/// read from the environment, minus `VALIDATION_INDIRECT_CALL`.
///
/// That flag is set in **release** builds too — it comes from
/// `InstanceFlags::from_build_config`'s non-debug branch, so it is not a
/// debug-only cost. It makes `Device::new` build a set of compute and render
/// pipelines that validate the arguments of indirect draws. This renderer
/// issues no indirect draws at all — not one `draw_indirect`,
/// `dispatch_indirect` or `multi_draw_*` anywhere in the workspace — so those
/// pipelines check nothing we will ever submit.
///
/// That alone would only be wasted startup work. The reason the flag is
/// cleared is that building those pipelines is also a way for device creation
/// to *fail*, and failing there is not survivable.
/// `wgpu_core::device::resource::Device::new` creates the hal device, then its
/// `empty_bgl` — which registers a bind-group layout with the Vulkan backend's
/// `DescriptorAllocator` — and only then calls `IndirectValidation::new(..)?`.
/// A driver that cannot build them takes that `?`, and the early return drops
/// the hal device *without* unregistering `empty_bgl`, because hal objects are
/// not RAII and need an explicit destroy. `Drop for DescriptorAllocator` then
/// finds a non-empty bucket and panics — "buckets are not empty, at least one
/// BGL has not been unregistered" — from an ordinary, non-unwinding drop, so
/// its own `thread::panicking()` guard does not suppress it.
///
/// The process therefore dies *inside* `request_device`, and neither caller
/// can do anything about it there: a backend search cannot search past a
/// panic, and an offscreen renderer cannot fall back to a software adapter.
/// Reported from the field on an older Windows 10 machine where an app never
/// opened a window, and confirmed there by setting
/// `WGPU_VALIDATION_INDIRECT_CALL=0`, which let the window open. D3D12 has no
/// `DescriptorAllocator` and never runs the assertion, which is why forcing
/// `WGPU_BACKEND=dx12` looked like a graphics fix when it was really a way of
/// not reaching this code.
///
/// `WGPU_VALIDATION_INDIRECT_CALL` is honoured in both directions, so the flag
/// stays reachable for anyone debugging wgpu itself.
/// [`instance_flags`]'s decision, as a pure function of its two inputs.
///
/// Split out because the alternative is a test that writes a process-wide
/// environment variable: unsafe since the 2024 edition, and racy against every
/// other test in the binary regardless.
///
/// `asked_for` is whether the variable is *present*, not whether it is true.
/// wgpu's `with_env` has already read its value into `base` by this point — it
/// sets the flag for any value but `0`, and clears it for `0` — so all this
/// has to decide is whether the user expressed an opinion at all. Testing the
/// resulting bit instead cannot tell "wgpu's default" from "a developer asked
/// for it", and testing the value again would re-implement `with_env`.