2023-03-30 05:20:38 +11:00
|
|
|
// Copyright 2023 The Vello authors
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
|
|
|
2023-01-26 06:27:14 +11:00
|
|
|
#[path = "src/compile/mod.rs"]
|
|
|
|
mod compile;
|
|
|
|
#[path = "src/types.rs"]
|
|
|
|
mod types;
|
|
|
|
|
|
|
|
use std::env;
|
|
|
|
use std::fmt::Write;
|
2023-05-17 08:02:34 +10:00
|
|
|
use std::path::{Path, PathBuf};
|
2023-01-26 06:27:14 +11:00
|
|
|
|
|
|
|
use compile::ShaderInfo;
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
|
|
|
let dest_path = Path::new(&out_dir).join("shaders.rs");
|
2023-05-17 08:02:34 +10:00
|
|
|
|
|
|
|
// 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");
|
2023-05-19 09:13:32 +10:00
|
|
|
let mut shaders = compile::ShaderInfo::from_dir(shader_dir);
|
2023-05-17 08:02:34 +10:00
|
|
|
|
2023-01-26 08:02:57 +11:00
|
|
|
// Drop the HashMap and sort by name so that we get deterministic order.
|
|
|
|
let mut shaders = shaders.drain().collect::<Vec<_>>();
|
|
|
|
shaders.sort_by(|x, y| x.0.cmp(&y.0));
|
2023-01-26 06:27:14 +11:00
|
|
|
let mut buf = String::default();
|
|
|
|
write_types(&mut buf, &shaders).unwrap();
|
[shaders] Revise access to backend-agnostic metadata
Previously the generated shader data structures were rooted in
backend-specific top-level mods (`mod wgsl`, `mod msl`, etc). This made
access to per-shader information that is common to all backends (e.g.
workgroup sizes, shader name etc) awkward to access from backend
agnostic code, especially when feature-gated conditional compilation is
used on the client side.
The data structures have been rearranged such that there is a top-level
`ComputeShader` declaration for each stage under a `gen` mod. The
`ComputeShader` struct declares feature-gated fields for backend shader
sources, such that backend specific data is now a leaf node in the
structure rather than the root. This has some additional benefits:
1. Common data doesn't have to be redeclared, saving on code size when
multiple backends are enabled.
2. The backend specific source code was previously encoded as a `[u8]`.
We can now use types that more closely match the expected format, for
example `&str` for WGSL and MSL, `[u32]` for SPIR-V, etc.
3. If we ever need to expose additional backend-specific metadata in the
future, we can bundle them alongside the source code in a
backend-specific data structure at this level of the tree.
2023-05-11 07:03:50 +10:00
|
|
|
write_shaders(&mut buf, &shaders).unwrap();
|
2023-05-19 09:13:32 +10:00
|
|
|
std::fs::write(dest_path, &buf).unwrap();
|
2023-01-26 07:36:19 +11:00
|
|
|
println!("cargo:rerun-if-changed=../shader");
|
2023-01-26 06:27:14 +11:00
|
|
|
}
|
|
|
|
|
2023-01-26 08:05:01 +11:00
|
|
|
fn write_types(buf: &mut String, shaders: &[(String, ShaderInfo)]) -> Result<(), std::fmt::Error> {
|
2023-01-26 06:27:14 +11:00
|
|
|
writeln!(buf, "pub struct Shaders<'a> {{")?;
|
|
|
|
for (name, _) in shaders {
|
|
|
|
writeln!(buf, " pub {name}: ComputeShader<'a>,")?;
|
|
|
|
}
|
|
|
|
writeln!(buf, "}}")?;
|
|
|
|
writeln!(buf, "pub struct Pipelines<T> {{")?;
|
|
|
|
for (name, _) in shaders {
|
|
|
|
writeln!(buf, " pub {name}: T,")?;
|
|
|
|
}
|
|
|
|
writeln!(buf, "}}")?;
|
|
|
|
writeln!(buf, "impl<T> Pipelines<T> {{")?;
|
|
|
|
writeln!(buf, " pub fn from_shaders<H: PipelineHost<ComputePipeline = T>>(shaders: &Shaders, device: &H::Device, host: &mut H) -> Result<Self, H::Error> {{")?;
|
|
|
|
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,
|
2023-01-26 08:02:57 +11:00
|
|
|
shaders: &[(String, ShaderInfo)],
|
2023-01-26 06:27:14 +11:00
|
|
|
) -> Result<(), std::fmt::Error> {
|
[shaders] Revise access to backend-agnostic metadata
Previously the generated shader data structures were rooted in
backend-specific top-level mods (`mod wgsl`, `mod msl`, etc). This made
access to per-shader information that is common to all backends (e.g.
workgroup sizes, shader name etc) awkward to access from backend
agnostic code, especially when feature-gated conditional compilation is
used on the client side.
The data structures have been rearranged such that there is a top-level
`ComputeShader` declaration for each stage under a `gen` mod. The
`ComputeShader` struct declares feature-gated fields for backend shader
sources, such that backend specific data is now a leaf node in the
structure rather than the root. This has some additional benefits:
1. Common data doesn't have to be redeclared, saving on code size when
multiple backends are enabled.
2. The backend specific source code was previously encoded as a `[u8]`.
We can now use types that more closely match the expected format, for
example `&str` for WGSL and MSL, `[u32]` for SPIR-V, etc.
3. If we ever need to expose additional backend-specific metadata in the
future, we can bundle them alongside the source code in a
backend-specific data structure at this level of the tree.
2023-05-11 07:03:50 +10:00
|
|
|
writeln!(buf, "mod gen {{")?;
|
2023-01-26 06:27:14 +11:00
|
|
|
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::<Vec<_>>();
|
2023-03-30 04:27:16 +11:00
|
|
|
let wg_bufs = &info.workgroup_buffers;
|
2023-01-26 06:27:14 +11:00
|
|
|
writeln!(buf, " {name}: ComputeShader {{")?;
|
|
|
|
writeln!(buf, " name: Cow::Borrowed({:?}),", name)?;
|
|
|
|
writeln!(
|
|
|
|
buf,
|
|
|
|
" workgroup_size: {:?},",
|
|
|
|
info.workgroup_size
|
|
|
|
)?;
|
|
|
|
writeln!(buf, " bindings: Cow::Borrowed(&{:?}),", bind_tys)?;
|
2023-03-30 04:27:16 +11:00
|
|
|
writeln!(
|
|
|
|
buf,
|
|
|
|
" workgroup_buffers: Cow::Borrowed(&{:?}),",
|
|
|
|
wg_bufs
|
|
|
|
)?;
|
[shaders] Revise access to backend-agnostic metadata
Previously the generated shader data structures were rooted in
backend-specific top-level mods (`mod wgsl`, `mod msl`, etc). This made
access to per-shader information that is common to all backends (e.g.
workgroup sizes, shader name etc) awkward to access from backend
agnostic code, especially when feature-gated conditional compilation is
used on the client side.
The data structures have been rearranged such that there is a top-level
`ComputeShader` declaration for each stage under a `gen` mod. The
`ComputeShader` struct declares feature-gated fields for backend shader
sources, such that backend specific data is now a leaf node in the
structure rather than the root. This has some additional benefits:
1. Common data doesn't have to be redeclared, saving on code size when
multiple backends are enabled.
2. The backend specific source code was previously encoded as a `[u8]`.
We can now use types that more closely match the expected format, for
example `&str` for WGSL and MSL, `[u32]` for SPIR-V, etc.
3. If we ever need to expose additional backend-specific metadata in the
future, we can bundle them alongside the source code in a
backend-specific data structure at this level of the tree.
2023-05-11 07:03:50 +10:00
|
|
|
if cfg!(feature = "wgsl") {
|
2023-05-19 09:13:32 +10:00
|
|
|
writeln!(buf, " wgsl: Cow::Borrowed({:?}),", info.source)?;
|
[shaders] Revise access to backend-agnostic metadata
Previously the generated shader data structures were rooted in
backend-specific top-level mods (`mod wgsl`, `mod msl`, etc). This made
access to per-shader information that is common to all backends (e.g.
workgroup sizes, shader name etc) awkward to access from backend
agnostic code, especially when feature-gated conditional compilation is
used on the client side.
The data structures have been rearranged such that there is a top-level
`ComputeShader` declaration for each stage under a `gen` mod. The
`ComputeShader` struct declares feature-gated fields for backend shader
sources, such that backend specific data is now a leaf node in the
structure rather than the root. This has some additional benefits:
1. Common data doesn't have to be redeclared, saving on code size when
multiple backends are enabled.
2. The backend specific source code was previously encoded as a `[u8]`.
We can now use types that more closely match the expected format, for
example `&str` for WGSL and MSL, `[u32]` for SPIR-V, etc.
3. If we ever need to expose additional backend-specific metadata in the
future, we can bundle them alongside the source code in a
backend-specific data structure at this level of the tree.
2023-05-11 07:03:50 +10:00
|
|
|
}
|
|
|
|
if cfg!(feature = "msl") {
|
|
|
|
writeln!(
|
|
|
|
buf,
|
2023-05-19 09:13:32 +10:00
|
|
|
" msl: Cow::Borrowed({:?}),",
|
[shaders] Revise access to backend-agnostic metadata
Previously the generated shader data structures were rooted in
backend-specific top-level mods (`mod wgsl`, `mod msl`, etc). This made
access to per-shader information that is common to all backends (e.g.
workgroup sizes, shader name etc) awkward to access from backend
agnostic code, especially when feature-gated conditional compilation is
used on the client side.
The data structures have been rearranged such that there is a top-level
`ComputeShader` declaration for each stage under a `gen` mod. The
`ComputeShader` struct declares feature-gated fields for backend shader
sources, such that backend specific data is now a leaf node in the
structure rather than the root. This has some additional benefits:
1. Common data doesn't have to be redeclared, saving on code size when
multiple backends are enabled.
2. The backend specific source code was previously encoded as a `[u8]`.
We can now use types that more closely match the expected format, for
example `&str` for WGSL and MSL, `[u32]` for SPIR-V, etc.
3. If we ever need to expose additional backend-specific metadata in the
future, we can bundle them alongside the source code in a
backend-specific data structure at this level of the tree.
2023-05-11 07:03:50 +10:00
|
|
|
compile::msl::translate(info).unwrap()
|
|
|
|
)?;
|
|
|
|
}
|
2023-01-26 06:27:14 +11:00
|
|
|
writeln!(buf, " }},")?;
|
|
|
|
}
|
|
|
|
writeln!(buf, " }};")?;
|
|
|
|
writeln!(buf, "}}")?;
|
|
|
|
Ok(())
|
|
|
|
}
|