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 cc;
6 extern crate glsl_to_cxx;
7 extern crate webrender_build;
8
9 use std::collections::HashSet;
10 use std::fmt::Write;
11 use webrender_build::shader::{ShaderFeatureFlags, get_shader_features};
12
13 // Shader key is in "name feature,feature" format.
14 // File name needs to be formatted as "name_feature_feature".
shader_file(shader_key: &str) -> String15 fn shader_file(shader_key: &str) -> String {
16 shader_key.replace(' ', "_").replace(',', "_")
17 }
18
write_load_shader(shader_keys: &[String])19 fn write_load_shader(shader_keys: &[String]) {
20 let mut load_shader = String::new();
21 for s in shader_keys {
22 let _ = write!(load_shader, "#include \"{}.h\"\n", shader_file(s));
23 }
24 load_shader.push_str("ProgramLoader load_shader(const char* name) {\n");
25 for s in shader_keys {
26 let _ = write!(load_shader, " if (!strcmp(name, \"{}\")) {{ return {}_program::loader; }}\n",
27 s, shader_file(s));
28 }
29 load_shader.push_str(" return nullptr;\n}\n");
30 std::fs::write(std::env::var("OUT_DIR").unwrap() + "/load_shader.h", load_shader).unwrap();
31 }
32
process_imports(shader_dir: &str, shader: &str, included: &mut HashSet<String>, output: &mut String)33 fn process_imports(shader_dir: &str, shader: &str, included: &mut HashSet<String>, output: &mut String) {
34 if !included.insert(shader.into()) {
35 return;
36 }
37 println!("cargo:rerun-if-changed={}/{}.glsl", shader_dir, shader);
38 let source = std::fs::read_to_string(format!("{}/{}.glsl", shader_dir, shader)).unwrap();
39 for line in source.lines() {
40 if line.starts_with("#include ") {
41 let imports = line["#include ".len() ..].split(',');
42 for import in imports {
43 process_imports(shader_dir, import, included, output);
44 }
45 } else if line.starts_with("#version ") || line.starts_with("#extension ") {
46 // ignore
47 } else {
48 output.push_str(line);
49 output.push('\n');
50 }
51 }
52 }
53
translate_shader(shader_key: &str, shader_dir: &str)54 fn translate_shader(shader_key: &str, shader_dir: &str) {
55 let mut imported = String::from("#define SWGL 1\n");
56 let _ = write!(imported, "#define WR_MAX_VERTEX_TEXTURE_WIDTH {}U\n",
57 webrender_build::MAX_VERTEX_TEXTURE_WIDTH);
58
59 let (basename, features) =
60 shader_key.split_at(shader_key.find(' ').unwrap_or(shader_key.len()));
61 if !features.is_empty() {
62 for feature in features.trim().split(',') {
63 let _ = write!(imported, "#define WR_FEATURE_{}\n", feature);
64 }
65 }
66
67 process_imports(shader_dir, basename, &mut HashSet::new(), &mut imported);
68
69 let shader = shader_file(shader_key);
70
71 let out_dir = std::env::var("OUT_DIR").unwrap();
72 let imp_name = format!("{}/{}.c", out_dir, shader);
73 std::fs::write(&imp_name, imported).unwrap();
74
75 let mut build = cc::Build::new();
76 if build.get_compiler().is_like_msvc() {
77 build.flag("/EP");
78 } else {
79 build.flag("-xc").flag("-P");
80 }
81 build.file(&imp_name);
82 let vs = build.clone()
83 .define("WR_VERTEX_SHADER", Some("1"))
84 .expand();
85 let fs = build.clone()
86 .define("WR_FRAGMENT_SHADER", Some("1"))
87 .expand();
88 let vs_name = format!("{}/{}.vert", out_dir, shader);
89 let fs_name = format!("{}/{}.frag", out_dir, shader);
90 std::fs::write(&vs_name, vs).unwrap();
91 std::fs::write(&fs_name, fs).unwrap();
92
93 let mut args = vec![
94 "glsl_to_cxx".to_string(),
95 vs_name,
96 fs_name,
97 ];
98 let frag_include = format!("{}/{}.frag.h", shader_dir, shader);
99 if std::path::Path::new(&frag_include).exists() {
100 println!("cargo:rerun-if-changed={}/{}.frag.h", shader_dir, shader);
101 args.push(frag_include);
102 }
103 let result = glsl_to_cxx::translate(&mut args.into_iter());
104 std::fs::write(format!("{}/{}.h", out_dir, shader), result).unwrap();
105 }
106
main()107 fn main() {
108 let shader_dir = match std::env::var("MOZ_SRC") {
109 Ok(dir) => dir + "/gfx/wr/webrender/res",
110 Err(_) => std::env::var("CARGO_MANIFEST_DIR").unwrap() + "/../webrender/res",
111 };
112
113 let shader_flags =
114 ShaderFeatureFlags::GL |
115 ShaderFeatureFlags::DUAL_SOURCE_BLENDING;
116 let mut shaders: Vec<String> = Vec::new();
117 for (name, features) in get_shader_features(shader_flags) {
118 shaders.extend(features.iter().map(|f| {
119 if f.is_empty() { name.to_owned() } else { format!("{} {}", name, f) }
120 }));
121 }
122
123 shaders.sort();
124
125 for shader in &shaders {
126 translate_shader(shader, &shader_dir);
127 }
128
129 write_load_shader(&shaders);
130
131 println!("cargo:rerun-if-changed=src/gl_defs.h");
132 println!("cargo:rerun-if-changed=src/glsl.h");
133 println!("cargo:rerun-if-changed=src/program.h");
134 println!("cargo:rerun-if-changed=src/texture.h");
135 println!("cargo:rerun-if-changed=src/vector_type.h");
136 println!("cargo:rerun-if-changed=src/gl.cc");
137 cc::Build::new()
138 .cpp(true)
139 .file("src/gl.cc")
140 .flag("-std=c++14")
141 .flag("-UMOZILLA_CONFIG_H")
142 .flag("-fno-exceptions")
143 .flag("-fno-rtti")
144 .flag("-fno-math-errno")
145 .define("_GLIBCXX_USE_CXX11_ABI", Some("0"))
146 .include(shader_dir)
147 .include("src")
148 .include(std::env::var("OUT_DIR").unwrap())
149 .compile("gl_cc");
150 }
151