use crate::error::Result;
use crate::pipeline_layouts::{PipelineLayoutCacheKey, PipelineLayoutKey};
use crate::pipelines::compute_pipeline::{ComputePipelineCacheKey, ComputePipelineKey};
use crate::render_passes::material_decal::{
bind_group::MaterialDecalBindGroups, shader::cache_key::ShaderCacheKeyMaterialDecal,
};
use crate::render_passes::RenderPassInitContext;
use crate::shaders::ShaderCacheKey;
pub struct MaterialDecalPipelines {
pub singlesampled_pipeline_key: ComputePipelineKey,
pub multisampled_pipeline_key: ComputePipelineKey,
}
struct DecalShaderDesc {
shader_cache: ShaderCacheKey,
layout_key: PipelineLayoutKey,
is_msaa: bool,
}
pub struct MaterialDecalPipelineDescriptors {
pub shader_cache_keys: Vec<ShaderCacheKey>,
pub pipeline_cache_keys: Vec<ComputePipelineCacheKey>,
pub is_msaa: Vec<bool>,
}
impl MaterialDecalPipelines {
pub async fn new(
ctx: &mut RenderPassInitContext<'_>,
bind_groups: &MaterialDecalBindGroups,
) -> Result<Self> {
let shader_descs = Self::shader_descs(ctx, bind_groups)?;
ctx.shaders
.ensure_keys(ctx.gpu, shader_descs.iter().map(|d| d.shader_cache.clone()))
.await?;
let descs =
Self::build_descriptors_from_shader_descs(ctx.gpu, ctx.shaders, shader_descs).await?;
let pipeline_keys = ctx
.pipelines
.compute
.ensure_keys(
ctx.gpu,
ctx.shaders,
ctx.pipeline_layouts,
descs.pipeline_cache_keys.clone(),
)
.await?;
Ok(Self::from_resolved(descs.is_msaa, pipeline_keys))
}
fn shader_descs(
ctx: &mut RenderPassInitContext<'_>,
bind_groups: &MaterialDecalBindGroups,
) -> Result<Vec<DecalShaderDesc>> {
let singlesampled_pipeline_layout_key = ctx.pipeline_layouts.get_key(
ctx.gpu,
ctx.bind_group_layouts,
PipelineLayoutCacheKey::new(vec![
bind_groups.main_layout_key_singlesampled,
bind_groups.texture_pool_layout_key,
]),
)?;
let multisampled_pipeline_layout_key = ctx.pipeline_layouts.get_key(
ctx.gpu,
ctx.bind_group_layouts,
PipelineLayoutCacheKey::new(vec![
bind_groups.main_layout_key_multisampled,
bind_groups.texture_pool_layout_key,
]),
)?;
let texture_pool_layers_per_array = crate::decals::decal_texture_index_stride(ctx.gpu);
Ok(vec![
DecalShaderDesc {
shader_cache: ShaderCacheKey::from(ShaderCacheKeyMaterialDecal {
msaa_sample_count: None,
texture_pool_arrays_len: bind_groups.texture_pool_arrays_len,
texture_pool_samplers_len: bind_groups.texture_pool_samplers_len,
texture_pool_layers_per_array,
}),
layout_key: singlesampled_pipeline_layout_key,
is_msaa: false,
},
DecalShaderDesc {
shader_cache: ShaderCacheKey::from(ShaderCacheKeyMaterialDecal {
msaa_sample_count: Some(4),
texture_pool_arrays_len: bind_groups.texture_pool_arrays_len,
texture_pool_samplers_len: bind_groups.texture_pool_samplers_len,
texture_pool_layers_per_array,
}),
layout_key: multisampled_pipeline_layout_key,
is_msaa: true,
},
])
}
pub fn build_shader_cache_keys(
ctx: &mut RenderPassInitContext<'_>,
bind_groups: &MaterialDecalBindGroups,
) -> Result<Vec<ShaderCacheKey>> {
Ok(Self::shader_descs(ctx, bind_groups)?
.into_iter()
.map(|d| d.shader_cache)
.collect())
}
pub async fn build_descriptors(
ctx: &mut RenderPassInitContext<'_>,
bind_groups: &MaterialDecalBindGroups,
) -> Result<MaterialDecalPipelineDescriptors> {
let shader_descs = Self::shader_descs(ctx, bind_groups)?;
Self::build_descriptors_from_shader_descs(ctx.gpu, ctx.shaders, shader_descs).await
}
async fn build_descriptors_from_shader_descs(
gpu: &awsm_renderer_core::renderer::AwsmRendererWebGpu,
shaders: &mut crate::shaders::Shaders,
shader_descs: Vec<DecalShaderDesc>,
) -> Result<MaterialDecalPipelineDescriptors> {
let mut shader_cache_keys = Vec::with_capacity(shader_descs.len());
let mut pipeline_cache_keys = Vec::with_capacity(shader_descs.len());
let mut is_msaa = Vec::with_capacity(shader_descs.len());
for d in shader_descs {
let shader_key = shaders.get_key(gpu, d.shader_cache.clone()).await?;
shader_cache_keys.push(d.shader_cache);
pipeline_cache_keys.push(ComputePipelineCacheKey::new(shader_key, d.layout_key));
is_msaa.push(d.is_msaa);
}
Ok(MaterialDecalPipelineDescriptors {
shader_cache_keys,
pipeline_cache_keys,
is_msaa,
})
}
pub fn from_resolved(is_msaa: Vec<bool>, pipeline_keys: Vec<ComputePipelineKey>) -> Self {
let mut singlesampled_pipeline_key: Option<ComputePipelineKey> = None;
let mut multisampled_pipeline_key: Option<ComputePipelineKey> = None;
for (msaa, key) in is_msaa.into_iter().zip(pipeline_keys) {
if msaa {
multisampled_pipeline_key = Some(key);
} else {
singlesampled_pipeline_key = Some(key);
}
}
Self {
singlesampled_pipeline_key: singlesampled_pipeline_key
.expect("decal singlesampled pipeline slot must be filled"),
multisampled_pipeline_key: multisampled_pipeline_key
.expect("decal multisampled pipeline slot must be filled"),
}
}
}