2020-12-13 06:20:39 +00:00
|
|
|
bitflags::bitflags! {
|
|
|
|
struct Language: u32 {
|
|
|
|
const SPIRV = 0x1;
|
|
|
|
const METAL = 0x2;
|
|
|
|
const GLSL = 0x4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-11 14:56:10 +00:00
|
|
|
#[derive(Hash, PartialEq, Eq, serde::Deserialize)]
|
2020-12-08 05:23:29 +00:00
|
|
|
enum Stage {
|
|
|
|
Vertex,
|
|
|
|
Fragment,
|
|
|
|
Compute,
|
|
|
|
}
|
|
|
|
|
2020-12-11 14:56:10 +00:00
|
|
|
#[derive(Hash, PartialEq, Eq, serde::Deserialize)]
|
2020-12-08 05:23:29 +00:00
|
|
|
struct BindSource {
|
|
|
|
stage: Stage,
|
|
|
|
group: u32,
|
|
|
|
binding: u32,
|
|
|
|
}
|
|
|
|
|
2020-12-11 14:56:10 +00:00
|
|
|
#[derive(serde::Deserialize)]
|
2020-12-08 05:23:29 +00:00
|
|
|
struct BindTarget {
|
2020-12-11 06:45:28 +00:00
|
|
|
#[cfg_attr(not(feature = "msl-out"), allow(dead_code))]
|
2020-12-08 05:23:29 +00:00
|
|
|
#[serde(default)]
|
|
|
|
buffer: Option<u8>,
|
2020-12-11 06:45:28 +00:00
|
|
|
#[cfg_attr(not(feature = "msl-out"), allow(dead_code))]
|
2020-12-08 05:23:29 +00:00
|
|
|
#[serde(default)]
|
|
|
|
texture: Option<u8>,
|
2020-12-11 06:45:28 +00:00
|
|
|
#[cfg_attr(not(feature = "msl-out"), allow(dead_code))]
|
2020-12-08 05:23:29 +00:00
|
|
|
#[serde(default)]
|
|
|
|
sampler: Option<u8>,
|
2020-12-11 06:45:28 +00:00
|
|
|
#[cfg_attr(not(feature = "msl-out"), allow(dead_code))]
|
2020-12-08 05:23:29 +00:00
|
|
|
#[serde(default)]
|
|
|
|
mutable: bool,
|
|
|
|
}
|
|
|
|
|
2020-12-11 14:56:10 +00:00
|
|
|
#[derive(Default, serde::Deserialize)]
|
2020-12-08 05:23:29 +00:00
|
|
|
struct Parameters {
|
|
|
|
#[serde(default)]
|
2020-12-10 14:43:42 +00:00
|
|
|
#[allow(dead_code)]
|
2020-12-08 05:23:29 +00:00
|
|
|
spv_flow_dump_prefix: String,
|
|
|
|
#[cfg_attr(not(feature = "spv-out"), allow(dead_code))]
|
2021-02-14 05:37:54 +00:00
|
|
|
spv_version: (u8, u8),
|
|
|
|
#[cfg_attr(not(feature = "spv-out"), allow(dead_code))]
|
2020-12-08 05:23:29 +00:00
|
|
|
spv_capabilities: naga::FastHashSet<spirv::Capability>,
|
|
|
|
#[cfg_attr(not(feature = "msl-out"), allow(dead_code))]
|
|
|
|
mtl_bindings: naga::FastHashMap<BindSource, BindTarget>,
|
|
|
|
}
|
|
|
|
|
2021-02-07 23:01:58 +00:00
|
|
|
fn with_snapshot_settings<F: FnOnce() -> ()>(snapshot_assertion: F) {
|
|
|
|
let mut settings = insta::Settings::new();
|
|
|
|
settings.set_snapshot_path("out");
|
|
|
|
settings.set_prepend_module_to_snapshot(false);
|
|
|
|
settings.bind(|| snapshot_assertion());
|
|
|
|
}
|
|
|
|
|
2020-12-11 06:45:28 +00:00
|
|
|
#[cfg(feature = "spv-out")]
|
|
|
|
fn check_output_spv(module: &naga::Module, name: &str, params: &Parameters) {
|
|
|
|
use naga::back::spv;
|
|
|
|
use rspirv::binary::Disassemble;
|
|
|
|
|
2021-02-14 05:37:54 +00:00
|
|
|
let options = spv::Options {
|
|
|
|
lang_version: params.spv_version,
|
|
|
|
flags: spv::WriterFlags::DEBUG,
|
|
|
|
capabilities: params.spv_capabilities.clone(),
|
|
|
|
};
|
|
|
|
|
|
|
|
let spv = spv::write_vec(&module, &options).unwrap();
|
2020-12-11 06:45:28 +00:00
|
|
|
|
|
|
|
let dis = rspirv::dr::load_words(spv)
|
|
|
|
.expect("Produced invalid SPIR-V")
|
|
|
|
.disassemble();
|
2021-02-07 23:01:58 +00:00
|
|
|
with_snapshot_settings(|| {
|
|
|
|
insta::assert_snapshot!(format!("{}.spvasm", name), dis);
|
|
|
|
});
|
2020-12-11 06:45:28 +00:00
|
|
|
}
|
|
|
|
|
2020-12-08 05:23:29 +00:00
|
|
|
#[cfg(feature = "msl-out")]
|
2021-02-12 06:39:08 +00:00
|
|
|
fn check_output_msl(
|
|
|
|
module: &naga::Module,
|
|
|
|
analysis: &naga::proc::analyzer::Analysis,
|
|
|
|
name: &str,
|
|
|
|
params: &Parameters,
|
|
|
|
) {
|
2020-12-08 05:23:29 +00:00
|
|
|
use naga::back::msl;
|
2020-12-11 06:45:28 +00:00
|
|
|
|
2020-12-08 05:23:29 +00:00
|
|
|
let mut binding_map = msl::BindingMap::default();
|
|
|
|
for (key, value) in params.mtl_bindings.iter() {
|
|
|
|
binding_map.insert(
|
|
|
|
msl::BindSource {
|
|
|
|
stage: match key.stage {
|
|
|
|
Stage::Vertex => naga::ShaderStage::Vertex,
|
|
|
|
Stage::Fragment => naga::ShaderStage::Fragment,
|
|
|
|
Stage::Compute => naga::ShaderStage::Compute,
|
|
|
|
},
|
|
|
|
group: key.group,
|
|
|
|
binding: key.binding,
|
|
|
|
},
|
|
|
|
msl::BindTarget {
|
|
|
|
buffer: value.buffer,
|
|
|
|
texture: value.texture,
|
|
|
|
sampler: value.sampler,
|
|
|
|
mutable: value.mutable,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
let options = msl::Options {
|
|
|
|
lang_version: (1, 0),
|
|
|
|
spirv_cross_compatibility: false,
|
|
|
|
binding_map,
|
|
|
|
};
|
2020-12-11 06:45:28 +00:00
|
|
|
|
2021-02-12 06:39:08 +00:00
|
|
|
let (msl, _) = msl::write_string(module, analysis, &options).unwrap();
|
2021-02-07 23:01:58 +00:00
|
|
|
|
|
|
|
with_snapshot_settings(|| {
|
|
|
|
insta::assert_snapshot!(format!("{}.msl", name), msl);
|
|
|
|
});
|
2020-12-08 05:23:29 +00:00
|
|
|
}
|
|
|
|
|
2020-12-11 06:45:28 +00:00
|
|
|
#[cfg(feature = "glsl-out")]
|
|
|
|
fn check_output_glsl(module: &naga::Module, name: &str, stage: naga::ShaderStage, ep_name: &str) {
|
|
|
|
use naga::back::glsl;
|
|
|
|
|
|
|
|
let options = glsl::Options {
|
|
|
|
version: glsl::Version::Embedded(310),
|
|
|
|
entry_point: (stage, ep_name.to_string()),
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut buffer = Vec::new();
|
|
|
|
let mut writer = glsl::Writer::new(&mut buffer, &module, &options).unwrap();
|
|
|
|
writer.write().unwrap();
|
|
|
|
|
|
|
|
let string = String::from_utf8(buffer).unwrap();
|
2021-02-07 23:01:58 +00:00
|
|
|
|
|
|
|
with_snapshot_settings(|| {
|
|
|
|
insta::assert_snapshot!(format!("{}-{:?}.glsl", name, stage), string);
|
|
|
|
});
|
2020-12-08 05:23:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "wgsl-in")]
|
2020-12-11 06:45:28 +00:00
|
|
|
fn convert_wgsl(name: &str, language: Language) {
|
2021-02-08 07:06:42 +00:00
|
|
|
let params = match std::fs::read_to_string(format!("tests/in/{}{}", name, ".param.ron")) {
|
|
|
|
Ok(string) => ron::de::from_str(&string).expect("Couldn't find param file"),
|
|
|
|
Err(_) => Parameters::default(),
|
|
|
|
};
|
2020-12-08 05:23:29 +00:00
|
|
|
|
|
|
|
let module = naga::front::wgsl::parse_str(
|
2021-02-07 23:01:58 +00:00
|
|
|
&std::fs::read_to_string(format!("tests/in/{}{}", name, ".wgsl"))
|
2020-12-08 05:23:29 +00:00
|
|
|
.expect("Couldn't find wgsl file"),
|
|
|
|
)
|
|
|
|
.unwrap();
|
2021-02-12 06:39:08 +00:00
|
|
|
#[cfg_attr(not(feature = "msl-out"), allow(unused_variables))]
|
|
|
|
let analysis = naga::proc::Validator::new().validate(&module).unwrap();
|
2020-12-08 05:23:29 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "spv-out")]
|
2020-12-11 06:45:28 +00:00
|
|
|
{
|
|
|
|
if language.contains(Language::SPIRV) {
|
|
|
|
check_output_spv(&module, name, ¶ms);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[cfg(feature = "msl-out")]
|
|
|
|
{
|
|
|
|
if language.contains(Language::METAL) {
|
2021-02-12 06:39:08 +00:00
|
|
|
check_output_msl(&module, &analysis, name, ¶ms);
|
2020-12-11 06:45:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#[cfg(feature = "glsl-out")]
|
|
|
|
{
|
|
|
|
if language.contains(Language::GLSL) {
|
|
|
|
for &(stage, ref ep_name) in module.entry_points.keys() {
|
|
|
|
check_output_glsl(&module, name, stage, ep_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-12-08 05:23:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "wgsl-in")]
|
|
|
|
#[test]
|
2021-01-23 06:57:02 +00:00
|
|
|
fn convert_wgsl_quad() {
|
2020-12-11 06:45:28 +00:00
|
|
|
convert_wgsl("quad", Language::all());
|
2020-12-08 05:23:29 +00:00
|
|
|
}
|
2020-12-09 02:49:59 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "wgsl-in")]
|
|
|
|
#[test]
|
2021-01-23 06:57:02 +00:00
|
|
|
fn convert_wgsl_empty() {
|
|
|
|
convert_wgsl("empty", Language::all());
|
2020-12-09 02:49:59 +00:00
|
|
|
}
|
2020-12-09 04:46:23 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "wgsl-in")]
|
|
|
|
#[test]
|
2021-01-23 06:57:02 +00:00
|
|
|
fn convert_wgsl_boids() {
|
2021-01-28 05:31:21 +00:00
|
|
|
convert_wgsl("boids", Language::METAL | Language::SPIRV);
|
2020-12-09 04:46:23 +00:00
|
|
|
}
|
2020-12-13 06:20:39 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "wgsl-in")]
|
|
|
|
#[test]
|
2021-01-23 06:57:02 +00:00
|
|
|
fn convert_wgsl_skybox() {
|
2020-12-13 06:20:39 +00:00
|
|
|
convert_wgsl("skybox", Language::all());
|
|
|
|
}
|
2021-01-22 04:56:18 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "wgsl-in")]
|
|
|
|
#[test]
|
2021-01-23 06:57:02 +00:00
|
|
|
fn convert_wgsl_collatz() {
|
2021-01-28 05:31:21 +00:00
|
|
|
convert_wgsl("collatz", Language::METAL | Language::SPIRV);
|
2021-01-22 04:56:18 +00:00
|
|
|
}
|
2021-01-30 05:11:23 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "wgsl-in")]
|
|
|
|
#[test]
|
|
|
|
fn convert_wgsl_shadow() {
|
|
|
|
convert_wgsl("shadow", Language::METAL | Language::SPIRV);
|
|
|
|
}
|
2021-02-07 02:02:49 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "wgsl-in")]
|
|
|
|
#[test]
|
|
|
|
fn convert_wgsl_texture_array() {
|
|
|
|
convert_wgsl("texture-array", Language::SPIRV);
|
|
|
|
}
|
2021-02-08 17:30:21 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "spv-in")]
|
|
|
|
fn convert_spv(name: &str) {
|
|
|
|
let module = naga::front::spv::parse_u8_slice(
|
|
|
|
&std::fs::read(format!("tests/in/{}{}", name, ".spv")).expect("Couldn't find spv file"),
|
|
|
|
&Default::default(),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
naga::proc::Validator::new().validate(&module).unwrap();
|
|
|
|
|
|
|
|
#[cfg(feature = "serialize")]
|
|
|
|
{
|
2021-02-14 11:21:33 +00:00
|
|
|
let config = ron::ser::PrettyConfig::default().with_new_line("\n".to_string());
|
2021-02-08 17:30:21 +00:00
|
|
|
let output = ron::ser::to_string_pretty(&module, config).unwrap();
|
|
|
|
with_snapshot_settings(|| {
|
|
|
|
insta::assert_snapshot!(format!("{}.ron", name), output);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "spv-in")]
|
|
|
|
#[test]
|
|
|
|
fn convert_spv_shadow() {
|
|
|
|
convert_spv("shadow");
|
|
|
|
}
|