1#![cfg(not(target_arch = "wasm32"))]
2use std::{future::Future, pin::Pin};
7
8use parking_lot::Mutex;
9
10use crate::{
11 config::GpuTestConfiguration, params::TestInfo, report::AdapterReport, run::execute_test,
12 GpuTestInitializer,
13};
14
15type NativeTestFuture = Pin<Box<dyn Future<Output = ()> + Send>>;
16
17struct NativeTest {
18 name: String,
19 future: NativeTestFuture,
20}
21
22impl NativeTest {
23 fn from_configuration(
25 config: GpuTestConfiguration,
26 adapter_report: AdapterReport,
27 adapter_index: usize,
28 ) -> Self {
29 let device_name = &adapter_report.info.name;
30 let backend = adapter_report.info.backend;
31 let driver = &adapter_report.info.driver;
32 let report_driver_as_backend = [
33 (wgpu::Backend::Vulkan, "MoltenVK"),
34 (wgpu::Backend::Vulkan, "KosmicKrisp"),
35 ];
36 let backend_str = if report_driver_as_backend.contains(&(backend, driver.as_ref())) {
37 driver.clone()
38 } else {
39 format!("{backend:?}")
40 };
41
42 let test_info = TestInfo::from_configuration(&config, &adapter_report);
43
44 let full_name = format!(
45 "[{running_msg}] [{backend_str}/{device_name}/{adapter_index}] {base_name}",
46 running_msg = test_info.running_msg,
47 base_name = config.name,
48 );
49 Self {
50 name: full_name,
51 future: Box::pin(async move {
52 let metal_validation = backend == wgpu::Backend::Metal;
62
63 let env_value = if metal_validation { "1" } else { "0" };
64 std::env::set_var("MTL_DEBUG_LAYER", env_value);
65 if std::env::var("GITHUB_ACTIONS").as_deref() != Ok("true")
66 && !config.params.disable_mtl_shader_validation
67 {
68 std::env::set_var("MTL_SHADER_VALIDATION", env_value);
70 } else if config.params.disable_mtl_shader_validation {
71 std::env::set_var("MTL_SHADER_VALIDATION", "0");
74 }
75
76 execute_test(Some(&adapter_report), config, Some(test_info)).await;
77 }),
78 }
79 }
80
81 pub fn into_trial(self) -> libtest_mimic::Trial {
82 libtest_mimic::Trial::test(self.name, || {
83 pollster::block_on(self.future);
84 Ok(())
85 })
86 }
87}
88
89#[doc(hidden)]
90pub static TEST_LIST: Mutex<Vec<crate::GpuTestConfiguration>> = Mutex::new(Vec::new());
91
92pub type MainResult = anyhow::Result<()>;
94
95pub fn main(tests: Vec<GpuTestInitializer>) -> MainResult {
97 use anyhow::Context;
98
99 use crate::report::GpuReport;
100
101 let use_noop = std::env::var("WGPU_GPU_TESTS_USE_NOOP_BACKEND").as_deref() == Ok("1");
105
106 let report = if use_noop {
107 GpuReport::noop_only()
108 } else {
109 let config_text = {
110 profiling::scope!("Reading .gpuconfig");
111 &std::fs::read_to_string(format!("{}/../.gpuconfig", env!("CARGO_MANIFEST_DIR")))
112 .context(
113 "Failed to read .gpuconfig, did you run the tests via `cargo xtask test`?",
114 )?
115 };
116 let mut report =
117 GpuReport::from_json(config_text).context("Could not parse .gpuconfig JSON")?;
118
119 let wgpu_backends = wgpu::Backends::from_env().unwrap_or_default();
121 report
122 .devices
123 .retain(|report| wgpu_backends.contains(wgpu::Backends::from(report.info.backend)));
124
125 report
126 };
127
128 execute_native(tests.into_iter().flat_map(|initializer| {
130 let test = initializer();
131 report
132 .devices
133 .iter()
134 .enumerate()
135 .map(move |(adapter_index, adapter_report)| {
136 NativeTest::from_configuration(test.clone(), adapter_report.clone(), adapter_index)
137 })
138 }));
139
140 Ok(())
141}
142
143fn execute_native(tests: impl IntoIterator<Item = NativeTest>) {
144 let args = libtest_mimic::Arguments::from_args();
145 let trials = {
146 profiling::scope!("collecting tests");
147 tests.into_iter().map(NativeTest::into_trial).collect()
148 };
149
150 libtest_mimic::run(&args, trials).exit_if_failed();
151}