Coverage Report

Created: 2025-11-11 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/av-scenechange-0.14.1/src/cpu.rs
Line
Count
Source
1
#[cfg(asm_neon)]
2
pub use neon::*;
3
#[cfg(not(any(asm_x86_64, asm_neon)))]
4
pub use rust::*;
5
#[cfg(asm_x86_64)]
6
pub use x86::*;
7
8
#[cfg(not(any(asm_x86_64, asm_neon)))]
9
mod rust {
10
    use arg_enum_proc_macro::ArgEnum;
11
12
0
    #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, ArgEnum, Default)]
13
    #[allow(clippy::upper_case_acronyms)]
14
15
    pub enum CpuFeatureLevel {
16
        #[default]
17
        RUST,
18
    }
19
20
    impl CpuFeatureLevel {
21
        #[cfg(test)]
22
        #[allow(unused)]
23
        #[inline]
24
        pub const fn all() -> &'static [Self] {
25
            use CpuFeatureLevel::*;
26
            &[RUST]
27
        }
28
    }
29
}
30
31
#[cfg(asm_x86_64)]
32
#[macro_use]
33
mod x86 {
34
    use std::{env, str::FromStr};
35
36
    use arg_enum_proc_macro::ArgEnum;
37
38
    #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, ArgEnum)]
39
    #[allow(clippy::upper_case_acronyms)]
40
    pub enum CpuFeatureLevel {
41
        RUST,
42
        SSE2,
43
        SSSE3,
44
        #[arg_enum(alias = "sse4.1")]
45
        SSE4_1,
46
        AVX2,
47
        AVX512,
48
        #[arg_enum(alias = "avx512vpclmulqdq")]
49
        AVX512ICL,
50
    }
51
52
    impl CpuFeatureLevel {
53
        #[cfg(test)]
54
        pub const fn all() -> &'static [Self] {
55
            &[
56
                CpuFeatureLevel::RUST,
57
                CpuFeatureLevel::SSE2,
58
                CpuFeatureLevel::SSSE3,
59
                CpuFeatureLevel::SSE4_1,
60
                CpuFeatureLevel::AVX2,
61
                CpuFeatureLevel::AVX512,
62
                CpuFeatureLevel::AVX512ICL,
63
            ]
64
        }
65
66
        #[inline]
67
        pub const fn len() -> usize {
68
            CpuFeatureLevel::AVX512ICL as usize + 1
69
        }
70
71
        #[inline]
72
        pub const fn as_index(self) -> usize {
73
            self as usize
74
        }
75
    }
76
77
    impl Default for CpuFeatureLevel {
78
        #[inline]
79
        fn default() -> CpuFeatureLevel {
80
            fn avx512_detected() -> bool {
81
                is_x86_feature_detected!("avx512bw")
82
                    && is_x86_feature_detected!("avx512cd")
83
                    && is_x86_feature_detected!("avx512dq")
84
                    && is_x86_feature_detected!("avx512f")
85
                    && is_x86_feature_detected!("avx512vl")
86
            }
87
            #[allow(deprecated)] // Until MSRV >= 1.69.0
88
            fn avx512icl_detected() -> bool {
89
                // Per dav1d, these are the flags needed.
90
                avx512_detected()
91
                    && is_x86_feature_detected!("avx512vnni")
92
                    && is_x86_feature_detected!("avx512ifma")
93
                    && is_x86_feature_detected!("avx512vbmi")
94
                    && is_x86_feature_detected!("avx512vbmi2")
95
                    && is_x86_feature_detected!("avx512vpopcntdq")
96
                    && is_x86_feature_detected!("avx512bitalg")
97
                    && is_x86_feature_detected!("avx512gfni")
98
                    && is_x86_feature_detected!("avx512vaes")
99
                    && is_x86_feature_detected!("avx512vpclmulqdq")
100
            }
101
102
            let detected: CpuFeatureLevel = if avx512icl_detected() {
103
                CpuFeatureLevel::AVX512ICL
104
            } else if avx512_detected() {
105
                CpuFeatureLevel::AVX512
106
            } else if is_x86_feature_detected!("avx2") {
107
                CpuFeatureLevel::AVX2
108
            } else if is_x86_feature_detected!("sse4.1") {
109
                CpuFeatureLevel::SSE4_1
110
            } else if is_x86_feature_detected!("ssse3") {
111
                CpuFeatureLevel::SSSE3
112
            } else if is_x86_feature_detected!("sse2") {
113
                CpuFeatureLevel::SSE2
114
            } else {
115
                CpuFeatureLevel::RUST
116
            };
117
            let manual: CpuFeatureLevel = match env::var("CPU_TARGET") {
118
                Ok(feature) => CpuFeatureLevel::from_str(&feature).unwrap_or(detected),
119
                Err(_e) => detected,
120
            };
121
            if manual > detected {
122
                detected
123
            } else {
124
                manual
125
            }
126
        }
127
    }
128
129
    // Create a static lookup table for CPUFeatureLevel enums
130
    // Note: keys are CpuFeatureLevels without any prefix (no CpuFeatureLevel::)
131
    macro_rules! cpu_function_lookup_table {
132
        // version for default visibility
133
        ($name:ident: [$type:ty], default: $empty:expr, [$(($key:ident, $value:expr)),*]) => {
134
            static $name: [$type; crate::cpu::CpuFeatureLevel::len()] = {
135
            use crate::cpu::CpuFeatureLevel;
136
            #[allow(unused_mut)]
137
            let mut out: [$type; CpuFeatureLevel::len()] = [$empty; CpuFeatureLevel::len()];
138
139
            // Can't use out[0][.] == $empty in static as of rust 1.40
140
            #[allow(unused_mut)]
141
            let mut set: [bool; CpuFeatureLevel::len()] = [false; CpuFeatureLevel::len()];
142
143
            #[allow(unused_imports)]
144
            use CpuFeatureLevel::*;
145
            $(
146
                out[$key as usize] = $value;
147
                set[$key as usize] = true;
148
            )*
149
            cpu_function_lookup_table!(waterfall_cpu_features(out, set, [SSE2, SSSE3, SSE4_1, AVX2, AVX512, AVX512ICL]));
150
            out
151
            };
152
        };
153
        ($pub:vis, $name:ident: [$type:ty], default: $empty:expr, [$(($key:ident, $value:expr)),*]) => {
154
            $pub cpu_function_lookup_table!($name: [$type], default: $empty, [$(($key, $value)),*]);
155
        };
156
157
        // Fill empty output functions with the existent functions they support.
158
        // cpus should be in order of lowest cpu level to highest
159
        // Used like an internal function
160
        // Put in here to avoid adding more public macros
161
        (waterfall_cpu_features($out:ident, $set:ident, [$($cpu:ident),*])) => {
162
            // Use an array to emulate if statements (not supported in static as of
163
            // rust 1.40). Setting best[0] (false) and best[1] (true) is equivalent to
164
            // doing nothing and overriding our value respectively.
165
            #[allow(unused_assignments)]
166
            let mut best = [$out[0], $out[0]];
167
            $(
168
            // If the current entry has a function, update out best function.
169
            best[$set[$cpu as usize] as usize] = $out[$cpu as usize];
170
            // Update our current entry. Does nothing if it already had a function.
171
            $out[$cpu as usize] = best[1];
172
            )*
173
        };
174
175
        // use $name_$key as our values
176
        ($pub:vis, $name:ident: [$type:ty], default: $empty:expr, [$($key:ident),*]) => {
177
            pastey::item!{
178
                cpu_function_lookup_table!(
179
                    $pub, $name: [$type], default: $empty, [$(($key, [<$name _$key>])),*]
180
                );
181
            }
182
        };
183
184
        // version for default visibility
185
        ($name:ident: [$type:ty], default: $empty:expr, [$($key:ident),*]) => {
186
            pastey::item!{
187
                cpu_function_lookup_table!(
188
                    $name: [$type], default: $empty, [$(($key, [<$name _$key>])),*]
189
                );
190
            }
191
        };
192
    }
193
}
194
195
#[cfg(asm_neon)]
196
#[macro_use]
197
mod neon {
198
    use std::{env, str::FromStr};
199
200
    use arg_enum_proc_macro::ArgEnum;
201
202
    #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, ArgEnum)]
203
    #[allow(clippy::upper_case_acronyms)]
204
    pub enum CpuFeatureLevel {
205
        RUST,
206
        NEON,
207
    }
208
209
    impl CpuFeatureLevel {
210
        #[cfg(test)]
211
        #[inline]
212
        pub const fn all() -> &'static [Self] {
213
            use CpuFeatureLevel::*;
214
            &[RUST, NEON]
215
        }
216
217
        #[inline]
218
        pub const fn len() -> usize {
219
            CpuFeatureLevel::NEON as usize + 1
220
        }
221
222
        #[inline]
223
        pub fn as_index(self) -> usize {
224
            self as usize
225
        }
226
    }
227
228
    impl Default for CpuFeatureLevel {
229
        #[inline]
230
        fn default() -> CpuFeatureLevel {
231
            let detected = CpuFeatureLevel::NEON;
232
            let manual: CpuFeatureLevel = match env::var("CPU_TARGET") {
233
                Ok(feature) => CpuFeatureLevel::from_str(&feature).unwrap_or(detected),
234
                Err(_e) => detected,
235
            };
236
            if manual > detected {
237
                detected
238
            } else {
239
                manual
240
            }
241
        }
242
    }
243
244
    // Create a static lookup table for CPUFeatureLevel enums
245
    // Note: keys are CpuFeatureLevels without any prefix (no CpuFeatureLevel::)
246
    macro_rules! cpu_function_lookup_table {
247
        // version for default visibility
248
        ($name:ident: [$type:ty], default: $empty:expr, [$(($key:ident, $value:expr)),*]) => {
249
            static $name: [$type; crate::cpu::CpuFeatureLevel::len()] = {
250
            use crate::cpu::CpuFeatureLevel;
251
            #[allow(unused_mut)]
252
            let mut out: [$type; CpuFeatureLevel::len()] = [$empty; CpuFeatureLevel::len()];
253
254
            // Can't use out[0][.] == $empty in static as of rust 1.40
255
            #[allow(unused_mut)]
256
            let mut set: [bool; CpuFeatureLevel::len()] = [false; CpuFeatureLevel::len()];
257
258
            #[allow(unused_imports)]
259
            use CpuFeatureLevel::*;
260
            $(
261
                out[$key as usize] = $value;
262
                set[$key as usize] = true;
263
            )*
264
            cpu_function_lookup_table!(waterfall_cpu_features(out, set, [NEON]));
265
            out
266
            };
267
        };
268
269
        ($pub:vis, $name:ident: [$type:ty], default: $empty:expr, [$(($key:ident, $value:expr)),*]) => {
270
            $pub cpu_function_lookup_table!($name: [$type], default: $empty, [$(($key, $value)),*]);
271
        };
272
        // Fill empty output functions with the existent functions they support.
273
        // cpus should be in order of lowest cpu level to highest
274
        // Used like an internal function
275
        // Put in here to avoid adding more public macros
276
        (waterfall_cpu_features($out:ident, $set:ident, [$($cpu:ident),*])) => {
277
            // Use an array to emulate if statements (not supported in static as of
278
            // rust 1.40). Setting best[0] (false) and best[1] (true) is equivalent to
279
            // doing nothing and overriding our value respectively.
280
            #[allow(unused_assignments)]
281
            let mut best = [$out[0], $out[0]];
282
            $(
283
            // If the current entry has a function, update out best function.
284
            best[$set[$cpu as usize] as usize] = $out[$cpu as usize];
285
            // Update our current entry. Does nothing if it already had a function.
286
            $out[$cpu as usize] = best[1];
287
            )*
288
        };
289
290
291
        // use $name_$key as our values
292
        ($pub:vis, $name:ident: [$type:ty], default: $empty:expr, [$($key:ident),*]) => {
293
            pastey::item!{
294
            cpu_function_lookup_table!(
295
                $pub, $name: [$type], default: $empty, [$(($key, [<$name _$key>])),*]
296
            );
297
            }
298
        };
299
300
        // version for default visibility
301
        ($name:ident: [$type:ty], default: $empty:expr, [$($key:ident),*]) => {
302
            pastey::item!{
303
            cpu_function_lookup_table!(
304
                $name: [$type], default: $empty, [$(($key, [<$name _$key>])),*]
305
            );
306
            }
307
        };
308
    }
309
}