compatdb_core/value.rs
1//! The values of the settings that choose between implementations: the
2//! Direct3D trees, the wined3d renderer and the Mac driver's OpenGL.
3
4use std::{fmt, str::FromStr};
5
6use crate::{EnvEntry, FieldError, Key};
7
8/// Which implementation of the DXGI family a process loads.
9///
10/// D3D10, D3D10.1, D3D11 and D3D12 travel together because they all create
11/// their device through one `dxgi.dll`, and each implementation's modules only
12/// work with its own.
13#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
14pub enum Dxgi {
15 /// DXMT, which a built-in rule gives every program.
16 Dxmt,
17 /// Wine's own wined3d, what upstream Wine loads, and so what a process
18 /// gets when no rule names an implementation.
19 Wined3d,
20}
21
22impl Dxgi {
23 /// Every implementation.
24 pub const ALL: &'static [Self] = &[Self::Dxmt, Self::Wined3d];
25
26 /// The wire spelling, which is also the `lib/wine/dxgi/<name>` tree.
27 #[must_use]
28 pub const fn as_str(self) -> &'static str {
29 match self {
30 Self::Dxmt => "dxmt",
31 Self::Wined3d => "wined3d",
32 }
33 }
34}
35
36/// Which D3D9 implementation a process loads. Independent of [`Dxgi`]: neither
37/// implementation's `d3d9.dll` touches `dxgi.dll`.
38#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
39pub enum D3d9 {
40 /// mtld3d, which a built-in rule gives every program.
41 Mtld3d,
42 /// Wine's own wined3d, what upstream Wine loads, and so what a process
43 /// gets when no rule names an implementation.
44 Wined3d,
45}
46
47impl D3d9 {
48 /// Every implementation.
49 pub const ALL: &'static [Self] = &[Self::Mtld3d, Self::Wined3d];
50
51 /// The wire spelling, which is also the `lib/wine/d3d9/<name>` tree.
52 #[must_use]
53 pub const fn as_str(self) -> &'static str {
54 match self {
55 Self::Mtld3d => "mtld3d",
56 Self::Wined3d => "wined3d",
57 }
58 }
59}
60
61/// Which renderer wined3d, Wine's own Direct3D, draws with in a process.
62///
63/// One `wined3d.dll` serves every wined3d user in a process (the wined3d trees
64/// of [`Dxgi`] and [`D3d9`], D3D8 and `DirectDraw`), and it reads its settings
65/// once, so this is a setting of the process, not of a family. It chooses no
66/// tree: [`Dxgi`] and [`D3d9`] still decide whether wined3d is used at all.
67#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
68pub enum Wined3d {
69 /// OpenGL, wined3d's own default.
70 Gl,
71 /// Vulkan, on the bundle's `KosmicKrisp`.
72 Vulkan,
73}
74
75impl Wined3d {
76 /// The environment variable wined3d reads its settings from, a list of
77 /// `name=value` options.
78 pub const CONFIG_VAR: &'static str = "WINE_D3D_CONFIG";
79
80 /// Every renderer.
81 pub const ALL: &'static [Self] = &[Self::Gl, Self::Vulkan];
82
83 /// The wire spelling, which is also the value of wined3d's `renderer`
84 /// option.
85 #[must_use]
86 pub const fn as_str(self) -> &'static str {
87 match self {
88 Self::Gl => "gl",
89 Self::Vulkan => "vulkan",
90 }
91 }
92}
93
94/// Which OpenGL the Mac driver gives a process.
95///
96/// The value is the process's own: ntdll stores it for winemac.drv, which
97/// reads it when OpenGL is first initialized, so a program does not take the
98/// choice of the program that started it.
99#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
100pub enum OpenGl {
101 /// Mesa's EGL, with Zink on `KosmicKrisp`. Without a GPU `KosmicKrisp`
102 /// can use, the process gets no OpenGL.
103 Egl,
104 /// Apple's OpenGL, upstream Wine's.
105 Cgl,
106}
107
108impl OpenGl {
109 /// Every OpenGL.
110 pub const ALL: &'static [Self] = &[Self::Egl, Self::Cgl];
111
112 /// The wire spelling.
113 #[must_use]
114 pub const fn as_str(self) -> &'static str {
115 match self {
116 Self::Egl => "egl",
117 Self::Cgl => "cgl",
118 }
119 }
120}
121
122/// The variables that show the Metal performance HUD, each with the value
123/// that `metal_hud` set to `true` gives it.
124pub const METAL_HUD_ENV: [(&str, &str); 3] = [
125 ("MTL_HUD_ENABLED", "1"),
126 ("MTL_HUD_ALIGNMENT", "28"),
127 (
128 "MTL_HUD_ELEMENTS",
129 "device,rosetta,layersize,memory,fps,frameinterval,shaders,frameintervalgraph,gputime,\
130 thermal,layerscale,refreshrate,gamemode,client",
131 ),
132];
133
134/// The environment entries `metal_hud` stands for.
135///
136/// With `on`, each variable of [`METAL_HUD_ENV`] is set to its value, and
137/// otherwise each of them is removed, so a process does not show the HUD
138/// that the process which started it asked for.
139#[must_use]
140pub fn metal_hud_env(on: bool) -> Vec<EnvEntry> {
141 METAL_HUD_ENV
142 .iter()
143 .map(|&(name, value)| EnvEntry::literal(name, if on { value } else { "" }))
144 .collect()
145}
146
147/// The value of `all` that `name` spells `s`, ASCII-case-insensitively, or
148/// the error for the setting `key`, whose spellings without `default` are
149/// the ones it lists.
150fn parse_word<T: Copy>(
151 key: Key,
152 all: &[T],
153 name: fn(T) -> &'static str,
154 s: &str,
155) -> Result<T, FieldError> {
156 all.iter()
157 .copied()
158 .find(|value| name(*value).eq_ignore_ascii_case(s))
159 .ok_or_else(|| FieldError::BadValue {
160 key,
161 value: s.to_owned(),
162 expected: key
163 .values()
164 .split_last()
165 .map_or(&[], |(_default, words)| words),
166 })
167}
168
169impl FromStr for Dxgi {
170 type Err = FieldError;
171
172 /// The implementation spelled `s`, ASCII-case-insensitively.
173 fn from_str(s: &str) -> Result<Self, Self::Err> {
174 parse_word(Key::Dxgi, Self::ALL, Self::as_str, s)
175 }
176}
177
178impl FromStr for D3d9 {
179 type Err = FieldError;
180
181 /// The implementation spelled `s`, ASCII-case-insensitively.
182 fn from_str(s: &str) -> Result<Self, Self::Err> {
183 parse_word(Key::D3d9, Self::ALL, Self::as_str, s)
184 }
185}
186
187impl FromStr for Wined3d {
188 type Err = FieldError;
189
190 /// The renderer spelled `s`, ASCII-case-insensitively.
191 fn from_str(s: &str) -> Result<Self, Self::Err> {
192 parse_word(Key::Wined3d, Self::ALL, Self::as_str, s)
193 }
194}
195
196impl FromStr for OpenGl {
197 type Err = FieldError;
198
199 /// The OpenGL spelled `s`, ASCII-case-insensitively.
200 fn from_str(s: &str) -> Result<Self, Self::Err> {
201 parse_word(Key::OpenGl, Self::ALL, Self::as_str, s)
202 }
203}
204
205impl fmt::Display for Dxgi {
206 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207 f.write_str(self.as_str())
208 }
209}
210
211impl fmt::Display for D3d9 {
212 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213 f.write_str(self.as_str())
214 }
215}
216
217impl fmt::Display for Wined3d {
218 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219 f.write_str(self.as_str())
220 }
221}
222
223impl fmt::Display for OpenGl {
224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225 f.write_str(self.as_str())
226 }
227}
228
229#[cfg(test)]
230mod tests;