use crate::optics::materials::{CrystalSystem, GemMaterial};
use super::{SHADER_SRC, renderer::GpuFrameRenderer};
use crate::renderer::gpu::{compute, pipeline_cache};
pub mod material_class {
pub const GENERIC: u32 = 0;
pub const ISOTROPIC: u32 = 1;
pub const UNIAXIAL: u32 = 2;
pub const BIAXIAL: u32 = 3;
}
#[must_use]
pub fn classify_material(material: &GemMaterial) -> u32 {
if material.biaxial_delta_beta_alpha.is_some() {
material_class::BIAXIAL
} else if material.crystal_system != CrystalSystem::Cubic
&& material.birefringence_delta.abs() > 1e-4
{
material_class::UNIAXIAL
} else {
material_class::ISOTROPIC
}
}
impl GpuFrameRenderer {
pub(super) fn ensure_specialized_pipeline(&mut self, class: u32) {
debug_assert!(
class <= material_class::BIAXIAL,
"ensure_specialized_pipeline: class out of range (must be <= material_class::BIAXIAL)"
);
let (slot, label) = match class {
material_class::ISOTROPIC => (
&mut self.pipeline_isotropic,
"transport_main (MATERIAL_CLASS=isotropic)",
),
material_class::UNIAXIAL => (
&mut self.pipeline_uniaxial,
"transport_main (MATERIAL_CLASS=uniaxial)",
),
material_class::BIAXIAL => (
&mut self.pipeline_biaxial,
"transport_main (MATERIAL_CLASS=biaxial)",
),
_ => return,
};
if slot.is_none() {
*slot = Some(compute::create_compute_pipeline_cached(
&self.ctx.device,
self.pipeline_cache.as_ref(),
label,
SHADER_SRC,
"transport_main",
&[("MATERIAL_CLASS", f64::from(class))],
));
if let Some(cache) = self.pipeline_cache.as_ref() {
pipeline_cache::persist(cache, &self.ctx.adapter.get_info());
}
}
}
fn generic_pipeline(&self) -> &wgpu::ComputePipeline {
self.pipeline_generic.get_or_init(|| {
compute::create_compute_pipeline_cached(
&self.ctx.device,
self.pipeline_cache.as_ref(),
"transport_main",
SHADER_SRC,
"transport_main",
&[],
)
})
}
pub(super) fn pipeline_for_class(&self, class: u32) -> &wgpu::ComputePipeline {
debug_assert!(
class <= material_class::BIAXIAL,
"pipeline_for_class: class out of range (must be <= material_class::BIAXIAL)"
);
match class {
material_class::ISOTROPIC => self.pipeline_isotropic.as_ref(),
material_class::UNIAXIAL => self.pipeline_uniaxial.as_ref(),
material_class::BIAXIAL => self.pipeline_biaxial.as_ref(),
_ => return self.generic_pipeline(),
}
.expect("ensure_specialized_pipeline must be called for this class before dispatching")
}
}