GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
build.rs (2.4K)
1 //! Compiles the renderer's fixed WGSL shaders to SPIR-V at build time.
2 //!
3 //! Every `VkRenderer` needs these four, and naga's WGSL front end, validator
4 //! and SPIR-V writer ran in every process that built one: 20-60 ms of each
5 //! app's launch, nearly all of it `shader2d.wgsl`. The output is a pure
6 //! function of the source, so it is made once here and embedded
7 //! (`renderer::shader2d_spirv` and friends). A WGSL error is now a build
8 //! failure rather than a panic at the first window.
9 //!
10 //! The sources are `draw::shaders`' files, which the Vulkan path uses
11 //! verbatim (the WebGPU and Metal backends make their own variants of them).
12 //! The options MUST match `renderer::compile_wgsl`, which still compiles the
13 //! shaders built at run time (compute kernels, the ray-query stack);
14 //! `precompiled_spirv_matches_runtime_compile` checks that they do.
15
16 use std::path::Path;
17
18 const SHADERS: [&str; 5] = ["shader2d", "glyph", "scene3d", "scene3d_image", "scene3d_lit"];
19
20 fn main() {
21 let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR");
22 for name in SHADERS {
23 let src_path = format!("src/draw/{name}.wgsl");
24 println!("cargo:rerun-if-changed={src_path}");
25 let source = std::fs::read_to_string(&src_path)
26 .unwrap_or_else(|e| panic!("read {src_path}: {e}"));
27 let spirv = compile_wgsl(&source, &src_path);
28 let bytes: Vec<u8> = spirv.iter().flat_map(|w| w.to_le_bytes()).collect();
29 std::fs::write(Path::new(&out_dir).join(format!("{name}.spv")), bytes)
30 .unwrap_or_else(|e| panic!("write {name}.spv: {e}"));
31 }
32 println!("cargo:rerun-if-changed=build.rs");
33 }
34
35 fn compile_wgsl(source: &str, path: &str) -> Vec<u32> {
36 let module = naga::front::wgsl::parse_str(source)
37 .unwrap_or_else(|e| panic!("{path}: WGSL parse failed:\n{}", e.emit_to_string(source)));
38 let info = naga::valid::Validator::new(
39 naga::valid::ValidationFlags::all(),
40 naga::valid::Capabilities::PUSH_CONSTANT,
41 )
42 .validate(&module)
43 .unwrap_or_else(|e| panic!("{path}: WGSL validation failed:\n{}", e.emit_to_string(source)));
44 let options = naga::back::spv::Options {
45 lang_version: (1, 0),
46 flags: naga::back::spv::WriterFlags::LABEL_VARYINGS,
47 ..Default::default()
48 };
49 naga::back::spv::write_vec(&module, &info, &options, None)
50 .unwrap_or_else(|e| panic!("{path}: SPIR-V write failed: {e}"))
51 }