mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
385 lines
15 KiB
Rust
385 lines
15 KiB
Rust
use common::{
|
|
generation::EntityInfo,
|
|
store::{Id, Store},
|
|
terrain::{Block, BlockKind, SpriteKind, TerrainSubChunk, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
|
|
vol::RectVolSize,
|
|
};
|
|
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
|
use hashbrown::HashMap;
|
|
use rand::prelude::*;
|
|
use rayon::ThreadPoolBuilder;
|
|
use vek::{Aabr, Rgb, Vec2, Vec3};
|
|
use veloren_world::{
|
|
config::CONFIG,
|
|
sim::{FileOpts, WorldOpts, DEFAULT_WORLD_MAP},
|
|
site2::{plot::PlotKind, Fill, Filler, Plot, Primitive, Site, Structure},
|
|
CanvasInfo, Land, World,
|
|
};
|
|
|
|
/* #[allow(dead_code)]
|
|
fn count_prim_kinds(prims: &Store<Primitive>) -> HashMap<String, usize> {
|
|
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<'a>(/*canvas: &mut Canvas<'a>,*/
|
|
arena: &'a mut bumpalo::Bump,
|
|
info: CanvasInfo<'a>,
|
|
site: &'a Site,
|
|
render_area: Aabr<i32>,
|
|
) {
|
|
for plot in site.plots() {
|
|
let structure: &dyn Structure<_> = match plot.kind() {
|
|
PlotKind::House(house) => house,
|
|
PlotKind::Workshop(workshop) => workshop,
|
|
PlotKind::Castle(castle) => castle,
|
|
PlotKind::Dungeon(dungeon) => dungeon,
|
|
PlotKind::Gnarling(gnarling) => gnarling,
|
|
PlotKind::GiantTree(giant_tree) => giant_tree,
|
|
PlotKind::CliffTower(cliff_tower) => cliff_tower,
|
|
PlotKind::Citadel(citadel) => citadel,
|
|
_ => continue,
|
|
};
|
|
|
|
let mut null_canvas = NullCanvas;
|
|
let result = structure.render_collect(site, /*canvas*/arena, info, render_area, /*|_canvas| */&mut null_canvas);
|
|
// NOTE: Clearing out the primitives between renders costs us nothing, because any
|
|
// chunks that get deallocated were going to be eventually deallocated anyway, while
|
|
// the current chunk remains for reuse. So this just ends up saving memory.
|
|
arena.reset();
|
|
|
|
/* //println!("{:?}", count_prim_kinds(&result.0));
|
|
iter_fills(canvas, site, plot, result); */
|
|
}
|
|
}
|
|
|
|
/// Null canvas for avoiding writing to the real cnavas.
|
|
struct NullCanvas;
|
|
impl Filler for NullCanvas {
|
|
#[inline]
|
|
fn map<F: Fill>(&mut self, pos: Vec3<i32>, f: F) {
|
|
// black_box(pos);
|
|
// black_box(f);
|
|
// black_box(f.sample_at(pos, Block::empty()));
|
|
black_box((pos, if F::NEEDS_BLOCK {
|
|
f.sample_at(pos, black_box(Block::empty()))
|
|
} else /* if F::NEEDS_POS {
|
|
f.sample_at(pos, Block::empty())
|
|
} else */{
|
|
f.sample_at(pos, Block::empty())
|
|
}));
|
|
}
|
|
|
|
#[inline]
|
|
fn spawn(&mut self, entity: EntityInfo) {
|
|
black_box(entity);
|
|
}
|
|
}
|
|
|
|
/* fn iter_fills(
|
|
canvas: &CanvasInfo<'_>,
|
|
_site: &Site,
|
|
_plot: &Plot,
|
|
(prim_tree, fills, _): (
|
|
Store<Primitive>,
|
|
Vec<(Id<Primitive>, Fill)>,
|
|
Vec<EntityInfo>,
|
|
),
|
|
) {
|
|
let arena = bumpalo::Bump::new();
|
|
let mut cache = HashMap::default();
|
|
|
|
/* let wpos2d = canvas.wpos();
|
|
let chunk_aabr = Aabr {
|
|
min: wpos2d,
|
|
max: wpos2d + TerrainChunkSize::RECT_SIZE.as_::<i32>(),
|
|
}; */
|
|
|
|
/* let info = canvas.info(); */
|
|
|
|
for (prim, fill) in fills {
|
|
let aabb = Fill::get_bounds(&mut cache, &prim_tree, prim)/*Aabr::new_empty(Vec2::zero())*/;
|
|
// let mut aabb = Fill::get_bounds(&prim_tree, prim);
|
|
/* fill.sample_at(
|
|
&arena,
|
|
&mut cache,
|
|
&prim_tree,
|
|
prim,
|
|
aabb.into(),
|
|
|pos, f| canvas.map(pos, f)
|
|
); */
|
|
/*Fill::get_bounds_disjoint*/fill.sample_at(&arena, &mut cache, &prim_tree, prim, aabb.into(), canvas, /* |pos| {
|
|
/* canvas.map(pos, |block| {
|
|
let current_block =
|
|
fill.sample_at(
|
|
/* &mut bounds_cache,
|
|
&prim_tree,
|
|
prim, */
|
|
pos,
|
|
&info,
|
|
block,
|
|
);
|
|
/* if let (Some(last_block), None) = (last_block, current_block) {
|
|
spawn(pos, last_block);
|
|
}
|
|
last_block = current_block; */
|
|
current_block.unwrap_or(block)
|
|
}); */
|
|
black_box(/*fill.sample_at(pos, canvas, Block::empty())*/pos);
|
|
}*/&mut NullCanvas);
|
|
|
|
/* for /*mut */aabb in Fill::get_bounds_disjoint(&mut cache, &prim_tree, prim) {
|
|
/* aabb.min = Vec2::max(aabb.min.xy(), chunk_aabr.min).with_z(aabb.min.z);
|
|
aabb.max = Vec2::min(aabb.max.xy(), chunk_aabr.max).with_z(aabb.max.z); */
|
|
|
|
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 col_tile = site.wpos_tile(Vec2::new(x, y));
|
|
if
|
|
/* col_tile.is_building() && */
|
|
col_tile
|
|
.plot()
|
|
.and_then(|p| site.plots().nth(p.id() as usize).unwrap().z_range())
|
|
.zip(plot.z_range())
|
|
.map_or(false, |(a, b)| a.end > b.end)
|
|
{
|
|
continue;
|
|
} */
|
|
let pos = Vec3::new(x, y, z);
|
|
black_box(fill.sample_at(&mut cache, &prim_tree, prim, pos, canvas, Block::empty()));
|
|
}
|
|
}
|
|
}
|
|
} */
|
|
}
|
|
} */
|
|
|
|
fn dungeon(c: &mut Criterion) {
|
|
let pool = ThreadPoolBuilder::new().build().unwrap();
|
|
let (world, index) = World::generate(
|
|
/*230*/59686,
|
|
WorldOpts {
|
|
seed_elements: true,
|
|
world_file: FileOpts::LoadAsset(DEFAULT_WORLD_MAP.into()),
|
|
..WorldOpts::default()
|
|
},
|
|
&pool,
|
|
);
|
|
let wpos = Vec2::zero();
|
|
let seed = [1; 32];
|
|
|
|
let air = Block::air(SpriteKind::Empty);
|
|
/* let stone = Block::new(
|
|
BlockKind::Rock,
|
|
zcache_grid
|
|
.get(grid_border + TerrainChunkSize::RECT_SIZE.map(|e| e as i32) / 2)
|
|
.and_then(|zcache| zcache.as_ref())
|
|
.map(|zcache| zcache.sample.stone_col)
|
|
.unwrap_or_else(|| index.colors.deep_stone_color.into()),
|
|
); */
|
|
let water = Block::new(BlockKind::Water, Rgb::zero());
|
|
let mut chunk = TerrainChunk::new(CONFIG.sea_level as i32, water, air, TerrainChunkMeta::void());
|
|
|
|
let find_bounds = |site: &Site| {
|
|
let aabr = site.plots()
|
|
.fold(
|
|
Aabr::new_empty(Vec2::zero()),
|
|
|aabr, plot| {
|
|
// NOTE: Approx
|
|
aabr.union(plot.find_bounds())
|
|
},
|
|
);
|
|
let chunks = Vec2::from(aabr.size())
|
|
.map2(TerrainChunkSize::RECT_SIZE, |e: i32, sz| (e as f32 / sz as f32).ceil() as u32);
|
|
// .as_::<i32>();
|
|
(chunks.x as u64 * chunks.y as u64, aabr)
|
|
};
|
|
|
|
let mut bench_group = |gen_name, render_name, f: fn(&Land, &mut _, _) -> _| {
|
|
c.bench_function(gen_name, |b| {
|
|
let mut rng = rand::rngs::StdRng::from_seed(seed);
|
|
b.iter(|| {
|
|
f(&Land::from_sim(world.sim()), &mut rng, wpos);
|
|
});
|
|
});
|
|
CanvasInfo::with_mock_canvas_info(index.as_index_ref(), world.sim(), |&info| {
|
|
let mut rng = rand::rngs::StdRng::from_seed(seed);
|
|
let site = f(&info.land(), &mut rng, wpos);
|
|
let mut render_dungeon_group = c.benchmark_group(render_name);
|
|
let (throughput, render_area) = find_bounds(&site);
|
|
render_dungeon_group.throughput(criterion::Throughput::Elements(throughput));
|
|
render_dungeon_group.bench_function("identity_allocator", |b| {
|
|
b.iter(|| {
|
|
let mut arena = bumpalo::Bump::new();
|
|
/* let mut canvas = Canvas {
|
|
info,
|
|
chunk: &mut chunk,
|
|
arena: &mut arena,
|
|
entities: Vec::new(),
|
|
}; */
|
|
render_plots(/*&mut canvas, */&mut arena, info, &site, render_area);
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
bench_group("generate_city", "render_city", Site::generate_city);
|
|
bench_group("generate_cliff_town", "render_cliff_town", Site::generate_cliff_town);
|
|
bench_group("generate_dungeon", "render_dungeon", Site::generate_dungeon);
|
|
bench_group("generate_giant_tree", "render_giant_tree", Site::generate_giant_tree);
|
|
bench_group("generate_gnarling", "render_gnarling", Site::generate_gnarling);
|
|
bench_group("generate_citadel", "render_citadel", Site::generate_citadel);
|
|
|
|
c.bench_function("generate_chunk", |b| {
|
|
// let chunk_pos = (world.sim().map_size_lg().chunks() >> 1).as_();
|
|
// let chunk_pos = Vec2::new(9500 / 32, 29042 / 32);
|
|
// let chunk_pos = Vec2::new(26944 / 32, 26848 / 32);
|
|
let chunk_pos = Vec2::new(842, 839);
|
|
// let chunk_pos = Vec2::new(24507/32, 20682/32);
|
|
// let chunk_pos = Vec2::new(19638/32, 19621/32);
|
|
b.iter(|| {
|
|
black_box(world.generate_chunk(index.as_index_ref(), chunk_pos, || false, None));
|
|
});
|
|
});
|
|
|
|
c.bench_function("deserialize_chunk", |b| {
|
|
// let chunk_pos = (world.sim().map_size_lg().chunks() >> 1).as_();
|
|
// let chunk_pos = Vec2::new(9500 / 32, 29042 / 32);
|
|
// let chunk_pos = Vec2::new(26944 / 32, 26848 / 32);
|
|
let chunk_pos = Vec2::new(842, 839);
|
|
let chunk = world.generate_chunk(index.as_index_ref(), chunk_pos, || false, None).unwrap().0;
|
|
/* println!("{:?}", chunk.sub_chunks_len());
|
|
let chunk = chunk.sub_chunks().next().unwrap(); */
|
|
let serialized = bincode::serialize(&chunk).unwrap();
|
|
// let chunk_pos = Vec2::new(24507/32, 20682/32);
|
|
// let chunk_pos = Vec2::new(19638/32, 19621/32);
|
|
b.iter(|| {
|
|
black_box(bincode::deserialize::<TerrainChunk/*TerrainSubChunk*//*BlockVec*/>(&*serialized).unwrap());
|
|
});
|
|
});
|
|
|
|
/* 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);
|
|
});
|
|
});
|
|
{
|
|
CanvasInfo::with_mock_canvas_info(index.as_index_ref(), world.sim(), |&info| {
|
|
let mut rng = rand::rngs::StdRng::from_seed(seed);
|
|
let site = Site::generate_dungeon(&info.land(), &mut rng, wpos);
|
|
let mut render_dungeon_group = c.benchmark_group("render_dungeon");
|
|
render_dungeon_group.throughput(criterion::Throughput::Elements(find_bounds(&site)));
|
|
render_dungeon_group.bench_function("identity_allocator", |b| {
|
|
b.iter(|| {
|
|
let mut arena = bumpalo::Bump::new();
|
|
let mut canvas = Canvas {
|
|
info,
|
|
chunk: &mut chunk,
|
|
arena: &mut arena,
|
|
entities: Vec::new(),
|
|
};
|
|
render_plots(&mut 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);
|
|
});
|
|
});
|
|
{
|
|
CanvasInfo::with_mock_canvas_info(index.as_index_ref(), world.sim(), |&info| {
|
|
let mut rng = rand::rngs::StdRng::from_seed(seed);
|
|
let site = Site::generate_gnarling(&info.land(), &mut rng, wpos);
|
|
let mut render_gnarling_group = c.benchmark_group("render_gnarling");
|
|
render_gnarling_group.throughput(criterion::Throughput::Elements(find_bounds(&site)));
|
|
render_gnarling_group.bench_function("identity_allocator", |b| {
|
|
b.iter(|| {
|
|
let mut arena = bumpalo::Bump::new();
|
|
let mut canvas = Canvas {
|
|
info,
|
|
chunk: &mut chunk,
|
|
arena: &mut arena,
|
|
entities: Vec::new(),
|
|
};
|
|
render_plots(&mut canvas, &site);
|
|
});
|
|
});
|
|
});
|
|
} */
|
|
}
|
|
|
|
criterion_group!(benches, dungeon);
|
|
criterion_main!(benches);
|