2022-02-03 18:27:21 +00:00
|
|
|
/*!
|
|
|
|
Test SPIR-V backend capability checks.
|
|
|
|
*/
|
2021-08-19 20:03:45 +00:00
|
|
|
|
2024-07-06 08:58:52 +00:00
|
|
|
#![cfg(all(feature = "wgsl-in", spv_out))]
|
2021-08-19 20:03:45 +00:00
|
|
|
|
|
|
|
use spirv::Capability as Ca;
|
|
|
|
|
2023-06-21 20:14:00 +00:00
|
|
|
fn capabilities_used(source: &str) -> naga::FastIndexSet<Ca> {
|
2021-08-19 20:03:45 +00:00
|
|
|
use naga::back::spv;
|
|
|
|
use naga::valid;
|
|
|
|
|
|
|
|
let module = naga::front::wgsl::parse_str(source).unwrap_or_else(|e| {
|
|
|
|
panic!(
|
|
|
|
"expected WGSL to parse successfully:\n{}",
|
|
|
|
e.emit_to_string(source)
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
let info = valid::Validator::new(valid::ValidationFlags::all(), valid::Capabilities::all())
|
|
|
|
.validate(&module)
|
|
|
|
.expect("validation failed");
|
|
|
|
|
|
|
|
let mut words = vec![];
|
|
|
|
let mut writer = spv::Writer::new(&spv::Options::default()).unwrap();
|
2023-06-28 12:30:25 +00:00
|
|
|
writer
|
|
|
|
.write(&module, &info, None, &None, &mut words)
|
|
|
|
.unwrap();
|
2021-08-19 20:03:45 +00:00
|
|
|
writer.get_capabilities_used().clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn require(capabilities: &[Ca], source: &str) {
|
2021-08-28 03:42:11 +00:00
|
|
|
require_and_forbid(capabilities, &[], source);
|
2021-08-19 20:03:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn require_and_forbid(required: &[Ca], forbidden: &[Ca], source: &str) {
|
|
|
|
let caps_used = capabilities_used(source);
|
|
|
|
|
|
|
|
let missing_caps: Vec<_> = required
|
|
|
|
.iter()
|
2023-06-21 20:14:00 +00:00
|
|
|
.filter(|&cap| !caps_used.contains(cap))
|
2021-08-19 20:03:45 +00:00
|
|
|
.cloned()
|
|
|
|
.collect();
|
|
|
|
if !missing_caps.is_empty() {
|
2023-01-31 00:34:04 +00:00
|
|
|
panic!("shader code should have requested these caps: {missing_caps:?}\n\n{source}");
|
2021-08-19 20:03:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let forbidden_caps: Vec<_> = forbidden
|
|
|
|
.iter()
|
2023-06-21 20:14:00 +00:00
|
|
|
.filter(|&cap| caps_used.contains(cap))
|
2021-08-19 20:03:45 +00:00
|
|
|
.cloned()
|
|
|
|
.collect();
|
|
|
|
if !forbidden_caps.is_empty() {
|
2023-01-31 00:34:04 +00:00
|
|
|
panic!("shader code should not have requested these caps: {forbidden_caps:?}\n\n{source}");
|
2021-08-19 20:03:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn sampler1d() {
|
|
|
|
require(
|
|
|
|
&[Ca::Sampled1D],
|
|
|
|
r#"
|
2022-01-19 15:33:06 +00:00
|
|
|
@group(0) @binding(0)
|
2021-08-19 20:03:45 +00:00
|
|
|
var image_1d: texture_1d<f32>;
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn storage1d() {
|
|
|
|
require(
|
|
|
|
&[Ca::Image1D],
|
|
|
|
r#"
|
2022-01-19 15:33:06 +00:00
|
|
|
@group(0) @binding(0)
|
2021-08-19 20:03:45 +00:00
|
|
|
var image_1d: texture_storage_1d<rgba8unorm,write>;
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn cube_array() {
|
|
|
|
// ImageCubeArray is only for storage cube array images, which WGSL doesn't
|
|
|
|
// support
|
|
|
|
require_and_forbid(
|
|
|
|
&[Ca::SampledCubeArray],
|
|
|
|
&[Ca::ImageCubeArray],
|
|
|
|
r#"
|
2022-01-19 15:33:06 +00:00
|
|
|
@group(0) @binding(0)
|
2021-08-19 20:03:45 +00:00
|
|
|
var image_cube: texture_cube_array<f32>;
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn image_queries() {
|
|
|
|
require(
|
|
|
|
&[Ca::ImageQuery],
|
|
|
|
r#"
|
2023-02-13 13:13:58 +00:00
|
|
|
fn f(i: texture_2d<f32>) -> vec2<u32> {
|
2021-08-19 20:03:45 +00:00
|
|
|
return textureDimensions(i);
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
require(
|
|
|
|
&[Ca::ImageQuery],
|
|
|
|
r#"
|
2023-02-13 13:13:58 +00:00
|
|
|
fn f(i: texture_2d_array<f32>) -> u32 {
|
2021-08-19 20:03:45 +00:00
|
|
|
return textureNumLayers(i);
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
require(
|
|
|
|
&[Ca::ImageQuery],
|
|
|
|
r#"
|
2023-02-13 13:13:58 +00:00
|
|
|
fn f(i: texture_2d<f32>) -> u32 {
|
2021-08-19 20:03:45 +00:00
|
|
|
return textureNumLevels(i);
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
require(
|
|
|
|
&[Ca::ImageQuery],
|
|
|
|
r#"
|
2023-02-13 13:13:58 +00:00
|
|
|
fn f(i: texture_multisampled_2d<f32>) -> u32 {
|
2021-08-19 20:03:45 +00:00
|
|
|
return textureNumSamples(i);
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn sample_rate_shading() {
|
|
|
|
require(
|
|
|
|
&[Ca::SampleRateShading],
|
|
|
|
r#"
|
2022-04-15 09:54:15 +00:00
|
|
|
@fragment
|
2022-01-19 15:33:06 +00:00
|
|
|
fn f(@location(0) @interpolate(perspective, sample) x: f32) { }
|
2021-08-19 20:03:45 +00:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
|
|
|
|
require(
|
|
|
|
&[Ca::SampleRateShading],
|
|
|
|
r#"
|
2022-04-15 09:54:15 +00:00
|
|
|
@fragment
|
2022-01-19 15:33:06 +00:00
|
|
|
fn f(@builtin(sample_index) x: u32) { }
|
2021-08-19 20:03:45 +00:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn geometry() {
|
|
|
|
require(
|
|
|
|
&[Ca::Geometry],
|
|
|
|
r#"
|
2022-04-15 09:54:15 +00:00
|
|
|
@fragment
|
2022-01-19 15:33:06 +00:00
|
|
|
fn f(@builtin(primitive_index) x: u32) { }
|
2021-08-19 20:03:45 +00:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
2021-08-28 03:42:11 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn storage_image_formats() {
|
|
|
|
require_and_forbid(
|
|
|
|
&[Ca::Shader],
|
|
|
|
&[Ca::StorageImageExtendedFormats],
|
|
|
|
r#"
|
2022-01-19 15:33:06 +00:00
|
|
|
@group(0) @binding(0)
|
2021-08-28 03:42:11 +00:00
|
|
|
var image_rg32f: texture_storage_2d<rgba16uint, read>;
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
|
|
|
|
require(
|
|
|
|
&[Ca::StorageImageExtendedFormats],
|
|
|
|
r#"
|
2022-01-19 15:33:06 +00:00
|
|
|
@group(0) @binding(0)
|
2021-08-28 03:42:11 +00:00
|
|
|
var image_rg32f: texture_storage_2d<rg32float, read>;
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
2024-03-12 11:34:06 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn float64() {
|
|
|
|
require(
|
|
|
|
&[Ca::Float64],
|
|
|
|
r#"
|
|
|
|
fn f(x: f64) -> f64 {
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn int64() {
|
|
|
|
require(
|
|
|
|
&[Ca::Int64],
|
|
|
|
r#"
|
|
|
|
fn f(x: i64) -> i64 {
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
require(
|
|
|
|
&[Ca::Int64],
|
|
|
|
r#"
|
|
|
|
fn f(x: u64) -> u64 {
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|