// Copyright 2023 The Vello authors // SPDX-License-Identifier: Apache-2.0 OR MIT #[path = "src/compile/mod.rs"] mod compile; #[path = "src/types.rs"] mod types; use std::env; use std::fmt::Write; use std::path::{Path, PathBuf}; use compile::ShaderInfo; fn main() { let out_dir = env::var_os("OUT_DIR").unwrap(); let dest_path = Path::new(&out_dir).join("shaders.rs"); // The shaders are defined under the workspace root and not in this crate so we need to locate // them somehow. Cargo doesn't define an environment variable that points at the root workspace // directory. In hermetic build environments that don't support relative paths (such as Bazel) // we support supplying a `WORKSPACE_MANIFEST_FILE` that is expected to be an absolute path to // the Cargo.toml file at the workspace root. If that's not present, we use a relative path. let workspace_dir = env::var("WORKSPACE_MANIFEST_FILE") .ok() .and_then(|p| Path::new(&p).parent().map(|p| p.to_owned())) .unwrap_or(PathBuf::from("../../")); let shader_dir = Path::new(&workspace_dir).join("shader"); let mut shaders = compile::ShaderInfo::from_dir(shader_dir); // Drop the HashMap and sort by name so that we get deterministic order. let mut shaders = shaders.drain().collect::>(); shaders.sort_by(|x, y| x.0.cmp(&y.0)); let mut buf = String::default(); write_types(&mut buf, &shaders).unwrap(); write_shaders(&mut buf, &shaders).unwrap(); std::fs::write(dest_path, &buf).unwrap(); println!("cargo:rerun-if-changed=../shader"); } fn write_types(buf: &mut String, shaders: &[(String, ShaderInfo)]) -> Result<(), std::fmt::Error> { writeln!(buf, "pub struct Shaders<'a> {{")?; for (name, _) in shaders { writeln!(buf, " pub {name}: ComputeShader<'a>,")?; } writeln!(buf, "}}")?; writeln!(buf, "pub struct Pipelines {{")?; for (name, _) in shaders { writeln!(buf, " pub {name}: T,")?; } writeln!(buf, "}}")?; writeln!(buf, "impl Pipelines {{")?; writeln!(buf, " pub fn from_shaders>(shaders: &Shaders, device: &H::Device, host: &mut H) -> Result {{")?; writeln!(buf, " Ok(Self {{")?; for (name, _) in shaders { writeln!( buf, " {name}: host.new_compute_pipeline(device, &shaders.{name})?," )?; } writeln!(buf, " }})")?; writeln!(buf, " }}")?; writeln!(buf, "}}")?; Ok(()) } fn write_shaders( buf: &mut String, shaders: &[(String, ShaderInfo)], ) -> Result<(), std::fmt::Error> { writeln!(buf, "mod gen {{")?; writeln!(buf, " use super::*;")?; writeln!(buf, " use BindType::*;")?; writeln!(buf, " pub const SHADERS: Shaders<'static> = Shaders {{")?; for (name, info) in shaders { let bind_tys = info .bindings .iter() .map(|binding| binding.ty) .collect::>(); let wg_bufs = &info.workgroup_buffers; writeln!(buf, " {name}: ComputeShader {{")?; writeln!(buf, " name: Cow::Borrowed({:?}),", name)?; writeln!( buf, " workgroup_size: {:?},", info.workgroup_size )?; writeln!(buf, " bindings: Cow::Borrowed(&{:?}),", bind_tys)?; writeln!( buf, " workgroup_buffers: Cow::Borrowed(&{:?}),", wg_bufs )?; if cfg!(feature = "wgsl") { writeln!(buf, " wgsl: Cow::Borrowed({:?}),", info.source)?; } if cfg!(feature = "msl") { writeln!( buf, " msl: Cow::Borrowed({:?}),", compile::msl::translate(info).unwrap() )?; } writeln!(buf, " }},")?; } writeln!(buf, " }};")?; writeln!(buf, "}}")?; Ok(()) }