use std::borrow::Cow;
use awsm_renderer_core::bind_groups::{
BindGroupDescriptor, BindGroupEntry, BindGroupLayoutResource, BindGroupResource,
StorageTextureAccess, StorageTextureBindingLayout, TextureBindingLayout,
};
use awsm_renderer_core::texture::{TextureFormat, TextureSampleType, TextureViewDimension};
use crate::bind_group_layout::{BindGroupLayoutCacheKey, BindGroupLayoutCacheKeyEntry};
use crate::bind_groups::{AwsmBindGroupError, BindGroupRecreateContext};
use crate::error::Result;
use crate::render_passes::hzb::texture::HzbTexture;
use crate::{bind_group_layout::BindGroupLayoutKey, render_passes::RenderPassInitContext};
pub struct HzbBindGroups {
pub seed_layout_key_msaa: BindGroupLayoutKey,
pub seed_layout_key_single: BindGroupLayoutKey,
pub reduce_layout_key: BindGroupLayoutKey,
seed_bind_group: Option<web_sys::GpuBindGroup>,
reduce_bind_groups: Vec<web_sys::GpuBindGroup>,
}
impl HzbBindGroups {
pub async fn new(ctx: &mut RenderPassInitContext<'_>) -> Result<Self> {
let seed_layout_key_msaa = create_seed_layout(ctx, true).await?;
let seed_layout_key_single = create_seed_layout(ctx, false).await?;
let reduce_layout_key = create_reduce_layout(ctx).await?;
Ok(Self {
seed_layout_key_msaa,
seed_layout_key_single,
reduce_layout_key,
seed_bind_group: None,
reduce_bind_groups: Vec::new(),
})
}
pub fn seed(&self) -> std::result::Result<&web_sys::GpuBindGroup, AwsmBindGroupError> {
self.seed_bind_group
.as_ref()
.ok_or_else(|| AwsmBindGroupError::NotFound("HZB Seed".to_string()))
}
pub fn reduce_at(
&self,
mip_transition: usize,
) -> std::result::Result<&web_sys::GpuBindGroup, AwsmBindGroupError> {
self.reduce_bind_groups.get(mip_transition).ok_or_else(|| {
AwsmBindGroupError::NotFound(format!("HZB Reduce mip transition {}", mip_transition))
})
}
pub fn recreate(&mut self, ctx: &BindGroupRecreateContext<'_>, hzb: &HzbTexture) -> Result<()> {
let seed_layout = if ctx.anti_aliasing.msaa_sample_count.is_some() {
self.seed_layout_key_msaa
} else {
self.seed_layout_key_single
};
let entries = vec![
BindGroupEntry::new(
0,
BindGroupResource::TextureView(Cow::Borrowed(&ctx.render_texture_views.depth)),
),
BindGroupEntry::new(
1,
BindGroupResource::TextureView(Cow::Borrowed(&hzb.views_per_mip[0])),
),
];
let descriptor = BindGroupDescriptor::new(
ctx.bind_group_layouts.get(seed_layout)?,
Some("HZB Seed"),
entries,
);
self.seed_bind_group = Some(ctx.gpu.create_bind_group(&descriptor.into()));
self.reduce_bind_groups.clear();
for n in 1..hzb.mip_count as usize {
let entries = vec![
BindGroupEntry::new(
0,
BindGroupResource::TextureView(Cow::Borrowed(&hzb.views_per_mip[n - 1])),
),
BindGroupEntry::new(
1,
BindGroupResource::TextureView(Cow::Borrowed(&hzb.views_per_mip[n])),
),
];
let descriptor = BindGroupDescriptor::new(
ctx.bind_group_layouts.get(self.reduce_layout_key)?,
Some("HZB Reduce"),
entries,
);
self.reduce_bind_groups
.push(ctx.gpu.create_bind_group(&descriptor.into()));
}
Ok(())
}
}
async fn create_seed_layout(
ctx: &mut RenderPassInitContext<'_>,
multisampled_geometry: bool,
) -> Result<BindGroupLayoutKey> {
let entries = vec![
BindGroupLayoutCacheKeyEntry {
resource: BindGroupLayoutResource::Texture(
TextureBindingLayout::new()
.with_view_dimension(TextureViewDimension::N2d)
.with_sample_type(TextureSampleType::Depth)
.with_multisampled(multisampled_geometry),
),
visibility_vertex: false,
visibility_fragment: false,
visibility_compute: true,
},
BindGroupLayoutCacheKeyEntry {
resource: BindGroupLayoutResource::StorageTexture(
StorageTextureBindingLayout::new(TextureFormat::R32float)
.with_view_dimension(TextureViewDimension::N2d)
.with_access(StorageTextureAccess::WriteOnly),
),
visibility_vertex: false,
visibility_fragment: false,
visibility_compute: true,
},
];
Ok(ctx
.bind_group_layouts
.get_key(ctx.gpu, BindGroupLayoutCacheKey { entries })?)
}
async fn create_reduce_layout(ctx: &mut RenderPassInitContext<'_>) -> Result<BindGroupLayoutKey> {
let entries = vec![
BindGroupLayoutCacheKeyEntry {
resource: BindGroupLayoutResource::Texture(
TextureBindingLayout::new()
.with_view_dimension(TextureViewDimension::N2d)
.with_sample_type(TextureSampleType::UnfilterableFloat),
),
visibility_vertex: false,
visibility_fragment: false,
visibility_compute: true,
},
BindGroupLayoutCacheKeyEntry {
resource: BindGroupLayoutResource::StorageTexture(
StorageTextureBindingLayout::new(TextureFormat::R32float)
.with_view_dimension(TextureViewDimension::N2d)
.with_access(StorageTextureAccess::WriteOnly),
),
visibility_vertex: false,
visibility_fragment: false,
visibility_compute: true,
},
];
Ok(ctx
.bind_group_layouts
.get_key(ctx.gpu, BindGroupLayoutCacheKey { entries })?)
}