use awsm_renderer_core::{
error::{AwsmCoreError, Result},
renderer::AwsmRendererWebGpu,
texture::{
Extent3d, TextureDescriptor, TextureFormat, TextureUsage, TextureViewDescriptor,
TextureViewDimension,
},
};
pub struct HzbTexture {
pub texture: web_sys::GpuTexture,
pub view_all: web_sys::GpuTextureView,
pub views_per_mip: Vec<web_sys::GpuTextureView>,
pub width: u32,
pub height: u32,
pub mip_count: u32,
}
impl HzbTexture {
pub fn new(gpu: &AwsmRendererWebGpu, width: u32, height: u32) -> Result<Self> {
let width = width.max(1);
let height = height.max(1);
let max_dim = width.max(height);
let mip_count = 32u32 - max_dim.leading_zeros();
let mip_count = mip_count.max(1);
let texture = gpu.create_texture(
&TextureDescriptor::new(
TextureFormat::R32float,
Extent3d::new(width, Some(height), Some(1)),
TextureUsage::new()
.with_storage_binding()
.with_texture_binding(),
)
.with_label("HZB")
.with_mip_level_count(mip_count)
.into(),
)?;
let view_all = {
let descriptor: web_sys::GpuTextureViewDescriptor =
TextureViewDescriptor::new(Some("HZB All Mips"))
.with_dimension(TextureViewDimension::N2d)
.with_mip_level_count(mip_count)
.into();
texture
.create_view_with_descriptor(&descriptor)
.map_err(AwsmCoreError::create_texture_view)?
};
let mut views_per_mip = Vec::with_capacity(mip_count as usize);
for mip in 0..mip_count {
let descriptor: web_sys::GpuTextureViewDescriptor =
TextureViewDescriptor::new(Some("HZB Mip"))
.with_dimension(TextureViewDimension::N2d)
.with_base_mip_level(mip)
.with_mip_level_count(1)
.into();
let view = texture
.create_view_with_descriptor(&descriptor)
.map_err(AwsmCoreError::create_texture_view)?;
views_per_mip.push(view);
}
Ok(Self {
texture,
view_all,
views_per_mip,
width,
height,
mip_count,
})
}
pub fn mip_dims(&self, level: u32) -> (u32, u32) {
let w = (self.width >> level).max(1);
let h = (self.height >> level).max(1);
(w, h)
}
}