use std::collections::HashMap;
use awsm_materials::MaterialShaderId;
use crate::dynamic_materials::ShadingBase;
use crate::error::Result;
use crate::pipeline_layouts::{PipelineLayoutCacheKey, PipelineLayoutKey};
use crate::pipelines::render_pipeline::RenderPipelineKey;
use crate::render_passes::geometry::bind_group::GeometryBindGroups;
use crate::render_passes::geometry::shader::masked_cache_key::DynamicAlphaShaderInfo;
use crate::render_passes::shadow_masked::bind_group::ShadowMaskedBindGroup;
use crate::render_passes::RenderPassInitContext;
use crate::shadows::shader::masked_cache_key::ShaderCacheKeyShadowMasked;
use crate::shadows::shadow_pipeline_cache_key;
#[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)]
pub struct MaskedShadowPipelineKeyId {
pub shader_id: MaterialShaderId,
pub instancing: bool,
pub cube_face: bool,
pub double_sided: bool,
}
#[derive(Clone)]
pub struct MaskedShadowVariant {
pub shader_id: MaterialShaderId,
pub base: ShadingBase,
pub dynamic_alpha: Option<DynamicAlphaShaderInfo>,
}
pub struct ShadowMaskedPipelines {
pipeline_layout_key_storage: PipelineLayoutKey,
pipeline_layout_key_uniform: PipelineLayoutKey,
main: HashMap<MaskedShadowPipelineKeyId, RenderPipelineKey>,
}
impl ShadowMaskedPipelines {
pub fn new(
ctx: &mut RenderPassInitContext<'_>,
masked_bind_group: &ShadowMaskedBindGroup,
geometry_bind_groups: &GeometryBindGroups,
) -> Result<Self> {
let (pipeline_layout_key_storage, pipeline_layout_key_uniform) =
resolve_layout_keys(ctx, masked_bind_group, geometry_bind_groups)?;
Ok(Self {
pipeline_layout_key_storage,
pipeline_layout_key_uniform,
main: HashMap::new(),
})
}
pub fn relayout(
&mut self,
ctx: &mut RenderPassInitContext<'_>,
masked_bind_group: &ShadowMaskedBindGroup,
geometry_bind_groups: &GeometryBindGroups,
) -> Result<()> {
let (storage, uniform) = resolve_layout_keys(ctx, masked_bind_group, geometry_bind_groups)?;
self.pipeline_layout_key_storage = storage;
self.pipeline_layout_key_uniform = uniform;
self.main.clear();
Ok(())
}
pub async fn ensure_variant(
&mut self,
ctx: &mut RenderPassInitContext<'_>,
masked_bind_group: &ShadowMaskedBindGroup,
variant: &MaskedShadowVariant,
) -> Result<()> {
for instancing in [false, true] {
let shader_cache = ShaderCacheKeyShadowMasked {
texture_pool_arrays_len: masked_bind_group.texture_pool_arrays_len,
texture_pool_samplers_len: masked_bind_group.texture_pool_sampler_keys.len() as u32,
shader_id: variant.shader_id,
base: variant.base,
dynamic_alpha: variant.dynamic_alpha.clone(),
instancing_transforms: instancing,
};
ctx.shaders
.ensure_keys(ctx.gpu, vec![shader_cache.clone().into()])
.await?;
let shader_key = ctx.shaders.get_key(ctx.gpu, shader_cache).await?;
let layout_key = if instancing {
self.pipeline_layout_key_uniform
} else {
self.pipeline_layout_key_storage
};
let combos: Vec<(bool, bool)> = [false, true]
.into_iter()
.flat_map(|cube_face| [false, true].into_iter().map(move |ds| (cube_face, ds)))
.collect();
let cache_keys: Vec<_> = combos
.iter()
.map(|&(cube_face, double_sided)| {
shadow_pipeline_cache_key(
shader_key,
layout_key,
instancing,
cube_face,
double_sided,
)
.with_force_fragment_stage()
})
.collect();
let keys = ctx
.pipelines
.render
.ensure_keys(ctx.gpu, ctx.shaders, ctx.pipeline_layouts, cache_keys)
.await?;
for ((cube_face, double_sided), key) in combos.into_iter().zip(keys) {
self.main.insert(
MaskedShadowPipelineKeyId {
shader_id: variant.shader_id,
instancing,
cube_face,
double_sided,
},
key,
);
}
}
Ok(())
}
pub fn clear(&mut self) {
self.main.clear();
}
pub fn get(
&self,
shader_id: MaterialShaderId,
instancing: bool,
cube_face: bool,
double_sided: bool,
) -> Option<RenderPipelineKey> {
self.main
.get(&MaskedShadowPipelineKeyId {
shader_id,
instancing,
cube_face,
double_sided,
})
.copied()
}
}
fn resolve_layout_keys(
ctx: &mut RenderPassInitContext<'_>,
masked_bind_group: &ShadowMaskedBindGroup,
geometry_bind_groups: &GeometryBindGroups,
) -> Result<(PipelineLayoutKey, PipelineLayoutKey)> {
let storage = ctx.pipeline_layouts.get_key(
ctx.gpu,
ctx.bind_group_layouts,
PipelineLayoutCacheKey::new(vec![
masked_bind_group.bind_group_layout_key,
geometry_bind_groups.transforms.bind_group_layout_key,
geometry_bind_groups.meta.storage_layout_key,
geometry_bind_groups.animation.bind_group_layout_key,
]),
)?;
let uniform = ctx.pipeline_layouts.get_key(
ctx.gpu,
ctx.bind_group_layouts,
PipelineLayoutCacheKey::new(vec![
masked_bind_group.bind_group_layout_key,
geometry_bind_groups.transforms.bind_group_layout_key,
geometry_bind_groups.meta.uniform_layout_key,
geometry_bind_groups.animation.bind_group_layout_key,
]),
)?;
Ok((storage, uniform))
}