2021-04-14 18:20:48 +00:00
|
|
|
//TODO: move this to a binary target once Rust supports
|
|
|
|
// binary-specific dependencies.
|
|
|
|
|
|
|
|
use std::{fs, path::PathBuf};
|
|
|
|
|
|
|
|
const DIR_IN: &str = "tests/in";
|
|
|
|
const DIR_OUT: &str = "tests/out";
|
|
|
|
|
2020-12-13 06:20:39 +00:00
|
|
|
bitflags::bitflags! {
|
2021-02-18 02:46:32 +00:00
|
|
|
struct Targets: u32 {
|
|
|
|
const IR = 0x1;
|
|
|
|
const ANALYSIS = 0x2;
|
|
|
|
const SPIRV = 0x4;
|
|
|
|
const METAL = 0x8;
|
|
|
|
const GLSL = 0x10;
|
2021-03-02 06:28:32 +00:00
|
|
|
const DOT = 0x20;
|
2021-04-11 15:36:26 +00:00
|
|
|
const HLSL = 0x40;
|
2020-12-13 06:20:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-11 14:56:10 +00:00
|
|
|
#[derive(Default, serde::Deserialize)]
|
2020-12-08 05:23:29 +00:00
|
|
|
struct Parameters {
|
|
|
|
#[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>,
|
2021-04-02 05:12:36 +00:00
|
|
|
#[cfg_attr(not(feature = "spv-out"), allow(dead_code))]
|
|
|
|
spv_debug: bool,
|
|
|
|
#[cfg_attr(not(feature = "spv-out"), allow(dead_code))]
|
|
|
|
spv_adjust_coordinate_space: bool,
|
2021-04-07 14:29:35 +00:00
|
|
|
#[cfg(all(feature = "deserialize", feature = "msl-out"))]
|
|
|
|
#[serde(default)]
|
|
|
|
msl: naga::back::msl::Options,
|
|
|
|
#[cfg(all(not(feature = "deserialize"), feature = "msl-out"))]
|
|
|
|
msl_custom: bool,
|
2020-12-08 05:23:29 +00:00
|
|
|
}
|
|
|
|
|
2021-02-24 14:12:14 +00:00
|
|
|
#[allow(dead_code, unused_variables)]
|
2021-02-18 02:46:32 +00:00
|
|
|
fn check_targets(module: &naga::Module, name: &str, targets: Targets) {
|
2021-04-14 18:20:48 +00:00
|
|
|
let root = env!("CARGO_MANIFEST_DIR");
|
|
|
|
let params = match fs::read_to_string(format!("{}/{}/{}.param.ron", root, DIR_IN, name)) {
|
2021-02-18 02:46:32 +00:00
|
|
|
Ok(string) => ron::de::from_str(&string).expect("Couldn't find param file"),
|
|
|
|
Err(_) => Parameters::default(),
|
|
|
|
};
|
2021-03-21 02:10:31 +00:00
|
|
|
let info = naga::valid::Validator::new(naga::valid::ValidationFlags::all())
|
2021-03-20 03:45:36 +00:00
|
|
|
.validate(module)
|
|
|
|
.unwrap();
|
2021-02-18 02:46:32 +00:00
|
|
|
|
2021-04-14 18:20:48 +00:00
|
|
|
let dest = PathBuf::from(root).join(DIR_OUT).join(name);
|
|
|
|
|
2021-02-18 02:46:32 +00:00
|
|
|
#[cfg(feature = "serialize")]
|
|
|
|
{
|
|
|
|
if targets.contains(Targets::IR) {
|
|
|
|
let config = ron::ser::PrettyConfig::default().with_new_line("\n".to_string());
|
2021-04-14 18:20:48 +00:00
|
|
|
let string = ron::ser::to_string_pretty(module, config).unwrap();
|
|
|
|
fs::write(dest.with_extension("ron"), string).unwrap();
|
2021-02-18 02:46:32 +00:00
|
|
|
}
|
|
|
|
if targets.contains(Targets::ANALYSIS) {
|
|
|
|
let config = ron::ser::PrettyConfig::default().with_new_line("\n".to_string());
|
2021-04-14 18:20:48 +00:00
|
|
|
let string = ron::ser::to_string_pretty(&info, config).unwrap();
|
|
|
|
fs::write(dest.with_extension("info.ron"), string).unwrap();
|
2021-02-18 02:46:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "spv-out")]
|
|
|
|
{
|
|
|
|
if targets.contains(Targets::SPIRV) {
|
2021-04-14 18:20:48 +00:00
|
|
|
check_output_spv(module, &info, &dest, ¶ms);
|
2021-02-18 02:46:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#[cfg(feature = "msl-out")]
|
|
|
|
{
|
|
|
|
if targets.contains(Targets::METAL) {
|
2021-04-14 18:20:48 +00:00
|
|
|
check_output_msl(module, &info, &dest, ¶ms);
|
2021-02-18 02:46:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#[cfg(feature = "glsl-out")]
|
|
|
|
{
|
|
|
|
if targets.contains(Targets::GLSL) {
|
2021-03-07 03:47:21 +00:00
|
|
|
for ep in module.entry_points.iter() {
|
2021-04-14 18:20:48 +00:00
|
|
|
check_output_glsl(module, &info, &dest, ep.stage, &ep.name);
|
2021-02-18 02:46:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-03-02 06:28:32 +00:00
|
|
|
#[cfg(feature = "dot-out")]
|
|
|
|
{
|
|
|
|
if targets.contains(Targets::DOT) {
|
2021-03-20 05:09:29 +00:00
|
|
|
let string = naga::back::dot::write(module, Some(&info)).unwrap();
|
2021-04-14 18:20:48 +00:00
|
|
|
fs::write(dest.with_extension("dot"), string).unwrap();
|
2021-03-02 06:28:32 +00:00
|
|
|
}
|
|
|
|
}
|
2021-04-11 15:36:26 +00:00
|
|
|
#[cfg(feature = "hlsl-out")]
|
|
|
|
{
|
|
|
|
if targets.contains(Targets::HLSL) {
|
2021-04-14 18:20:48 +00:00
|
|
|
check_output_hlsl(module, &dest);
|
2021-04-11 15:36:26 +00:00
|
|
|
}
|
|
|
|
}
|
2021-02-18 02:46:32 +00:00
|
|
|
}
|
|
|
|
|
2020-12-11 06:45:28 +00:00
|
|
|
#[cfg(feature = "spv-out")]
|
2021-02-17 19:55:46 +00:00
|
|
|
fn check_output_spv(
|
|
|
|
module: &naga::Module,
|
2021-03-20 05:09:29 +00:00
|
|
|
info: &naga::valid::ModuleInfo,
|
2021-04-14 18:20:48 +00:00
|
|
|
destination: &PathBuf,
|
2021-02-17 19:55:46 +00:00
|
|
|
params: &Parameters,
|
|
|
|
) {
|
2020-12-11 06:45:28 +00:00
|
|
|
use naga::back::spv;
|
|
|
|
use rspirv::binary::Disassemble;
|
|
|
|
|
2021-04-02 05:12:36 +00:00
|
|
|
let mut flags = spv::WriterFlags::empty();
|
|
|
|
if params.spv_debug {
|
|
|
|
flags |= spv::WriterFlags::DEBUG;
|
|
|
|
}
|
|
|
|
if params.spv_adjust_coordinate_space {
|
|
|
|
flags |= spv::WriterFlags::ADJUST_COORDINATE_SPACE;
|
|
|
|
}
|
2021-02-14 05:37:54 +00:00
|
|
|
let options = spv::Options {
|
|
|
|
lang_version: params.spv_version,
|
2021-04-02 05:12:36 +00:00
|
|
|
flags,
|
2021-02-14 05:37:54 +00:00
|
|
|
capabilities: params.spv_capabilities.clone(),
|
|
|
|
};
|
|
|
|
|
2021-03-20 05:09:29 +00:00
|
|
|
let spv = spv::write_vec(module, info, &options).unwrap();
|
2020-12-11 06:45:28 +00:00
|
|
|
|
|
|
|
let dis = rspirv::dr::load_words(spv)
|
|
|
|
.expect("Produced invalid SPIR-V")
|
|
|
|
.disassemble();
|
2021-04-14 18:20:48 +00:00
|
|
|
|
|
|
|
fs::write(destination.with_extension("spvasm"), dis).unwrap();
|
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,
|
2021-03-20 05:09:29 +00:00
|
|
|
info: &naga::valid::ModuleInfo,
|
2021-04-14 18:20:48 +00:00
|
|
|
destination: &PathBuf,
|
2021-02-12 06:39:08 +00:00
|
|
|
params: &Parameters,
|
|
|
|
) {
|
2020-12-08 05:23:29 +00:00
|
|
|
use naga::back::msl;
|
2020-12-11 06:45:28 +00:00
|
|
|
|
2021-04-07 14:29:35 +00:00
|
|
|
#[cfg_attr(feature = "deserialize", allow(unused_variables))]
|
|
|
|
let default_options = msl::Options::default();
|
|
|
|
#[cfg(feature = "deserialize")]
|
|
|
|
let options = ¶ms.msl;
|
|
|
|
#[cfg(not(feature = "deserialize"))]
|
|
|
|
let options = if params.msl_custom {
|
2021-04-14 18:20:48 +00:00
|
|
|
println!("Skipping {}", destination);
|
2021-04-07 14:29:35 +00:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
&default_options
|
2021-04-07 05:06:51 +00:00
|
|
|
};
|
2021-04-07 14:29:35 +00:00
|
|
|
|
2021-04-08 02:44:41 +00:00
|
|
|
let pipeline_options = msl::PipelineOptions {
|
2021-04-02 03:49:17 +00:00
|
|
|
allow_point_size: true,
|
2020-12-08 05:23:29 +00:00
|
|
|
};
|
2020-12-11 06:45:28 +00:00
|
|
|
|
2021-04-14 18:20:48 +00:00
|
|
|
let (string, _) = msl::write_string(module, info, options, &pipeline_options).unwrap();
|
2021-02-07 23:01:58 +00:00
|
|
|
|
2021-04-14 18:20:48 +00:00
|
|
|
fs::write(destination.with_extension("msl"), string).unwrap();
|
2020-12-08 05:23:29 +00:00
|
|
|
}
|
|
|
|
|
2020-12-11 06:45:28 +00:00
|
|
|
#[cfg(feature = "glsl-out")]
|
2021-02-14 22:26:31 +00:00
|
|
|
fn check_output_glsl(
|
|
|
|
module: &naga::Module,
|
2021-03-20 05:09:29 +00:00
|
|
|
info: &naga::valid::ModuleInfo,
|
2021-04-14 18:20:48 +00:00
|
|
|
destination: &PathBuf,
|
2021-02-14 22:26:31 +00:00
|
|
|
stage: naga::ShaderStage,
|
|
|
|
ep_name: &str,
|
|
|
|
) {
|
2020-12-11 06:45:28 +00:00
|
|
|
use naga::back::glsl;
|
|
|
|
|
|
|
|
let options = glsl::Options {
|
|
|
|
version: glsl::Version::Embedded(310),
|
2021-02-18 12:14:04 +00:00
|
|
|
shader_stage: stage,
|
|
|
|
entry_point: ep_name.to_string(),
|
2020-12-11 06:45:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let mut buffer = Vec::new();
|
2021-03-20 05:09:29 +00:00
|
|
|
let mut writer = glsl::Writer::new(&mut buffer, module, info, &options).unwrap();
|
2020-12-11 06:45:28 +00:00
|
|
|
writer.write().unwrap();
|
|
|
|
|
|
|
|
let string = String::from_utf8(buffer).unwrap();
|
2021-02-07 23:01:58 +00:00
|
|
|
|
2021-04-14 18:20:48 +00:00
|
|
|
let ext = format!("{:?}.glsl", stage);
|
|
|
|
fs::write(destination.with_extension(&ext), string).unwrap();
|
2020-12-08 05:23:29 +00:00
|
|
|
}
|
|
|
|
|
2021-04-11 15:36:26 +00:00
|
|
|
#[cfg(feature = "hlsl-out")]
|
2021-04-14 18:20:48 +00:00
|
|
|
fn check_output_hlsl(module: &naga::Module, destination: &PathBuf) {
|
2021-04-11 15:36:26 +00:00
|
|
|
use naga::back::hlsl;
|
|
|
|
|
2021-04-14 18:20:48 +00:00
|
|
|
let string = hlsl::write_string(module).unwrap();
|
|
|
|
|
|
|
|
fs::write(destination.with_extension("hlsl"), string).unwrap();
|
2021-04-11 15:36:26 +00:00
|
|
|
}
|
|
|
|
|
2020-12-13 06:20:39 +00:00
|
|
|
#[cfg(feature = "wgsl-in")]
|
|
|
|
#[test]
|
2021-04-14 14:05:48 +00:00
|
|
|
fn convert_wgsl() {
|
|
|
|
let root = env!("CARGO_MANIFEST_DIR");
|
|
|
|
let inputs = [
|
|
|
|
(
|
|
|
|
"empty",
|
|
|
|
Targets::SPIRV | Targets::METAL | Targets::GLSL | Targets::HLSL,
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"quad",
|
|
|
|
Targets::SPIRV | Targets::METAL | Targets::GLSL | Targets::DOT,
|
|
|
|
),
|
|
|
|
("boids", Targets::SPIRV | Targets::METAL),
|
|
|
|
("skybox", Targets::SPIRV | Targets::METAL | Targets::GLSL),
|
|
|
|
(
|
|
|
|
"collatz",
|
|
|
|
Targets::SPIRV | Targets::METAL | Targets::IR | Targets::ANALYSIS,
|
|
|
|
),
|
|
|
|
("shadow", Targets::SPIRV | Targets::METAL | Targets::GLSL),
|
|
|
|
//SPIR-V is blocked by https://github.com/gfx-rs/naga/issues/646
|
|
|
|
("image-copy", Targets::METAL),
|
|
|
|
("texture-array", Targets::SPIRV | Targets::METAL),
|
|
|
|
("operators", Targets::SPIRV | Targets::METAL | Targets::GLSL),
|
|
|
|
];
|
|
|
|
|
|
|
|
for &(name, targets) in inputs.iter() {
|
|
|
|
println!("Processing '{}'", name);
|
|
|
|
let file = fs::read_to_string(format!("{}/{}/{}.wgsl", root, DIR_IN, name))
|
|
|
|
.expect("Couldn't find wgsl file");
|
|
|
|
match naga::front::wgsl::parse_str(&file) {
|
|
|
|
Ok(module) => check_targets(&module, name, targets),
|
|
|
|
Err(e) => panic!("{}", e),
|
|
|
|
}
|
|
|
|
}
|
2021-02-07 02:02:49 +00:00
|
|
|
}
|
2021-02-08 17:30:21 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "spv-in")]
|
2021-04-02 04:16:11 +00:00
|
|
|
fn convert_spv(name: &str, adjust_coordinate_space: bool, targets: Targets) {
|
2021-04-14 18:20:48 +00:00
|
|
|
let root = env!("CARGO_MANIFEST_DIR");
|
2021-02-08 17:30:21 +00:00
|
|
|
let module = naga::front::spv::parse_u8_slice(
|
2021-04-14 18:20:48 +00:00
|
|
|
&fs::read(format!("{}/{}/{}.spv", root, DIR_IN, name)).expect("Couldn't find spv file"),
|
2021-04-02 04:16:11 +00:00
|
|
|
&naga::front::spv::Options {
|
|
|
|
adjust_coordinate_space,
|
|
|
|
flow_graph_dump_prefix: None,
|
|
|
|
},
|
2021-02-08 17:30:21 +00:00
|
|
|
)
|
|
|
|
.unwrap();
|
2021-02-18 02:46:32 +00:00
|
|
|
check_targets(&module, name, targets);
|
2021-03-21 02:10:31 +00:00
|
|
|
naga::valid::Validator::new(naga::valid::ValidationFlags::all())
|
2021-03-20 03:45:36 +00:00
|
|
|
.validate(&module)
|
|
|
|
.unwrap();
|
2021-02-08 17:30:21 +00:00
|
|
|
}
|
|
|
|
|
2021-03-27 02:07:40 +00:00
|
|
|
#[cfg(feature = "spv-in")]
|
|
|
|
#[test]
|
|
|
|
fn convert_spv_quad_vert() {
|
2021-04-02 04:16:11 +00:00
|
|
|
convert_spv("quad-vert", false, Targets::METAL);
|
2021-03-27 02:07:40 +00:00
|
|
|
}
|
|
|
|
|
2021-02-08 17:30:21 +00:00
|
|
|
#[cfg(feature = "spv-in")]
|
|
|
|
#[test]
|
|
|
|
fn convert_spv_shadow() {
|
2021-04-02 04:16:11 +00:00
|
|
|
convert_spv("shadow", true, Targets::IR | Targets::ANALYSIS);
|
2021-02-08 17:30:21 +00:00
|
|
|
}
|
2021-02-11 19:43:37 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "glsl-in")]
|
2021-02-18 02:46:32 +00:00
|
|
|
fn convert_glsl(
|
|
|
|
name: &str,
|
|
|
|
entry_points: naga::FastHashMap<String, naga::ShaderStage>,
|
2021-02-24 14:12:14 +00:00
|
|
|
_targets: Targets,
|
2021-02-18 02:46:32 +00:00
|
|
|
) {
|
2021-04-14 18:20:48 +00:00
|
|
|
let root = env!("CARGO_MANIFEST_DIR");
|
2021-03-02 06:28:32 +00:00
|
|
|
let _module = naga::front::glsl::parse_str(
|
2021-04-14 18:20:48 +00:00
|
|
|
&fs::read_to_string(format!("{}/{}/{}.glsl", root, DIR_IN, name))
|
2021-02-11 19:43:37 +00:00
|
|
|
.expect("Couldn't find glsl file"),
|
2021-02-17 11:23:36 +00:00
|
|
|
&naga::front::glsl::Options {
|
|
|
|
entry_points,
|
|
|
|
defines: Default::default(),
|
|
|
|
},
|
2021-02-11 19:43:37 +00:00
|
|
|
)
|
|
|
|
.unwrap();
|
2021-02-24 14:12:14 +00:00
|
|
|
//TODO
|
|
|
|
//check_targets(&module, name, targets);
|
2021-02-11 19:43:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "glsl-in")]
|
|
|
|
#[test]
|
|
|
|
fn convert_glsl_quad() {
|
2021-02-17 11:23:36 +00:00
|
|
|
let mut entry_points = naga::FastHashMap::default();
|
|
|
|
entry_points.insert("vert_main".to_string(), naga::ShaderStage::Vertex);
|
|
|
|
entry_points.insert("frag_main".to_string(), naga::ShaderStage::Fragment);
|
2021-02-18 02:46:32 +00:00
|
|
|
convert_glsl("quad-glsl", entry_points, Targets::SPIRV | Targets::IR);
|
2021-02-11 19:43:37 +00:00
|
|
|
}
|