fidget_core/render/
mod.rs1use crate::{
3 Error,
4 eval::{BulkEvaluator, Function, Trace, TracingEvaluator},
5 shape::{Shape, ShapeTape},
6};
7
8mod config;
9mod region;
10
11pub use config::{CancelToken, ThreadPool};
12pub use region::{ImageSize, RegionSize, VoxelSize};
13
14pub struct RenderHandle<F: Function, T = ()> {
21 shape: Shape<F, T>,
22
23 i_tape: Option<ShapeTape<<F::IntervalEval as TracingEvaluator>::Tape>>,
24 f_tape: Option<ShapeTape<<F::FloatSliceEval as BulkEvaluator>::Tape>>,
25 g_tape: Option<ShapeTape<<F::GradSliceEval as BulkEvaluator>::Tape>>,
26
27 next: Option<(F::Trace, Box<Self>)>,
28}
29
30impl<F: Function, T> Clone for RenderHandle<F, T> {
31 #[inline]
32 fn clone(&self) -> Self {
33 Self {
34 shape: self.shape.clone(),
35 i_tape: self.i_tape.clone(),
36 f_tape: self.f_tape.clone(),
37 g_tape: self.g_tape.clone(),
38 next: None,
39 }
40 }
41}
42
43impl<F: Function, T> RenderHandle<F, T> {
44 pub fn new(shape: Shape<F, T>) -> Self {
48 Self {
49 shape,
50 i_tape: None,
51 f_tape: None,
52 g_tape: None,
53 next: None,
54 }
55 }
56
57 #[inline]
59 pub fn i_tape(
60 &mut self,
61 storage: &mut Vec<F::TapeStorage>,
62 ) -> &ShapeTape<<F::IntervalEval as TracingEvaluator>::Tape> {
63 self.i_tape.get_or_insert_with(|| {
64 self.shape.interval_tape(storage.pop().unwrap_or_default())
65 })
66 }
67
68 #[inline]
70 pub fn f_tape(
71 &mut self,
72 storage: &mut Vec<F::TapeStorage>,
73 ) -> &ShapeTape<<F::FloatSliceEval as BulkEvaluator>::Tape> {
74 self.f_tape.get_or_insert_with(|| {
75 self.shape
76 .float_slice_tape(storage.pop().unwrap_or_default())
77 })
78 }
79
80 #[inline]
82 pub fn g_tape(
83 &mut self,
84 storage: &mut Vec<F::TapeStorage>,
85 ) -> &ShapeTape<<F::GradSliceEval as BulkEvaluator>::Tape> {
86 self.g_tape.get_or_insert_with(|| {
87 self.shape
88 .grad_slice_tape(storage.pop().unwrap_or_default())
89 })
90 }
91
92 #[inline]
97 pub fn simplify(
98 &mut self,
99 trace: &F::Trace,
100 workspace: &mut F::Workspace,
101 shape_storage: &mut Vec<F::Storage>,
102 tape_storage: &mut Vec<F::TapeStorage>,
103 ) -> &mut Self {
104 let mut trace_storage = if let Some(neighbor) = &self.next {
106 if &neighbor.0 != trace {
107 let (trace, neighbor) = self.next.take().unwrap();
108 neighbor.recycle(shape_storage, tape_storage);
109 Some(trace)
110 } else {
112 None
113 }
114 } else {
115 None
116 };
117
118 if self.next.is_none() {
122 let s = shape_storage.pop().unwrap_or_default();
123 let next = self.shape.simplify(trace, s, workspace).unwrap();
124 if next.size() >= self.shape.size() {
125 shape_storage.extend(next.recycle());
128 self
129 } else {
130 assert!(self.next.is_none());
131 if let Some(t) = trace_storage.as_mut() {
132 t.copy_from(trace);
133 } else {
134 trace_storage = Some(trace.clone());
135 }
136 self.next = Some((
137 trace_storage.unwrap(),
138 Box::new(RenderHandle {
139 shape: next,
140 i_tape: None,
141 f_tape: None,
142 g_tape: None,
143 next: None,
144 }),
145 ));
146 &mut self.next.as_mut().unwrap().1
147 }
148 } else {
149 &mut self.next.as_mut().unwrap().1
150 }
151 }
152
153 #[inline]
155 pub fn recycle(
156 mut self,
157 shape_storage: &mut Vec<F::Storage>,
158 tape_storage: &mut Vec<F::TapeStorage>,
159 ) {
160 if let Some((_trace, shape)) = self.next.take() {
162 shape.recycle(shape_storage, tape_storage);
163 }
164
165 if let Some(i_tape) = self.i_tape.take() {
166 tape_storage.extend(i_tape.recycle());
167 }
168 if let Some(g_tape) = self.g_tape.take() {
169 tape_storage.extend(g_tape.recycle());
170 }
171 if let Some(f_tape) = self.f_tape.take() {
172 tape_storage.extend(f_tape.recycle());
173 }
174
175 shape_storage.extend(self.shape.recycle());
177 }
178}
179
180#[derive(Debug, Eq, PartialEq)]
188pub struct TileSizes(Vec<usize>);
189
190impl TileSizes {
191 pub fn new(sizes: &[usize]) -> Result<Self, Error> {
193 if sizes.is_empty() {
194 return Err(Error::EmptyTileSizes);
195 }
196 for i in 1..sizes.len() {
197 if sizes[i - 1] <= sizes[i] {
198 return Err(Error::BadTileOrder(sizes[i - 1], sizes[i]));
199 } else if sizes[i - 1] % sizes[i] != 0 {
200 return Err(Error::BadTileSize(sizes[i - 1], sizes[i]));
201 }
202 }
203 Ok(Self(sizes.to_vec()))
204 }
205
206 #[allow(clippy::len_without_is_empty)]
208 pub fn len(&self) -> usize {
209 self.0.len()
210 }
211
212 pub fn iter(&self) -> impl Iterator<Item = &usize> {
214 self.0.iter()
215 }
216}
217
218impl std::ops::Index<usize> for TileSizes {
219 type Output = usize;
220
221 fn index(&self, i: usize) -> &Self::Output {
222 &self.0[i]
223 }
224}
225
226impl std::ops::Index<std::ops::RangeFrom<usize>> for TileSizes {
227 type Output = [usize];
228 fn index(&self, index: std::ops::RangeFrom<usize>) -> &Self::Output {
229 &self.0[index]
230 }
231}
232
233pub trait RenderHints {
239 fn tile_sizes_3d() -> TileSizes;
241
242 fn tile_sizes_2d() -> TileSizes;
244
245 fn simplify_tree_during_meshing(_d: usize) -> bool {
252 true
253 }
254}