use askama::Template;
use crate::{
dynamic_materials::BucketEntry,
render_passes::material_classify::{
buffers::header_bytes, shader::cache_key::ShaderCacheKeyMaterialClassify,
},
shaders::{AwsmShaderError, Result},
};
pub struct ShaderTemplateMaterialClassify {
pub bind_groups: ShaderTemplateMaterialClassifyBindGroups,
pub compute: ShaderTemplateMaterialClassifyCompute,
}
#[derive(Template, Debug)]
#[template(
path = "material_classify_wgsl/bind_groups.wgsl",
whitespace = "minimize"
)]
pub struct ShaderTemplateMaterialClassifyBindGroups {
pub multisampled_geometry: bool,
pub bucket_entries: Vec<BucketEntry>,
pub pad_words_iter: Vec<u32>,
pub emit_edge_data: bool,
}
#[derive(Template, Debug)]
#[template(path = "material_classify_wgsl/compute.wgsl", whitespace = "minimize")]
pub struct ShaderTemplateMaterialClassifyCompute {
pub multisampled_geometry: bool,
pub shader_id_consts: String,
pub bucket_entries: Vec<BucketEntry>,
pub emit_edge_data: bool,
pub n_words: u32,
pub words_iter: Vec<u32>,
}
pub fn pad_words_count(bucket_count: u32) -> u32 {
let unpadded = bucket_count * 16 + bucket_count * 4 + 4; let padded = header_bytes(bucket_count);
(padded - unpadded) / 4
}
pub fn build_shader_id_consts_from_entries(entries: &[BucketEntry]) -> String {
let mut out = String::new();
for entry in entries {
out.push_str(&format!(
"const SHADER_ID_{}: u32 = {}u;\n",
entry.name.to_uppercase(),
entry.shader_id.as_u32(),
));
}
out
}
impl TryFrom<&ShaderCacheKeyMaterialClassify> for ShaderTemplateMaterialClassify {
type Error = AwsmShaderError;
fn try_from(key: &ShaderCacheKeyMaterialClassify) -> Result<Self> {
let multisampled_geometry = key.msaa_sample_count.is_some();
let bucket_entries = key.bucket_entries.clone();
let pad_words_iter = (0..pad_words_count(key.bucket_count())).collect();
let shader_id_consts = build_shader_id_consts_from_entries(&bucket_entries);
Ok(ShaderTemplateMaterialClassify {
bind_groups: ShaderTemplateMaterialClassifyBindGroups {
multisampled_geometry,
bucket_entries: bucket_entries.clone(),
pad_words_iter,
emit_edge_data: key.emit_edge_data,
},
compute: ShaderTemplateMaterialClassifyCompute {
multisampled_geometry,
shader_id_consts,
bucket_entries,
emit_edge_data: key.emit_edge_data,
n_words: crate::dynamic_materials::MAX_BUCKET_WORDS,
words_iter: (0..crate::dynamic_materials::MAX_BUCKET_WORDS).collect(),
},
})
}
}
impl ShaderTemplateMaterialClassify {
pub fn into_source(self) -> Result<String> {
let bind_groups_source = self.bind_groups.render()?;
let compute_source = self.compute.render()?;
Ok(format!("{}\n{}", bind_groups_source, compute_source))
}
pub fn debug_label(&self) -> Option<&str> {
Some("Material Classify")
}
}