Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
extern crate webrender_build;
6
7
use std::borrow::Cow;
8
use std::env;
9
use std::fs::{canonicalize, read_dir, File};
10
use std::io::prelude::*;
11
use std::path::{Path, PathBuf};
12
use std::collections::hash_map::DefaultHasher;
13
use std::hash::Hasher;
14
use webrender_build::shader::*;
15
16
fn write_shaders(glsl_files: Vec<PathBuf>, shader_file_path: &Path) {
17
let mut shader_file = File::create(shader_file_path).unwrap();
18
19
write!(shader_file, "/// AUTO GENERATED BY build.rs\n\n").unwrap();
20
write!(shader_file, "use std::collections::HashMap;\n\n").unwrap();
21
write!(shader_file, "pub struct SourceWithDigest {{ pub source: &'static str, pub digest: &'static str }}\n\n")
22
.unwrap();
23
write!(shader_file, "lazy_static! {{\n").unwrap();
24
write!(
25
shader_file,
26
" pub static ref SHADERS: HashMap<&'static str, SourceWithDigest> = {{\n"
27
).unwrap();
28
write!(shader_file, " let mut h = HashMap::new();\n").unwrap();
29
for glsl in glsl_files {
30
// Compute the shader name.
31
assert!(glsl.is_file());
32
let shader_name = glsl.file_name().unwrap().to_str().unwrap();
33
let shader_name = shader_name.replace(".glsl", "");
34
35
// Compute a digest of the #include-expanded shader source. We store
36
// this as a literal alongside the source string so that we don't need
37
// to hash large strings at runtime.
38
let mut hasher = DefaultHasher::new();
39
let base = glsl.parent().unwrap();
40
assert!(base.is_dir());
41
ShaderSourceParser::new().parse(
42
Cow::Owned(shader_source_from_file(&glsl)),
43
&|f| Cow::Owned(shader_source_from_file(&base.join(&format!("{}.glsl", f)))),
44
&mut |s| hasher.write(s.as_bytes()),
45
);
46
let digest: ProgramSourceDigest = hasher.into();
47
48
// Compute the shader path for insertion into the include_str!() macro.
49
// This makes for more compact generated code than inserting the literal
50
// shader source into the generated file.
51
//
52
// If someone is building on a network share, I'm sorry.
53
let full_path = canonicalize(&glsl).unwrap();
54
let full_name = full_path.as_os_str().to_str().unwrap();
55
let full_name = full_name.replace("\\\\?\\", "");
56
let full_name = full_name.replace("\\", "/");
57
58
write!(
59
shader_file,
60
" h.insert(\"{}\", SourceWithDigest {{ source: include_str!(\"{}\"), digest: \"{}\"}});\n",
61
shader_name,
62
full_name,
63
digest,
64
).unwrap();
65
}
66
write!(shader_file, " h\n").unwrap();
67
write!(shader_file, " }};\n").unwrap();
68
write!(shader_file, "}}\n").unwrap();
69
}
70
71
fn main() {
72
let out_dir = env::var("OUT_DIR").unwrap_or("out".to_owned());
73
74
let shaders_file = Path::new(&out_dir).join("shaders.rs");
75
let mut glsl_files = vec![];
76
77
println!("cargo:rerun-if-changed=res");
78
let res_dir = Path::new("res");
79
for entry in read_dir(res_dir).unwrap() {
80
let entry = entry.unwrap();
81
let path = entry.path();
82
83
if entry.file_name().to_str().unwrap().ends_with(".glsl") {
84
println!("cargo:rerun-if-changed={}", path.display());
85
glsl_files.push(path.to_owned());
86
}
87
}
88
89
// Sort the file list so that the shaders.rs file is filled
90
// deterministically.
91
glsl_files.sort_by(|a, b| a.file_name().cmp(&b.file_name()));
92
93
write_shaders(glsl_files, &shaders_file);
94
}