diff --git a/world/Cargo.toml b/world/Cargo.toml index f906bf1a09..e0228a8b1e 100644 --- a/world/Cargo.toml +++ b/world/Cargo.toml @@ -63,6 +63,10 @@ strum = "0.24" harness = false name = "tree" +[[bench]] +harness = false +name = "site2" + [[example]] name = "chunk_compression_benchmarks" required-features = ["bin_compression"] diff --git a/world/benches/site2.rs b/world/benches/site2.rs new file mode 100644 index 0000000000..69326a9a1e --- /dev/null +++ b/world/benches/site2.rs @@ -0,0 +1,143 @@ +use common::{ + generation::EntityInfo, + store::{Id, Store}, + terrain::Block, +}; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use hashbrown::HashMap; +use rand::prelude::*; +use rayon::ThreadPoolBuilder; +use vek::{Vec2, Vec3}; +use veloren_world::{ + sim::{FileOpts, WorldOpts, DEFAULT_WORLD_MAP}, + site2::{ + plot::PlotKind, Fill, + Primitive, Site, Structure, + }, + CanvasInfo, Land, World, +}; + +#[allow(dead_code)] +fn count_prim_kinds(prims: &Store) -> HashMap { + let mut ret = HashMap::new(); + for prim in prims.values() { + match &prim { + Primitive::Empty => { *ret.entry("Empty".to_string()).or_default() += 1; } + Primitive::Aabb(_) => { *ret.entry("Aabb".to_string()).or_default() += 1; } + Primitive::Pyramid { .. } => { *ret.entry("Pyramid".to_string()).or_default() += 1; } + Primitive::Ramp { .. } => { *ret.entry("Ramp".to_string()).or_default() += 1; }, + Primitive::Gable { .. } => { *ret.entry("Gable".to_string()).or_default() += 1; }, + Primitive::Cylinder(_) => { *ret.entry("Cylinder".to_string()).or_default() += 1; }, + Primitive::Cone(_) => { *ret.entry("Cone".to_string()).or_default() += 1; }, + Primitive::Sphere(_) => { *ret.entry("Sphere".to_string()).or_default() += 1; }, + Primitive::Superquadric { .. } => { *ret.entry("Superquadratic".to_string()).or_default() += 1; }, + Primitive::Plane(_, _, _) => { *ret.entry("Plane".to_string()).or_default() += 1; }, + Primitive::Segment { .. } => { *ret.entry("Segment".to_string()).or_default() += 1; }, + Primitive::SegmentPrism { .. } => { *ret.entry("SegmentPrism".to_string()).or_default() += 1; }, + Primitive::Sampling(_, _) => { *ret.entry("Sampling".to_string()).or_default() += 1; }, + Primitive::Prefab(_) => { *ret.entry("Prefab".to_string()).or_default() += 1; }, + Primitive::Intersect(_, _) => { *ret.entry("Intersect".to_string()).or_default() += 1; }, + Primitive::Union(_, _) => { *ret.entry("Union".to_string()).or_default() += 1; }, + Primitive::Without(_, _) => { *ret.entry("Without".to_string()).or_default() += 1; }, + Primitive::RotateAbout(_, _, _) => { *ret.entry("RotateAbout".to_string()).or_default() += 1; }, + Primitive::Translate(_, _) => { *ret.entry("Translate".to_string()).or_default() += 1; }, + Primitive::Scale(_, _) => { *ret.entry("Scale".to_string()).or_default() += 1; }, + Primitive::Repeat(_, _, _) => { *ret.entry("Repeat".to_string()).or_default() += 1; }, + } + } + ret +} + +fn render_plots(canvas: &CanvasInfo<'_>, site: &Site) { + for plot in site.plots() { + let result = match &plot.kind() { + PlotKind::House(house) => house.render_collect(site, canvas), + PlotKind::Workshop(workshop) => workshop.render_collect(site, canvas), + PlotKind::Castle(castle) => castle.render_collect(site, canvas), + PlotKind::Dungeon(dungeon) => dungeon.render_collect(site, canvas), + PlotKind::Gnarling(gnarling) => gnarling.render_collect(site, canvas), + PlotKind::GiantTree(giant_tree) => giant_tree.render_collect(site, canvas), + _ => continue, + }; + //println!("{:?}", count_prim_kinds(&result.0)); + iter_fills(canvas, result); + } +} + +fn iter_fills( + canvas: &CanvasInfo<'_>, + (prim_tree, fills, _): (Store, Vec<(Id, Fill)>, Vec), +) { + for (prim, fill) in fills { + let aabb = Fill::get_bounds(&prim_tree, prim); + + for x in aabb.min.x..aabb.max.x { + for y in aabb.min.y..aabb.max.y { + for z in aabb.min.z..aabb.max.z { + let pos = Vec3::new(x, y, z); + black_box(fill.sample_at( + &prim_tree, + prim, + pos, + canvas, + Block::empty(), + )); + } + } + } + } +} + +fn dungeon(c: &mut Criterion) { + let pool = ThreadPoolBuilder::new().build().unwrap(); + let (world, index) = World::generate( + 230, + WorldOpts { + seed_elements: true, + world_file: FileOpts::LoadAsset(DEFAULT_WORLD_MAP.into()), + ..WorldOpts::default() + }, + &pool, + ); + let wpos = Vec2::zero(); + let seed = [1; 32]; + c.bench_function("generate_dungeon", |b| { + let mut rng = rand::rngs::StdRng::from_seed(seed); + b.iter(|| { + Site::generate_dungeon(&Land::empty(), &mut rng, wpos); + }); + }); + { + let mut render_dungeon_group = c.benchmark_group("render_dungeon"); + render_dungeon_group.bench_function("identity_allocator", |b| { + let mut rng = rand::rngs::StdRng::from_seed(seed); + CanvasInfo::with_mock_canvas_info(index.as_index_ref(), world.sim(), |canvas| { + let site = Site::generate_dungeon(&canvas.land(), &mut rng, wpos); + b.iter(|| { + render_plots(canvas, &site); + }); + }) + }); + } + c.bench_function("generate_gnarling", |b| { + let mut rng = rand::rngs::StdRng::from_seed(seed); + b.iter(|| { + Site::generate_gnarling(&Land::empty(), &mut rng, wpos); + }); + }); + { + let mut render_gnarling_group = c.benchmark_group("render_gnarling"); + render_gnarling_group.bench_function("identity_allocator", |b| { + let mut rng = rand::rngs::StdRng::from_seed(seed); + CanvasInfo::with_mock_canvas_info(index.as_index_ref(), world.sim(), |canvas| { + let site = Site::generate_gnarling(&canvas.land(), &mut rng, wpos); + b.iter(|| { + render_plots(canvas, &site); + }); + }) + }); + } +} + +criterion_group!(benches, dungeon); +criterion_main!(benches);