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 std::env::set_var("MTL_SHADER_VALIDATION", env_value);
68 }
69
70 execute_test(Some(&adapter_report), config, Some(test_info)).await;
71 }),
72 }
73 }
74
75 pub fn into_trial(self) -> libtest_mimic::Trial {
76 libtest_mimic::Trial::test(self.name, || {
77 pollster::block_on(self.future);
78 Ok(())
79 })
80 }
81}
82
83#[doc(hidden)]
84pub static TEST_LIST: Mutex<Vec<crate::GpuTestConfiguration>> = Mutex::new(Vec::new());
85
86pub type MainResult = anyhow::Result<()>;
88
89pub fn main(tests: Vec<GpuTestInitializer>) -> MainResult {
91 use anyhow::Context;
92
93 use crate::report::GpuReport;
94
95 let use_noop = std::env::var("WGPU_GPU_TESTS_USE_NOOP_BACKEND").as_deref() == Ok("1");
99
100 let report = if use_noop {
101 GpuReport::noop_only()
102 } else {
103 let config_text = {
104 profiling::scope!("Reading .gpuconfig");
105 &std::fs::read_to_string(format!("{}/../.gpuconfig", env!("CARGO_MANIFEST_DIR")))
106 .context(
107 "Failed to read .gpuconfig, did you run the tests via `cargo xtask test`?",
108 )?
109 };
110 let mut report =
111 GpuReport::from_json(config_text).context("Could not parse .gpuconfig JSON")?;
112
113 let wgpu_backends = wgpu::Backends::from_env().unwrap_or_default();
115 report
116 .devices
117 .retain(|report| wgpu_backends.contains(wgpu::Backends::from(report.info.backend)));
118
119 report
120 };
121
122 execute_native(tests.into_iter().flat_map(|initializer| {
124 let test = initializer();
125 report
126 .devices
127 .iter()
128 .enumerate()
129 .map(move |(adapter_index, adapter_report)| {
130 NativeTest::from_configuration(test.clone(), adapter_report.clone(), adapter_index)
131 })
132 }));
133
134 Ok(())
135}
136
137fn execute_native(tests: impl IntoIterator<Item = NativeTest>) {
138 let args = libtest_mimic::Arguments::from_args();
139 let trials = {
140 profiling::scope!("collecting tests");
141 tests.into_iter().map(NativeTest::into_trial).collect()
142 };
143
144 libtest_mimic::run(&args, trials).exit_if_failed();
145}