use crate::{
eval::{BulkEvaluator, Function, Trace, TracingEvaluator},
shape::{Shape, ShapeTape},
};
mod config;
mod region;
pub use config::{CancelToken, ThreadPool};
pub use region::{ImageSize, RegionSize, VoxelSize};
pub struct RenderHandle<F: Function> {
shape: Shape<F>,
i_tape: Option<ShapeTape<<F::IntervalEval as TracingEvaluator>::Tape>>,
f_tape: Option<ShapeTape<<F::FloatSliceEval as BulkEvaluator>::Tape>>,
g_tape: Option<ShapeTape<<F::GradSliceEval as BulkEvaluator>::Tape>>,
next: Option<(F::Trace, Box<Self>)>,
}
impl<F: Function> Clone for RenderHandle<F> {
#[inline]
fn clone(&self) -> Self {
Self {
shape: self.shape.clone(),
i_tape: self.i_tape.clone(),
f_tape: self.f_tape.clone(),
g_tape: self.g_tape.clone(),
next: None,
}
}
}
impl<F: Function> RenderHandle<F> {
pub fn new(shape: Shape<F>) -> Self {
Self {
shape,
i_tape: None,
f_tape: None,
g_tape: None,
next: None,
}
}
#[inline]
pub fn i_tape(
&mut self,
storage: &mut Vec<F::TapeStorage>,
) -> &ShapeTape<<F::IntervalEval as TracingEvaluator>::Tape> {
self.i_tape.get_or_insert_with(|| {
self.shape.interval_tape(storage.pop().unwrap_or_default())
})
}
#[inline]
pub fn f_tape(
&mut self,
storage: &mut Vec<F::TapeStorage>,
) -> &ShapeTape<<F::FloatSliceEval as BulkEvaluator>::Tape> {
self.f_tape.get_or_insert_with(|| {
self.shape
.float_slice_tape(storage.pop().unwrap_or_default())
})
}
#[inline]
pub fn g_tape(
&mut self,
storage: &mut Vec<F::TapeStorage>,
) -> &ShapeTape<<F::GradSliceEval as BulkEvaluator>::Tape> {
self.g_tape.get_or_insert_with(|| {
self.shape
.grad_slice_tape(storage.pop().unwrap_or_default())
})
}
#[inline]
pub fn simplify(
&mut self,
trace: &F::Trace,
workspace: &mut F::Workspace,
shape_storage: &mut Vec<F::Storage>,
tape_storage: &mut Vec<F::TapeStorage>,
) -> &mut Self {
let mut trace_storage = if let Some(neighbor) = &self.next {
if &neighbor.0 != trace {
let (trace, neighbor) = self.next.take().unwrap();
neighbor.recycle(shape_storage, tape_storage);
Some(trace)
} else {
None
}
} else {
None
};
#[allow(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
if self.next.is_none() {
let s = shape_storage.pop().unwrap_or_default();
let next = self.shape.simplify(trace, s, workspace).unwrap();
if next.size() >= self.shape.size() {
shape_storage.extend(next.recycle());
self
} else {
assert!(self.next.is_none());
if let Some(t) = trace_storage.as_mut() {
t.copy_from(trace);
} else {
trace_storage = Some(trace.clone());
}
self.next = Some((
trace_storage.unwrap(),
Box::new(RenderHandle {
shape: next,
i_tape: None,
f_tape: None,
g_tape: None,
next: None,
}),
));
&mut self.next.as_mut().unwrap().1
}
} else {
&mut self.next.as_mut().unwrap().1
}
}
#[inline]
pub fn recycle(
mut self,
shape_storage: &mut Vec<F::Storage>,
tape_storage: &mut Vec<F::TapeStorage>,
) {
if let Some((_trace, shape)) = self.next.take() {
shape.recycle(shape_storage, tape_storage);
}
if let Some(i_tape) = self.i_tape.take() {
tape_storage.extend(i_tape.recycle());
}
if let Some(g_tape) = self.g_tape.take() {
tape_storage.extend(g_tape.recycle());
}
if let Some(f_tape) = self.f_tape.take() {
tape_storage.extend(f_tape.recycle());
}
shape_storage.extend(self.shape.recycle());
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct TileSizes(Vec<usize>);
#[derive(thiserror::Error, Debug)]
pub enum TileSizeError {
#[error("bad tile sizes; {0} is not divisible by {1}")]
BadTileSize(usize, usize),
#[error("bad tile order; {0} is not larger than {1}")]
BadTileOrder(usize, usize),
#[error("tile size list must not be empty")]
EmptyTileSizes,
}
impl TileSizes {
pub fn new(sizes: &[usize]) -> Result<Self, TileSizeError> {
if sizes.is_empty() {
return Err(TileSizeError::EmptyTileSizes);
}
for i in 1..sizes.len() {
if sizes[i - 1] <= sizes[i] {
return Err(TileSizeError::BadTileOrder(
sizes[i - 1],
sizes[i],
));
} else if !sizes[i - 1].is_multiple_of(sizes[i]) {
return Err(TileSizeError::BadTileSize(sizes[i - 1], sizes[i]));
}
}
Ok(Self(sizes.to_vec()))
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.0.len()
}
pub fn iter(&self) -> impl Iterator<Item = &usize> {
self.0.iter()
}
}
impl std::ops::Index<usize> for TileSizes {
type Output = usize;
fn index(&self, i: usize) -> &Self::Output {
&self.0[i]
}
}
impl std::ops::Index<std::ops::RangeFrom<usize>> for TileSizes {
type Output = [usize];
fn index(&self, index: std::ops::RangeFrom<usize>) -> &Self::Output {
&self.0[index]
}
}
pub trait RenderHints {
fn tile_sizes_3d() -> TileSizes;
fn tile_sizes_2d() -> TileSizes;
fn simplify_tree_during_meshing(_d: usize) -> bool {
true
}
}