use alloc::vec::Vec;
#[derive(Debug)]
pub struct TonemapScratch {
chunk_pixels: usize,
linear_rgb: Vec<[f32; 3]>,
u8_rgb: Vec<[u8; 3]>,
}
impl Default for TonemapScratch {
fn default() -> Self {
Self::new()
}
}
impl TonemapScratch {
pub fn new() -> Self {
Self::with_chunk_size(4096)
}
pub fn with_chunk_size(chunk_pixels: usize) -> Self {
assert!(
chunk_pixels >= 8,
"chunk size must be at least 8 pixels for SIMD lanes"
);
Self {
chunk_pixels,
linear_rgb: Vec::new(),
u8_rgb: Vec::new(),
}
}
pub fn chunk_size(&self) -> usize {
self.chunk_pixels
}
pub(crate) fn linear_rgb(&mut self, len: usize) -> &mut [[f32; 3]] {
if self.linear_rgb.len() < len {
self.linear_rgb.resize(len, [0.0; 3]);
}
&mut self.linear_rgb[..len]
}
pub(crate) fn linear_and_u8(&mut self, len: usize) -> (&mut [[f32; 3]], &mut [[u8; 3]]) {
if self.linear_rgb.len() < len {
self.linear_rgb.resize(len, [0.0; 3]);
}
if self.u8_rgb.len() < len {
self.u8_rgb.resize(len, [0; 3]);
}
(&mut self.linear_rgb[..len], &mut self.u8_rgb[..len])
}
#[doc(hidden)]
pub fn linear_rgb_capacity(&self) -> usize {
self.linear_rgb.capacity()
}
#[doc(hidden)]
pub fn u8_rgb_capacity(&self) -> usize {
self.u8_rgb.capacity()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn defaults_to_4096() {
let s = TonemapScratch::new();
assert_eq!(s.chunk_size(), 4096);
}
#[test]
#[should_panic(expected = "at least 8 pixels")]
fn rejects_tiny_chunks() {
let _ = TonemapScratch::with_chunk_size(4);
}
#[test]
fn buffers_grow_only_as_needed() {
let mut s = TonemapScratch::with_chunk_size(64);
assert_eq!(s.linear_rgb_capacity(), 0);
let _ = s.linear_rgb(32);
assert!(s.linear_rgb_capacity() >= 32);
let cap_after_first = s.linear_rgb_capacity();
let _ = s.linear_rgb(8);
assert_eq!(s.linear_rgb_capacity(), cap_after_first);
}
}