use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
use iced_nodegraph_sdf::{Shape, ShapeCache};
use std::hint::black_box;
const EDGES_PER_NODE: usize = 128;
const NODE_W: f32 = 160.0;
const NODE_H: f32 = 90.0;
const CORNER_RADIUS: f32 = 8.0;
const PIN_RADIUS: f32 = 5.0;
struct NodeSpec {
cx: f32,
cy: f32,
}
struct Scene {
nodes: Vec<NodeSpec>,
edges: Vec<(usize, usize)>,
}
fn build_scene(n: usize) -> Scene {
let cols = (n as f32).sqrt().ceil() as usize;
let spacing_x = NODE_W * 1.6;
let spacing_y = NODE_H * 1.8;
let nodes = (0..n)
.map(|i| NodeSpec {
cx: (i % cols) as f32 * spacing_x,
cy: (i / cols) as f32 * spacing_y,
})
.collect();
let edge_count = n * EDGES_PER_NODE / 100;
let edges = (0..edge_count)
.map(|e| {
let from = e % n;
let to = (from + 1 + (e * 7 + 3) % (n.max(2) - 1)) % n;
(from, to)
})
.collect();
Scene { nodes, edges }
}
fn node_body() -> Shape {
Shape::rounded_box([NODE_W, NODE_H], [CORNER_RADIUS; 4])
- Shape::circle(PIN_RADIUS).translate([-NODE_W * 0.5, -25.0])
- Shape::circle(PIN_RADIUS).translate([-NODE_W * 0.5, 0.0])
- Shape::circle(PIN_RADIUS).translate([-NODE_W * 0.5, 25.0])
- Shape::circle(PIN_RADIUS).translate([NODE_W * 0.5, -15.0])
- Shape::circle(PIN_RADIUS).translate([NODE_W * 0.5, 15.0])
}
fn edge_shape(scene: &Scene, from: usize, to: usize) -> Shape {
let a = &scene.nodes[from];
let b = &scene.nodes[to];
let dx = (b.cx - a.cx).abs().max(NODE_W);
Shape::bezier(
[a.cx + NODE_W * 0.5, a.cy],
[a.cx + NODE_W * 0.5 + dx * 0.5, a.cy],
[b.cx - NODE_W * 0.5 - dx * 0.5, b.cy],
[b.cx - NODE_W * 0.5, b.cy],
)
}
fn prep_frame(scene: &Scene) -> usize {
let body = node_body();
let mut segs = 0usize;
for _ in &scene.nodes {
segs += body.evaluate().segment_count();
}
for &(from, to) in &scene.edges {
segs += edge_shape(scene, from, to).evaluate().segment_count();
}
segs
}
fn prep_frame_cached(scene: &Scene, cache: &mut ShapeCache) -> usize {
let body = node_body();
let mut segs = 0usize;
for _ in &scene.nodes {
segs += cache.get_or_eval(&body).segment_count();
}
for &(from, to) in &scene.edges {
segs += edge_shape(scene, from, to).evaluate().segment_count();
}
segs
}
fn bench_frame_prep(c: &mut Criterion) {
let mut group = c.benchmark_group("frame_prep");
for &n in &[100usize, 500, 2000] {
let scene = build_scene(n);
group.bench_with_input(BenchmarkId::new("cold", n), &scene, |b, scene| {
b.iter(|| black_box(prep_frame(black_box(scene))));
});
group.bench_with_input(BenchmarkId::new("cached", n), &scene, |b, scene| {
let mut cache = ShapeCache::new(64);
b.iter(|| black_box(prep_frame_cached(black_box(scene), &mut cache)));
});
}
group.finish();
}
criterion_group!(benches, bench_frame_prep);
criterion_main!(benches);