2020-02-01 20:39:39 +00:00
|
|
|
use common::{
|
|
|
|
terrain::{Block, TerrainGrid},
|
|
|
|
vol::{SampleVol, Vox},
|
|
|
|
};
|
2020-01-20 12:38:58 +00:00
|
|
|
use criterion::{black_box, criterion_group, criterion_main, Benchmark, Criterion};
|
2020-01-09 06:05:20 +00:00
|
|
|
use std::sync::Arc;
|
|
|
|
use vek::*;
|
|
|
|
use veloren_voxygen::mesh::Meshable;
|
2020-01-20 18:19:06 +00:00
|
|
|
use world::{sim, World};
|
2020-01-09 06:05:20 +00:00
|
|
|
|
|
|
|
const CENTER: Vec2<i32> = Vec2 { x: 512, y: 512 };
|
|
|
|
const GEN_SIZE: i32 = 4;
|
|
|
|
|
2020-06-10 19:47:36 +00:00
|
|
|
#[allow(clippy::needless_update)] // TODO: Pending review in #587
|
2020-01-09 06:05:20 +00:00
|
|
|
pub fn criterion_benchmark(c: &mut Criterion) {
|
|
|
|
// Generate chunks here to test
|
|
|
|
let mut terrain = TerrainGrid::new().unwrap();
|
2020-02-01 20:39:39 +00:00
|
|
|
let world = World::generate(42, sim::WorldOpts {
|
|
|
|
// NOTE: If this gets too expensive, we can turn it off.
|
|
|
|
// TODO: Consider an option to turn off all erosion as well, or even provide altitude
|
|
|
|
// directly with a closure.
|
|
|
|
seed_elements: true,
|
|
|
|
world_file: sim::FileOpts::LoadAsset(sim::DEFAULT_WORLD_MAP.into()),
|
|
|
|
..Default::default()
|
|
|
|
});
|
2020-01-09 06:05:20 +00:00
|
|
|
(0..GEN_SIZE)
|
|
|
|
.flat_map(|x| (0..GEN_SIZE).map(move |y| Vec2::new(x, y)))
|
|
|
|
.map(|offset| offset + CENTER)
|
|
|
|
.map(|pos| (pos, world.generate_chunk(pos, || false).unwrap()))
|
|
|
|
.for_each(|(key, chunk)| {
|
|
|
|
terrain.insert(key, Arc::new(chunk.0));
|
|
|
|
});
|
|
|
|
|
|
|
|
let sample = |chunk_pos: Vec2<i32>| {
|
|
|
|
let chunk_pos = chunk_pos + CENTER;
|
2020-02-01 20:39:39 +00:00
|
|
|
// Find the area of the terrain we want. Because meshing needs to compute things
|
|
|
|
// like ambient occlusion and edge elision, we also need the borders of
|
|
|
|
// the chunk's neighbours too (hence the `- 1` and `+ 1`).
|
2020-01-09 06:05:20 +00:00
|
|
|
let aabr = Aabr {
|
|
|
|
min: chunk_pos.map2(TerrainGrid::chunk_size(), |e, sz| e * sz as i32 - 1),
|
|
|
|
max: chunk_pos.map2(TerrainGrid::chunk_size(), |e, sz| (e + 1) * sz as i32 + 1),
|
|
|
|
};
|
|
|
|
|
2020-02-01 20:39:39 +00:00
|
|
|
// Copy out the chunk data we need to perform the meshing. We do this by taking
|
|
|
|
// a sample of the terrain that includes both the chunk we want and its
|
|
|
|
// neighbours.
|
2020-01-09 06:05:20 +00:00
|
|
|
let volume = terrain.sample(aabr).unwrap();
|
|
|
|
|
|
|
|
// The region to actually mesh
|
|
|
|
let min_z = volume
|
|
|
|
.iter()
|
|
|
|
.fold(std::i32::MAX, |min, (_, chunk)| chunk.get_min_z().min(min));
|
|
|
|
let max_z = volume
|
|
|
|
.iter()
|
|
|
|
.fold(std::i32::MIN, |max, (_, chunk)| chunk.get_max_z().max(max));
|
|
|
|
|
|
|
|
let aabb = Aabb {
|
|
|
|
min: Vec3::from(aabr.min) + Vec3::unit_z() * (min_z - 1),
|
|
|
|
max: Vec3::from(aabr.max) + Vec3::unit_z() * (max_z + 1),
|
|
|
|
};
|
|
|
|
|
|
|
|
(volume, aabb)
|
|
|
|
};
|
|
|
|
|
|
|
|
// Test speed of cloning voxel sample into a flat array
|
|
|
|
let (volume, range) = sample(Vec2::new(1, 1));
|
2020-01-20 12:38:58 +00:00
|
|
|
c.bench(
|
|
|
|
"meshing",
|
|
|
|
Benchmark::new("copying 1,1 into flat array", move |b| {
|
|
|
|
b.iter(|| {
|
|
|
|
let mut flat = vec![Block::empty(); range.size().product() as usize];
|
|
|
|
let mut i = 0;
|
|
|
|
let mut volume = volume.cached();
|
|
|
|
for x in 0..range.size().w {
|
|
|
|
for y in 0..range.size().h {
|
|
|
|
for z in 0..range.size().d {
|
|
|
|
flat[i] = *volume.get(range.min + Vec3::new(x, y, z)).unwrap();
|
|
|
|
i += 1;
|
|
|
|
}
|
2020-01-09 06:05:20 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-20 12:38:58 +00:00
|
|
|
/*let (w, h, d) = range.size().into_tuple();
|
|
|
|
for (chunk_key, chunk) in volume.iter() {
|
|
|
|
let chunk_pos = volume.key_pos(chunk_key);
|
|
|
|
let min = chunk_pos.map2(
|
|
|
|
Vec2::new(range.min.x, range.min.y),
|
|
|
|
|cmin: i32, rmin: i32| (rmin - cmin).max(0),
|
|
|
|
);
|
|
|
|
// Chunk not in area of interest
|
|
|
|
if min
|
|
|
|
.map2(TerrainGrid::chunk_size(), |m, size| m >= size as i32)
|
|
|
|
.reduce_and()
|
|
|
|
{
|
|
|
|
// TODO: comment after ensuing no panics
|
|
|
|
panic!("Shouldn't happen in this case");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let min = min.map(|m| m.min(31));
|
|
|
|
// TODO: Don't hardcode 31
|
|
|
|
let max = chunk_pos.map2(Vec2::new(range.max.x, range.max.y), |cmin, rmax| {
|
|
|
|
(rmax - cmin).min(31)
|
|
|
|
});
|
|
|
|
if max.map(|m| m < 0).reduce_and() {
|
|
|
|
panic!("Shouldn't happen in this case: {:?}", max);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let max = max.map(|m| m.max(0));
|
|
|
|
// Add z dims
|
|
|
|
let min = Vec3::new(min.x, min.y, range.min.z);
|
|
|
|
let max = Vec3::new(max.x, max.y, range.max.z);
|
|
|
|
// Offset of chunk in sample being cloned
|
|
|
|
let offset = Vec3::new(
|
|
|
|
chunk_pos.x - range.min.x,
|
|
|
|
chunk_pos.y - range.min.y,
|
|
|
|
-range.min.z,
|
|
|
|
);
|
|
|
|
for (pos, &block) in chunk.vol_iter(min, max) {
|
|
|
|
let pos = pos + offset;
|
|
|
|
flat[(w * h * pos.z + w * pos.y + pos.x) as usize] = block;
|
|
|
|
}
|
|
|
|
}*/
|
|
|
|
black_box(flat);
|
|
|
|
});
|
|
|
|
})
|
|
|
|
// Lower sample size to save time
|
|
|
|
.sample_size(15),
|
|
|
|
);
|
2020-01-09 06:05:20 +00:00
|
|
|
|
|
|
|
for x in 1..GEN_SIZE - 1 {
|
|
|
|
for y in 1..GEN_SIZE - 1 {
|
|
|
|
let (volume, range) = sample(Vec2::new(x, y));
|
2020-01-20 12:38:58 +00:00
|
|
|
c.bench(
|
|
|
|
"meshing",
|
|
|
|
Benchmark::new(&format!("Terrain mesh {}, {}", x, y), move |b| {
|
|
|
|
b.iter(|| volume.generate_mesh(black_box(range)))
|
|
|
|
})
|
|
|
|
// Lower sample size to save time
|
|
|
|
.sample_size(15),
|
|
|
|
);
|
2020-01-09 06:05:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
criterion_group!(benches, criterion_benchmark);
|
|
|
|
criterion_main!(benches);
|