Skip to main content

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;