Skip to main content

henad_core/authoring/primitives/wgsl/
mod.rs

1//! The shared WGSL modules that a model shader imports with `#import henad::<module>`, as text.
2//!
3//! Three modules pair with Rust: `henad::dispatch` with the engine's linear dispatch, and `henad::rng` and
4//! `henad::space` with most of [`super::rng`] and [`super::space`]. `henad::dims` and `henad::reduce_tree` are shared
5//! modules without a Rust twin. `henad::dims` holds the uniform that the grid engine writes for a display or reduce
6//! shader, and `henad::reduce_tree` holds the workgroup sum that a reduce shader repeats.
7//!
8//! henad-build writes these modules beside a crate's shaders before it composes them. This text is the single source
9//! that every build and every host reads.
10
11use crate::explore::fingerprint::Fnv1a64;
12
13/// A WGSL module a model shader can `#import`, as text.
14#[derive(Clone, Copy)]
15pub struct SharedModule {
16    /// Path a shader imports, as in `henad::rng`.
17    pub import_path: &'static str,
18    /// WGSL text of the module.
19    pub source: &'static str,
20}
21
22/// Prints the source's length, not the source.
23impl std::fmt::Debug for SharedModule {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        f.debug_struct("SharedModule")
26            .field("import_path", &self.import_path)
27            .field("source_len", &self.source.len())
28            .finish_non_exhaustive()
29    }
30}
31
32/// `henad::dispatch`, `henad::dims`, `henad::rng`, `henad::space` and `henad::reduce_tree`.
33pub const SHARED_WGSL_MODULES: &[SharedModule] = &[
34    SharedModule {
35        import_path: "henad::dispatch",
36        source: include_str!("dispatch.wgsl"),
37    },
38    SharedModule {
39        import_path: "henad::dims",
40        source: include_str!("dims.wgsl"),
41    },
42    SharedModule {
43        import_path: "henad::rng",
44        source: include_str!("rng.wgsl"),
45    },
46    SharedModule {
47        import_path: "henad::space",
48        source: include_str!("space.wgsl"),
49    },
50    SharedModule {
51        import_path: "henad::reduce_tree",
52        source: include_str!("reduce_tree.wgsl"),
53    },
54];
55
56/// FNV-1a hash of every module's import path and source, in [`SHARED_WGSL_MODULES`] order.
57pub const SHARED_WGSL_FNV1A64: u64 = {
58    let mut hasher = Fnv1a64::new();
59    let mut index = 0;
60    while index < SHARED_WGSL_MODULES.len() {
61        hasher.write_str(SHARED_WGSL_MODULES[index].import_path);
62        hasher.write_str(SHARED_WGSL_MODULES[index].source);
63        index += 1;
64    }
65    hasher.finish()
66};
67
68#[cfg(test)]
69mod tests {
70    use super::{SHARED_WGSL_FNV1A64, SHARED_WGSL_MODULES};
71    use crate::explore::fingerprint::Fnv1a64;
72
73    #[test]
74    fn each_module_declares_its_import_path() {
75        for module in SHARED_WGSL_MODULES {
76            let first = module.source.lines().next().unwrap_or_default();
77            assert_eq!(first, format!("#define_import_path {}", module.import_path));
78        }
79    }
80
81    #[test]
82    fn the_const_hash_matches_one_computed_at_run_time() {
83        let mut hasher = Fnv1a64::new();
84        for module in SHARED_WGSL_MODULES {
85            hasher.write_str(module.import_path);
86            hasher.write_str(module.source);
87        }
88        assert_eq!(SHARED_WGSL_FNV1A64, hasher.finish());
89    }
90}