use awsm_renderer_core::{
buffers::{BufferDescriptor, BufferUsage},
command::CommandEncoder,
error::AwsmCoreError,
renderer::AwsmRendererWebGpu,
};
pub const HEADER_BYTES: u32 = 16;
pub const BUCKET_CAPACITY: u32 = 32;
pub const PER_TILE_BYTES: u32 = 4 + BUCKET_CAPACITY * 4;
pub struct DecalClassifyBuffers {
pub buffer: web_sys::GpuBuffer,
pub tile_count_x: u32,
pub tile_count_y: u32,
pub size_bytes: u32,
}
impl DecalClassifyBuffers {
pub fn new(gpu: &AwsmRendererWebGpu) -> Result<Self, AwsmCoreError> {
Self::with_tile_count(gpu, 1, 1)
}
fn with_tile_count(
gpu: &AwsmRendererWebGpu,
tile_count_x: u32,
tile_count_y: u32,
) -> Result<Self, AwsmCoreError> {
let tile_count_x = tile_count_x.max(1);
let tile_count_y = tile_count_y.max(1);
let tile_count = tile_count_x.saturating_mul(tile_count_y);
let size_bytes = HEADER_BYTES + tile_count.saturating_mul(PER_TILE_BYTES);
let buffer = gpu.create_buffer(
&BufferDescriptor::new(
Some("DecalClassifyBuckets"),
size_bytes as usize,
BufferUsage::new().with_storage().with_copy_dst(),
)
.into(),
)?;
let mut header_bytes = [0u8; HEADER_BYTES as usize];
write_header(&mut header_bytes, tile_count_x, tile_count_y);
gpu.write_buffer(&buffer, None, header_bytes.as_slice(), None, None)?;
Ok(Self {
buffer,
tile_count_x,
tile_count_y,
size_bytes,
})
}
pub fn ensure_capacity(
&mut self,
gpu: &AwsmRendererWebGpu,
needed_x: u32,
needed_y: u32,
) -> Result<bool, AwsmCoreError> {
if needed_x <= self.tile_count_x && needed_y <= self.tile_count_y {
return Ok(false);
}
let new_x = needed_x.max(self.tile_count_x);
let new_y = needed_y.max(self.tile_count_y);
*self = Self::with_tile_count(gpu, new_x, new_y)?;
Ok(true)
}
pub fn reset_counts(&self, encoder: &CommandEncoder) {
encoder.clear_buffer(
&self.buffer,
Some(HEADER_BYTES),
Some(self.size_bytes.saturating_sub(HEADER_BYTES)),
);
}
}
fn write_header(dst: &mut [u8], tile_count_x: u32, tile_count_y: u32) {
dst[0..4].copy_from_slice(&tile_count_x.to_ne_bytes());
dst[4..8].copy_from_slice(&tile_count_y.to_ne_bytes());
dst[8..12].copy_from_slice(&BUCKET_CAPACITY.to_ne_bytes());
dst[12..16].copy_from_slice(&0u32.to_ne_bytes());
}