Skip to content

Commit 7878d06

Browse files
committed
Add Skip and add a vulkano test to try to debug windows
1 parent 47d80a2 commit 7878d06

File tree

26 files changed

+1218
-130
lines changed

26 files changed

+1218
-130
lines changed

Cargo.lock

Lines changed: 210 additions & 39 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/difftests/README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,18 @@ The library provides helper types for common test patterns:
9999
- `WgpuComputeTestMultiBuffer` - Multi-buffer compute shader test with input/output
100100
separation
101101
- `WgpuComputeTestPushConstant` - Compute shader test with push constants support
102+
- `Skip` - Marks a test variant as skipped with a reason
102103

103104
**Shader source types:**
104105

105106
- `RustComputeShader` - Compiles the current crate as a Rust GPU shader
106107
- `WgslComputeShader` - Loads WGSL shader from file (shader.wgsl or compute.wgsl)
107108

109+
**Backend types:**
110+
111+
- `WgpuBackend` - Default wgpu-based compute backend
112+
- `VulkanoBackend` - Vulkano-based compute backend (useful for testing different GPU drivers)
113+
108114
For examples, see:
109115

110116
- [`tests/lang/core/ops/math_ops/`](tests/lang/core/ops/math_ops/) - Multi-buffer test
@@ -205,6 +211,40 @@ The harness automatically writes human-readable `.txt` files alongside binary ou
205211
For floating-point data (F32/F64), these show the array values in decimal format. For
206212
raw/integer data, these show the values as hex bytes or integers
207213

214+
## Skipping Tests on Specific Platforms
215+
216+
Sometimes a test variant needs to be skipped on certain platforms (e.g., due to driver
217+
issues or platform limitations). The difftest framework provides a clean way to handle
218+
this using the `Skip` scaffolding type:
219+
220+
```rust
221+
use difftest::scaffold::Skip;
222+
223+
fn main() {
224+
let config = Config::from_path(std::env::args().nth(1).unwrap()).unwrap();
225+
226+
// Skip on macOS due to platform-specific issues
227+
#[cfg(target_os = "macos")]
228+
{
229+
let skip = Skip::new("This test is not supported on macOS");
230+
skip.run_test(&config).unwrap();
231+
return;
232+
}
233+
234+
// Run the actual test on other platforms
235+
#[cfg(not(target_os = "macos"))]
236+
{
237+
// ... normal test implementation ...
238+
}
239+
}
240+
```
241+
242+
When a test is skipped:
243+
- The skip reason is recorded in the test metadata
244+
- The test runner logs the skip reason
245+
- The test doesn't contribute to the output comparison
246+
- If all variants are skipped, the test fails with an error
247+
208248
## Harness logs
209249

210250
If you suspect a bug in the test harness, you can view detailed test harness logs:

tests/difftests/bin/src/runner.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,12 @@ impl Runner {
336336
if !metadata_content.trim().is_empty() {
337337
match serde_json::from_str::<TestMetadata>(&metadata_content) {
338338
Ok(metadata) => {
339+
// Check if test was skipped
340+
if let Some(skip_reason) = &metadata.skipped {
341+
info!("Package '{}' was skipped: {}", pkg_name, skip_reason);
342+
continue;
343+
}
344+
339345
if let Some(meta_epsilon) = metadata.epsilon {
340346
epsilon = match epsilon {
341347
Some(e) => Some(e.max(meta_epsilon)),
@@ -390,6 +396,12 @@ impl Runner {
390396
});
391397
}
392398

399+
// Check if we have any valid outputs
400+
if pkg_outputs.is_empty() {
401+
error!("All packages were skipped. At least one package must produce output.");
402+
return Err(RunnerError::EmptyOutput);
403+
}
404+
393405
if pkg_outputs.iter().all(|po| po.output.is_empty()) {
394406
error!("All packages produced empty output.");
395407
return Err(RunnerError::EmptyOutput);

tests/difftests/lib/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ spirv-builder.workspace = true
2020
serde = { version = "1.0", features = ["derive"] }
2121
serde_json = "1.0"
2222
wgpu = { version = "25.0.2", features = ["spirv", "vulkan-portability", "static-dxc"] }
23+
vulkano = { version = "0.35.1", default-features = false }
24+
naga = { version = "25.0.1", features = ["glsl-in", "spv-out"] }
2325
tempfile = "3.5"
2426
futures = "0.3.31"
2527
bytemuck = "1.21.0"

tests/difftests/lib/src/config.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ pub struct TestMetadata {
2727
/// (F32, F64, etc.) to enable epsilon-based comparison for numeric types.
2828
#[serde(default)]
2929
pub output_type: OutputType,
30+
31+
/// If present, indicates this test was skipped with the given reason
32+
#[serde(default, skip_serializing_if = "Option::is_none")]
33+
pub skipped: Option<String>,
3034
}
3135

3236
/// Specifies how test output data should be interpreted for comparison
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use crate::config::Config;
2+
use anyhow::Result;
3+
4+
/// Configuration for a GPU buffer
5+
#[derive(Clone)]
6+
pub struct BufferConfig {
7+
pub size: u64,
8+
pub usage: BufferUsage,
9+
pub initial_data: Option<Vec<u8>>,
10+
}
11+
12+
/// Buffer usage type
13+
#[derive(Clone, Copy, PartialEq)]
14+
pub enum BufferUsage {
15+
Storage,
16+
StorageReadOnly,
17+
Uniform,
18+
}
19+
20+
/// A generic trait for compute backends
21+
pub trait ComputeBackend: Sized {
22+
/// Initialize the backend
23+
fn init() -> Result<Self>;
24+
25+
/// Create and run a compute shader with multiple buffers
26+
fn run_compute(
27+
&self,
28+
spirv_bytes: &[u8],
29+
entry_point: &str,
30+
dispatch: [u32; 3],
31+
buffers: Vec<BufferConfig>,
32+
) -> Result<Vec<Vec<u8>>>;
33+
}
34+
35+
/// A compute test that can run on any backend
36+
pub struct ComputeTest<B: ComputeBackend> {
37+
backend: B,
38+
spirv_bytes: Vec<u8>,
39+
entry_point: String,
40+
dispatch: [u32; 3],
41+
buffers: Vec<BufferConfig>,
42+
}
43+
44+
impl<B: ComputeBackend> ComputeTest<B> {
45+
pub fn new(
46+
spirv_bytes: Vec<u8>,
47+
entry_point: String,
48+
dispatch: [u32; 3],
49+
buffers: Vec<BufferConfig>,
50+
) -> Result<Self> {
51+
Ok(Self {
52+
backend: B::init()?,
53+
spirv_bytes,
54+
entry_point,
55+
dispatch,
56+
buffers,
57+
})
58+
}
59+
60+
pub fn run(self) -> Result<Vec<Vec<u8>>> {
61+
self.backend.run_compute(
62+
&self.spirv_bytes,
63+
&self.entry_point,
64+
self.dispatch,
65+
self.buffers,
66+
)
67+
}
68+
69+
pub fn run_test(self, config: &Config) -> Result<()> {
70+
let buffers = self.buffers.clone();
71+
let outputs = self.run()?;
72+
// Write the first storage buffer output to the file
73+
for (output, buffer_config) in outputs.iter().zip(&buffers) {
74+
if matches!(buffer_config.usage, BufferUsage::Storage) && !output.is_empty() {
75+
use std::fs::File;
76+
use std::io::Write;
77+
let mut f = File::create(&config.output_path)?;
78+
f.write_all(output)?;
79+
return Ok(());
80+
}
81+
}
82+
anyhow::bail!("No storage buffer output found")
83+
}
84+
}
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1+
mod backend;
2+
mod vulkano;
13
mod wgpu;
4+
5+
pub use backend::{BufferConfig, BufferUsage, ComputeBackend, ComputeTest};
6+
pub use vulkano::VulkanoBackend;
27
pub use wgpu::{
3-
BufferConfig, BufferUsage, RustComputeShader, WgpuComputeTest, WgpuComputeTestMultiBuffer,
8+
RustComputeShader, WgpuBackend, WgpuComputeTest, WgpuComputeTestMultiBuffer,
49
WgpuComputeTestPushConstants, WgslComputeShader,
510
};

0 commit comments

Comments
 (0)