resolve merge: bug fixes with LUT caching and SAH BVH
This commit is contained in:
commit
afd3d6a409
|
|
@ -47,7 +47,7 @@ impl CORDICProgram {
|
||||||
/// counts are resolved from the CordicConfig if present, otherwise
|
/// counts are resolved from the CordicConfig if present, otherwise
|
||||||
/// all ops use word_bits as their iteration count.
|
/// all ops use word_bits as their iteration count.
|
||||||
pub fn compile(graph: &TrigGraph, config: &CompileConfig) -> Self {
|
pub fn compile(graph: &TrigGraph, config: &CompileConfig) -> Self {
|
||||||
let frac_bits = config.word_bits - 1;
|
let frac_bits = config.word_bits / 2;
|
||||||
let to_fixed = |val: f64| -> i64 {
|
let to_fixed = |val: f64| -> i64 {
|
||||||
(val * (1i64 << frac_bits) as f64).round() as i64
|
(val * (1i64 << frac_bits) as f64).round() as i64
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ pub struct CORDICEvaluator {
|
||||||
|
|
||||||
impl CORDICEvaluator {
|
impl CORDICEvaluator {
|
||||||
pub fn new(word_bits: u8) -> Self {
|
pub fn new(word_bits: u8) -> Self {
|
||||||
let frac_bits = word_bits - 1;
|
let frac_bits = word_bits / 2;
|
||||||
CORDICEvaluator {
|
CORDICEvaluator {
|
||||||
frac_bits,
|
frac_bits,
|
||||||
instr_table_idx: Vec::new(),
|
instr_table_idx: Vec::new(),
|
||||||
|
|
@ -26,7 +26,7 @@ impl CORDICEvaluator {
|
||||||
/// Create an evaluator from a compiled program, inheriting per-op tables.
|
/// Create an evaluator from a compiled program, inheriting per-op tables.
|
||||||
pub fn from_program(program: &CORDICProgram) -> Self {
|
pub fn from_program(program: &CORDICProgram) -> Self {
|
||||||
CORDICEvaluator {
|
CORDICEvaluator {
|
||||||
frac_bits: program.word_bits - 1,
|
frac_bits: program.word_bits / 2,
|
||||||
instr_table_idx: program.instr_table_idx.clone(),
|
instr_table_idx: program.instr_table_idx.clone(),
|
||||||
tables: program.tables.clone(),
|
tables: program.tables.clone(),
|
||||||
}
|
}
|
||||||
|
|
@ -190,15 +190,17 @@ impl CORDICEvaluator {
|
||||||
let (_, angle) = self.cordic_vectoring_with(one, vals[*a as usize], t);
|
let (_, angle) = self.cordic_vectoring_with(one, vals[*a as usize], t);
|
||||||
angle
|
angle
|
||||||
}
|
}
|
||||||
TrigOp::Sinh(a) => self.to_fixed(self.to_float(vals[*a as usize]).sinh()),
|
// Phasor-mode CORDIC implementation coming
|
||||||
TrigOp::Cosh(a) => self.to_fixed(self.to_float(vals[*a as usize]).cosh()),
|
TrigOp::Sinh(_) => unimplemented!("sinh: phasor CORDIC pending"),
|
||||||
TrigOp::Tanh(a) => self.to_fixed(self.to_float(vals[*a as usize]).tanh()),
|
TrigOp::Cosh(_) => unimplemented!("cosh: phasor CORDIC pending"),
|
||||||
|
TrigOp::Tanh(_) => unimplemented!("tanh: phasor CORDIC pending"),
|
||||||
|
TrigOp::Exp(_) => unimplemented!("exp: phasor CORDIC pending"),
|
||||||
|
TrigOp::Ln(_) => unimplemented!("ln: phasor CORDIC pending"),
|
||||||
|
|
||||||
TrigOp::Asinh(a) => self.to_fixed(self.to_float(vals[*a as usize]).asinh()),
|
TrigOp::Asinh(a) => self.to_fixed(self.to_float(vals[*a as usize]).asinh()),
|
||||||
TrigOp::Acosh(a) => self.to_fixed(self.to_float(vals[*a as usize]).acosh()),
|
TrigOp::Acosh(a) => self.to_fixed(self.to_float(vals[*a as usize]).acosh()),
|
||||||
TrigOp::Atanh(a) => self.to_fixed(self.to_float(vals[*a as usize]).atanh()),
|
TrigOp::Atanh(a) => self.to_fixed(self.to_float(vals[*a as usize]).atanh()),
|
||||||
TrigOp::Sqrt(a) => self.fixed_sqrt(vals[*a as usize]),
|
TrigOp::Sqrt(a) => self.fixed_sqrt(vals[*a as usize]),
|
||||||
TrigOp::Exp(a) => self.to_fixed(self.to_float(vals[*a as usize]).exp()),
|
|
||||||
TrigOp::Ln(a) => self.to_fixed(self.to_float(vals[*a as usize]).ln()),
|
|
||||||
|
|
||||||
TrigOp::Hypot(a, b) => {
|
TrigOp::Hypot(a, b) => {
|
||||||
let t = if use_per_instr { self.table_for(i) } else { &self.tables[0] };
|
let t = if use_per_instr { self.table_for(i) } else { &self.tables[0] };
|
||||||
|
|
|
||||||
|
|
@ -235,17 +235,17 @@ fn align_box_axes(
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut assignment = [0usize; 3];
|
let mut assignment = [0usize; 3];
|
||||||
let mut src_used = [false; 3];
|
let mut src_assigned = [false; 3];
|
||||||
let mut dst_used = [false; 3];
|
let mut dst_assigned = [false; 3];
|
||||||
|
|
||||||
for _ in 0..3 {
|
for _ in 0..3 {
|
||||||
let mut best_dot = 0.0f64;
|
let mut best_dot = 0.0f64;
|
||||||
let mut best_src = 0;
|
let mut best_src = 0;
|
||||||
let mut best_dst = 0;
|
let mut best_dst = 0;
|
||||||
for src in 0..3 {
|
for src in 0..3 {
|
||||||
if src_used[src] { continue; }
|
if src_assigned[src] { continue; }
|
||||||
for dst in 0..3 {
|
for dst in 0..3 {
|
||||||
if dst_used[dst] { continue; }
|
if dst_assigned[dst] { continue; }
|
||||||
let d = axes[src].dot(canonical[dst]).abs();
|
let d = axes[src].dot(canonical[dst]).abs();
|
||||||
if d > best_dot {
|
if d > best_dot {
|
||||||
best_dot = d;
|
best_dot = d;
|
||||||
|
|
@ -255,8 +255,8 @@ fn align_box_axes(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assignment[best_src] = best_dst;
|
assignment[best_src] = best_dst;
|
||||||
src_used[best_src] = true;
|
src_assigned[best_src] = true;
|
||||||
dst_used[best_dst] = true;
|
dst_assigned[best_dst] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut ordered = [0.0; 3];
|
let mut ordered = [0.0; 3];
|
||||||
|
|
|
||||||
|
|
@ -384,7 +384,10 @@ impl<'a> ExprParser<'a> {
|
||||||
return Ok(self.graph.push(TrigOp::Mul(sq, base)));
|
return Ok(self.graph.push(TrigOp::Mul(sq, base)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(self.graph.push(TrigOp::Mul(base, exp)))
|
// base^exp = exp(exp * ln(base))
|
||||||
|
let ln_base = self.graph.push(TrigOp::Ln(base));
|
||||||
|
let product = self.graph.push(TrigOp::Mul(exp, ln_base));
|
||||||
|
Ok(self.graph.push(TrigOp::Exp(product)))
|
||||||
} else {
|
} else {
|
||||||
Ok(base)
|
Ok(base)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ pub(crate) fn tokenize(input: &str) -> Result<(Vec<Token>, Vec<usize>), String>
|
||||||
'/' => {
|
'/' => {
|
||||||
chars.next();
|
chars.next();
|
||||||
match chars.peek() {
|
match chars.peek() {
|
||||||
Some('/') | Some('=') => {
|
Some('/') => {
|
||||||
while let Some(&c) = chars.peek() {
|
while let Some(&c) = chars.peek() {
|
||||||
chars.next();
|
chars.next();
|
||||||
if c == '\n' { line += 1; break; }
|
if c == '\n' { line += 1; break; }
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,24 @@ impl std::fmt::Display for LowerError {
|
||||||
|
|
||||||
impl std::error::Error for LowerError {}
|
impl std::error::Error for LowerError {}
|
||||||
|
|
||||||
/// Variable environment for expression evaluation during lowering.
|
#[derive(Debug, Clone)]
|
||||||
type Env = HashMap<String, f64>;
|
enum Value {
|
||||||
|
Scalar(f64),
|
||||||
|
Array(Vec<f64>),
|
||||||
|
}
|
||||||
|
|
||||||
|
type Env = HashMap<String, Value>;
|
||||||
|
|
||||||
|
fn env_get_scalar(env: &Env, name: &str) -> Option<f64> {
|
||||||
|
match env.get(name)? {
|
||||||
|
Value::Scalar(v) => Some(*v),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn env_insert_scalar(env: &mut Env, name: String, val: f64) {
|
||||||
|
env.insert(name, Value::Scalar(val));
|
||||||
|
}
|
||||||
|
|
||||||
/// Lower a parsed SCAD program into an SDF tree.
|
/// Lower a parsed SCAD program into an SDF tree.
|
||||||
/// Multiple top-level statements become an implicit union.
|
/// Multiple top-level statements become an implicit union.
|
||||||
|
|
@ -47,7 +63,7 @@ fn lower_statement(stmt: &Statement, env: &mut Env) -> Result<Option<SdfNode>, L
|
||||||
Statement::BooleanOp(bop) => lower_boolean(bop, env).map(Some),
|
Statement::BooleanOp(bop) => lower_boolean(bop, env).map(Some),
|
||||||
Statement::Assignment(asgn) => {
|
Statement::Assignment(asgn) => {
|
||||||
if let Some(val) = eval_expr_env(&asgn.value, env) {
|
if let Some(val) = eval_expr_env(&asgn.value, env) {
|
||||||
env.insert(asgn.name.clone(), val);
|
env_insert_scalar(env, asgn.name.clone(), val);
|
||||||
}
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
@ -69,7 +85,7 @@ fn lower_for_loop(fl: &ForLoop, env: &mut Env) -> Result<SdfNode, LowerError> {
|
||||||
let mut branches = Vec::with_capacity(values.len());
|
let mut branches = Vec::with_capacity(values.len());
|
||||||
for val in values {
|
for val in values {
|
||||||
let mut inner_env = env.clone();
|
let mut inner_env = env.clone();
|
||||||
inner_env.insert(fl.var.clone(), val);
|
env_insert_scalar(&mut inner_env, fl.var.clone(), val);
|
||||||
let nodes = lower_statements(&fl.body, &mut inner_env)?;
|
let nodes = lower_statements(&fl.body, &mut inner_env)?;
|
||||||
match nodes.len() {
|
match nodes.len() {
|
||||||
0 => {}
|
0 => {}
|
||||||
|
|
@ -172,7 +188,7 @@ fn eval_expr_env(expr: &Expr, env: &Env) -> Option<f64> {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Number(n) => Some(*n),
|
Expr::Number(n) => Some(*n),
|
||||||
Expr::Bool(b) => Some(if *b { 1.0 } else { 0.0 }),
|
Expr::Bool(b) => Some(if *b { 1.0 } else { 0.0 }),
|
||||||
Expr::Ident(name) => env.get(name).copied(),
|
Expr::Ident(name) => env_get_scalar(env, name),
|
||||||
Expr::UnaryOp { op: UnaryOp::Neg, operand } => eval_expr_env(operand, env).map(|n| -n),
|
Expr::UnaryOp { op: UnaryOp::Neg, operand } => eval_expr_env(operand, env).map(|n| -n),
|
||||||
Expr::UnaryOp { op: UnaryOp::Not, operand } => {
|
Expr::UnaryOp { op: UnaryOp::Not, operand } => {
|
||||||
eval_expr_env(operand, env).map(|n| if n == 0.0 { 1.0 } else { 0.0 })
|
eval_expr_env(operand, env).map(|n| if n == 0.0 { 1.0 } else { 0.0 })
|
||||||
|
|
|
||||||
|
|
@ -126,9 +126,7 @@ fn emit_scad(node: &SdfNode, depth: usize, out: &mut String) {
|
||||||
|
|
||||||
SdfNode::SmoothUnion { children, k } => {
|
SdfNode::SmoothUnion { children, k } => {
|
||||||
indent(depth, out);
|
indent(depth, out);
|
||||||
let _ = writeln!(out, "// smooth union (k={})", fmt(*k));
|
let _ = writeln!(out, "smooth_union(k={}) {{", fmt(*k));
|
||||||
indent(depth, out);
|
|
||||||
let _ = writeln!(out, "union() {{");
|
|
||||||
for c in children {
|
for c in children {
|
||||||
emit_scad(c, depth + 1, out);
|
emit_scad(c, depth + 1, out);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,7 @@ fn cmd_build(input: &std::path::Path, output: Option<PathBuf>, word_bits: u8) ->
|
||||||
} else {
|
} else {
|
||||||
writer.write_source_scad(&source)?;
|
writer.write_source_scad(&source)?;
|
||||||
}
|
}
|
||||||
|
writer.write_trig(&graph.to_bytes())?;
|
||||||
writer.write_shader(&wgsl)?;
|
writer.write_shader(&wgsl)?;
|
||||||
writer.write_cordic(&cordic_bytes, word_bits)?;
|
writer.write_cordic(&cordic_bytes, word_bits)?;
|
||||||
writer.write_config(&config_toml)?;
|
writer.write_config(&config_toml)?;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue