Empty mesh for JitShape when translating box
julianschuler opened this issue · 2 comments
Hi again,
I stumbled upon a case where meshing with a VmShape
results in a correct mesh while meshing with a JitShape
produces an empty one (on an x86 computer).
More specifically, this only seems to be the case when using a (mitered) box primitive and translating it along Z using remap_xyz()
, but only for translations putting the box entirely above/below the XY-plane.
Here is a minimum working example reproducing this issue:
use fidget::{
context::{IntoNode, Node},
eval::MathShape,
jit::JitShape,
mesh::{Octree, Settings},
vm::VmShape,
Context, Error,
};
pub struct BoxShape {
size: f64,
}
impl BoxShape {
pub fn new(size: f64) -> Self {
Self { size }
}
}
impl IntoNode for BoxShape {
fn into_node(self, context: &mut Context) -> Result<Node, Error> {
let x = context.x();
let y = context.y();
let z = context.z();
let abs_x = context.abs(x)?;
let abs_y = context.abs(y)?;
let abs_z = context.abs(z)?;
let qx = context.sub(abs_x, self.size / 2.0)?;
let qy = context.sub(abs_y, self.size / 2.0)?;
let qz = context.sub(abs_z, self.size / 2.0)?;
let max_elem = context.max(qx, qy)?;
context.max(max_elem, qz)
}
}
fn translate_z(
context: &mut Context,
root: impl IntoNode,
translation: f64,
) -> Result<Node, Error> {
let root = root.into_node(context)?;
let x = context.x();
let y = context.y();
let z = context.z();
let translated_z = context.sub(z, translation)?;
context.remap_xyz(root, [x, y, translated_z])
}
fn main() -> Result<(), Error> {
let settings = Settings {
threads: 12,
min_depth: 6,
max_depth: 6,
};
for i in -5..=5 {
let translation = i as f64 / 10.0;
let mut context = Context::new();
let box_shape = BoxShape::new(0.4);
let root = translate_z(&mut context, box_shape, translation)?;
let jit_shape = JitShape::new(&context, root)?;
let jit_mesh = Octree::build(&jit_shape, settings).walk_dual(settings);
let vm_shape = VmShape::new(&context, root)?;
let vm_mesh = Octree::build(&vm_shape, settings).walk_dual(settings);
println!(
"translation: {:.1} \t vertices (jit): {}\t vertices (vm): {}",
translation,
jit_mesh.vertices.len(),
vm_mesh.vertices.len(),
);
}
Ok(())
}
The output is the following (notice the lines with vertices jit: 0
):
translation: -0.5 vertices (jit): 0 vertices (vm): 14
translation: -0.4 vertices (jit): 0 vertices (vm): 36
translation: -0.3 vertices (jit): 0 vertices (vm): 21
translation: -0.2 vertices (jit): 14 vertices (vm): 14
translation: -0.1 vertices (jit): 14 vertices (vm): 14
translation: 0.0 vertices (jit): 14 vertices (vm): 14
translation: 0.1 vertices (jit): 17 vertices (vm): 17
translation: 0.2 vertices (jit): 14 vertices (vm): 14
translation: 0.3 vertices (jit): 0 vertices (vm): 21
translation: 0.4 vertices (jit): 0 vertices (vm): 14
translation: 0.5 vertices (jit): 0 vertices (vm): 42
Please let me know if I can help in any way resolving this.
Interesting, thanks for the minimal example!
This looks like a bug in the x86 JIT specifically: running on AArch64, both JIT and VM evaluator give the same result.
It's not a bug in tape generation, because the system works with GenericVmShape::<12>::new(..)
(i.e. building a VM-evaluated shape with only 12 registers, to match x86 JitShape
).
(later)
I tracked it down to a bug in the x86 interval abs
implementation, where we created a zero value by pulling from a high SIMD slot – which wasn't guaranteed to be empty!
Fixed by #50
Thank you for the quick fix!