Skip to content

Commit

Permalink
Make RenderHandle public and documented (#100)
Browse files Browse the repository at this point in the history
Same effect as #99 , but with additional cleanup + documentation
  • Loading branch information
mkeeter authored May 12, 2024
1 parent ba9b525 commit 89a8104
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 33 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- Updated `Context::import` to cache the `TreeOp → Node` mapping, which is a
minor optimization (probably only relevant for unreasonably large `Tree`
objects)
- Made `fidget::render::RenderHandle` public and documented

# 0.2.5
The highlight of this release is native Windows support (including JIT
Expand Down
4 changes: 4 additions & 0 deletions fidget/src/core/eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ pub use transform::TransformedShape;
/// most cases, they're a thin wrapper around an `Arc<..>`.
pub trait Shape: Send + Sync + Clone {
/// Associated type traces collected during tracing evaluation
///
/// This type must implement [`Eq`] so that traces can be compared; calling
/// [`Shape::simplify`] with traces that compare equal should produce an
/// identical result and may be cached.
type Trace: Clone + Eq + Send + Trace;

/// Associated type for storage used by the shape itself
Expand Down
79 changes: 60 additions & 19 deletions fidget/src/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,52 @@ pub use render3d::render as render3d;

pub use render2d::{BitRenderMode, DebugRenderMode, RenderMode, SdfRenderMode};

struct RenderHandle<S: Shape> {
/// A `RenderHandle` contains lazily-populated tapes for rendering
///
/// The tapes are stored as `Arc<..>`, so it can be cheaply cloned.
///
/// The most recent simplification is cached for reuse (if the trace matches).
pub struct RenderHandle<S: Shape> {
shape: S,

i_tape: Option<Arc<<S::IntervalEval as TracingEvaluator>::Tape>>,
f_tape: Option<<S::FloatSliceEval as BulkEvaluator>::Tape>,
g_tape: Option<<S::GradSliceEval as BulkEvaluator>::Tape>,
f_tape: Option<Arc<<S::FloatSliceEval as BulkEvaluator>::Tape>>,
g_tape: Option<Arc<<S::GradSliceEval as BulkEvaluator>::Tape>>,

next: Option<(S::Trace, Box<Self>)>,
}

impl<S: Shape> Clone for RenderHandle<S> {
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<S> RenderHandle<S>
where
S: Shape,
{
fn new(
shape: S,
i_tape: Arc<<S::IntervalEval as TracingEvaluator>::Tape>,
) -> Self {
/// Build a new [`RenderHandle`] for the given shape
///
/// None of the tapes are populated here.
pub fn new(shape: S) -> Self {
Self {
shape,
i_tape: Some(i_tape),
i_tape: None,
f_tape: None,
g_tape: None,
next: None,
}
}
fn i_tape(

/// Returns a tape for tracing interval evaluation
pub fn i_tape(
&mut self,
storage: &mut Vec<S::TapeStorage>,
) -> &<S::IntervalEval as TracingEvaluator>::Tape {
Expand All @@ -53,25 +72,38 @@ where
)
})
}
fn f_tape(

/// Returns a tape for bulk float evaluation
pub fn f_tape(
&mut self,
storage: &mut Vec<S::TapeStorage>,
) -> &<S::FloatSliceEval as BulkEvaluator>::Tape {
self.f_tape.get_or_insert_with(|| {
self.shape
.float_slice_tape(storage.pop().unwrap_or_default())
Arc::new(
self.shape
.float_slice_tape(storage.pop().unwrap_or_default()),
)
})
}
fn g_tape(

/// Returns a tape for bulk gradient evaluation
pub fn g_tape(
&mut self,
storage: &mut Vec<S::TapeStorage>,
) -> &<S::GradSliceEval as BulkEvaluator>::Tape {
self.g_tape.get_or_insert_with(|| {
self.shape
.grad_slice_tape(storage.pop().unwrap_or_default())
Arc::new(
self.shape
.grad_slice_tape(storage.pop().unwrap_or_default()),
)
})
}
fn simplify(

/// Simplifies the shape with the given trace
///
/// As an internal optimization, this may reuse a previous simplification if
/// the trace matches.
pub fn simplify(
&mut self,
trace: &S::Trace,
workspace: &mut S::Workspace,
Expand Down Expand Up @@ -127,7 +159,8 @@ where
}
}

fn recycle(
/// Recycles the entire handle into the given storage vectors
pub fn recycle(
mut self,
shape_storage: &mut Vec<S::Storage>,
tape_storage: &mut Vec<S::TapeStorage>,
Expand All @@ -142,8 +175,16 @@ where
tape_storage.push(i_tape.recycle());
}
}
tape_storage.extend(self.g_tape.map(Tape::recycle));
tape_storage.extend(self.f_tape.map(Tape::recycle));
if let Some(g_tape) = self.g_tape.take() {
if let Ok(g_tape) = Arc::try_unwrap(g_tape) {
tape_storage.push(g_tape.recycle());
}
}
if let Some(f_tape) = self.f_tape.take() {
if let Ok(f_tape) = Arc::try_unwrap(f_tape) {
tape_storage.push(f_tape.recycle());
}
}

// Do this step last because the evaluators may borrow the shape
shape_storage.extend(self.shape.recycle());
Expand Down
12 changes: 6 additions & 6 deletions fidget/src/render/render2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::{
types::Interval,
};
use nalgebra::Point2;
use std::sync::Arc;

////////////////////////////////////////////////////////////////////////////////

Expand Down Expand Up @@ -363,13 +362,14 @@ fn render_inner<S: Shape, M: RenderMode + Sync>(
}
}

let i_tape = Arc::new(shape.interval_tape(Default::default()));
let queue = Queue::new(tiles);
let threads = config.threads();

let mut rh = RenderHandle::new(shape);
let _ = rh.i_tape(&mut vec![]); // populate i_tape before cloning

let out: Vec<_> = if threads == 1 {
let shape = RenderHandle::new(shape, i_tape);
worker::<S, M>(shape, &queue, &config, mode)
worker::<S, M>(rh, &queue, &config, mode)
.into_iter()
.collect()
} else {
Expand All @@ -380,9 +380,9 @@ fn render_inner<S: Shape, M: RenderMode + Sync>(
std::thread::scope(|s| {
let mut handles = vec![];
for _ in 0..threads {
let shape = RenderHandle::new(shape.clone(), i_tape.clone());
let rh = rh.clone();
handles.push(
s.spawn(|| worker::<S, M>(shape, &queue, &config, mode)),
s.spawn(|| worker::<S, M>(rh, &queue, &config, mode)),
);
}
let mut out = vec![];
Expand Down
15 changes: 7 additions & 8 deletions fidget/src/render/render3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
};

use nalgebra::Point3;
use std::{collections::HashMap, sync::Arc};
use std::collections::HashMap;

////////////////////////////////////////////////////////////////////////////////

Expand Down Expand Up @@ -380,12 +380,12 @@ pub fn render_inner<S: Shape>(
}
tile_queues.resize_with(threads, || Queue::new(vec![]));

let i_tape = Arc::new(shape.interval_tape(Default::default()));
let mut rh = RenderHandle::new(shape);
let _ = rh.i_tape(&mut vec![]); // populate i_tape before cloning

// Special-case for single-threaded operation, to give simpler backtraces
let out: Vec<_> = if threads == 1 {
let shape = RenderHandle::new(shape, i_tape);
worker::<S>(shape, tile_queues.as_slice(), 0, &config)
worker::<S>(rh, tile_queues.as_slice(), 0, &config)
.into_iter()
.collect()
} else {
Expand All @@ -398,10 +398,9 @@ pub fn render_inner<S: Shape>(
let mut handles = vec![];
let queues = tile_queues.as_slice();
for i in 0..threads {
let handle = RenderHandle::new(shape.clone(), i_tape.clone());
handles.push(
s.spawn(move || worker::<S>(handle, queues, i, config)),
);
let rh = rh.clone();
handles
.push(s.spawn(move || worker::<S>(rh, queues, i, config)));
}
let mut out = vec![];
for h in handles {
Expand Down

0 comments on commit 89a8104

Please sign in to comment.