1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
use std::{fs::File, io::Write, process::Command};
pub type SpirvOutput = File;
pub fn compile(
code: &str,
ty: ShaderType,
shader_defs: Option<&[String]>,
) -> Result<SpirvOutput, String> {
compile_inner(Some((code, ty)), shader_defs)
}
fn compile_inner<'a, I>(shaders: I, shader_defs: Option<&[String]>) -> Result<SpirvOutput, String>
where
I: IntoIterator<Item = (&'a str, ShaderType)>,
{
let temp_dir = tempfile::tempdir().unwrap();
let output_file = temp_dir.path().join("compilation_output.spv");
let mut command = Command::new(concat!(env!("OUT_DIR"), "/glslang_validator"));
command.arg("-V");
command.arg("-l");
command.arg("-o").arg(&output_file);
if let Some(shader_defs) = shader_defs {
for def in shader_defs.iter() {
command.arg(format!("-D {}", def));
}
}
for (num, (source, ty)) in shaders.into_iter().enumerate() {
let extension = match ty {
ShaderType::Vertex => ".vert",
ShaderType::Fragment => ".frag",
ShaderType::Geometry => ".geom",
ShaderType::TessellationControl => ".tesc",
ShaderType::TessellationEvaluation => ".tese",
ShaderType::Compute => ".comp",
};
let file_path = temp_dir.path().join(format!("{}{}", num, extension));
File::create(&file_path)
.unwrap()
.write_all(source.as_bytes())
.unwrap();
command.arg(file_path);
}
let output = command
.output()
.expect("Failed to execute glslangValidator");
if output.status.success() {
let spirv_output = File::open(output_file).expect("failed to open SPIR-V output file");
return Ok(spirv_output);
}
let error1 = String::from_utf8_lossy(&output.stdout);
let error2 = String::from_utf8_lossy(&output.stderr);
return Err(error1.into_owned() + &error2);
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ShaderType {
Vertex,
Fragment,
Geometry,
TessellationControl,
TessellationEvaluation,
Compute,
}