Add compute_*_normals benchmarks (#18648)

# Objective

Benchmark current `compute_*_normals` methods to get a baseline as
requested in
https://github.com/bevyengine/bevy/pull/18552#issuecomment-2764875143

## Solution

Since the change to the default smooth normals method will definitely
cause a regression, but the previous method will remain as an option, I
added two technically-redundant benchmarks but with different names:
`smooth_normals` for whatever default weighting method is used, and
`face_weighted_normals` to benchmark the area-weighted method regardless
of what the default is. Then I'm adding `angle_weighted_normals` in
#18552. I also added `flat_normals` for completeness.
This commit is contained in:
Waridley 2025-03-31 12:58:45 -05:00 committed by GitHub
parent 301f61845a
commit 89e00b19c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 102 additions and 1 deletions

View File

@ -0,0 +1,96 @@
use core::hint::black_box;
use criterion::{criterion_group, Criterion};
use rand::random;
use std::time::{Duration, Instant};
use bevy_render::{
mesh::{Indices, Mesh, PrimitiveTopology},
render_asset::RenderAssetUsages,
};
const GRID_SIZE: usize = 256;
fn compute_normals(c: &mut Criterion) {
let indices = Indices::U32(
(0..GRID_SIZE - 1)
.flat_map(|i| std::iter::repeat(i).zip(0..GRID_SIZE - 1))
.flat_map(|(i, j)| {
let tl = ((GRID_SIZE * j) + i) as u32;
let tr = tl + 1;
let bl = ((GRID_SIZE * (j + 1)) + i) as u32;
let br = bl + 1;
[tl, bl, tr, tr, bl, br]
})
.collect(),
);
let new_mesh = || {
let positions = (0..GRID_SIZE)
.flat_map(|i| std::iter::repeat(i).zip(0..GRID_SIZE))
.map(|(i, j)| [i as f32, j as f32, random::<f32>()])
.collect::<Vec<_>>();
Mesh::new(
PrimitiveTopology::TriangleList,
RenderAssetUsages::MAIN_WORLD,
)
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions)
.with_inserted_indices(indices.clone())
};
c.bench_function("smooth_normals", |b| {
b.iter_custom(|iters| {
let mut total = Duration::default();
for _ in 0..iters {
let mut mesh = new_mesh();
black_box(mesh.attribute(Mesh::ATTRIBUTE_NORMAL));
let start = Instant::now();
mesh.compute_smooth_normals();
let end = Instant::now();
black_box(mesh.attribute(Mesh::ATTRIBUTE_NORMAL));
total += end.duration_since(start);
}
total
});
});
c.bench_function("face_weighted_normals", |b| {
b.iter_custom(|iters| {
let mut total = Duration::default();
for _ in 0..iters {
let mut mesh = new_mesh();
black_box(mesh.attribute(Mesh::ATTRIBUTE_NORMAL));
let start = Instant::now();
mesh.compute_smooth_normals();
let end = Instant::now();
black_box(mesh.attribute(Mesh::ATTRIBUTE_NORMAL));
total += end.duration_since(start);
}
total
});
});
let new_mesh = || {
new_mesh()
.with_duplicated_vertices()
.with_computed_flat_normals()
};
c.bench_function("flat_normals", |b| {
b.iter_custom(|iters| {
let mut total = Duration::default();
for _ in 0..iters {
let mut mesh = new_mesh();
black_box(mesh.attribute(Mesh::ATTRIBUTE_NORMAL));
let start = Instant::now();
mesh.compute_flat_normals();
let end = Instant::now();
black_box(mesh.attribute(Mesh::ATTRIBUTE_NORMAL));
total += end.duration_since(start);
}
total
});
});
}
criterion_group!(benches, compute_normals);

View File

@ -1,6 +1,11 @@
use criterion::criterion_main;
mod compute_normals;
mod render_layers;
mod torus;
criterion_main!(render_layers::benches, torus::benches);
criterion_main!(
render_layers::benches,
compute_normals::benches,
torus::benches
);