Skip to content

Commit 1e3bd7b

Browse files
committed
aquifer optimizations
1 parent bbf6856 commit 1e3bd7b

File tree

4 files changed

+189
-115
lines changed

4 files changed

+189
-115
lines changed

pumpkin-world/benches/chunk_gen.rs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ use pumpkin_world::generation::{Seed, get_world_gen};
1212
use pumpkin_world::level::Level;
1313
use pumpkin_world::world::{BlockAccessor, BlockRegistryExt};
1414

15-
use rayon::prelude::*;
16-
1715
struct BlockRegistry;
1816

1917
impl BlockRegistryExt for BlockRegistry {
@@ -40,14 +38,7 @@ fn chunk_generation_seed(seed: i64) {
4038
Dimension::Overworld,
4139
));
4240

43-
// Prepare all positions to generate
44-
let positions: Vec<Vector2<i32>> = (0..100)
45-
.flat_map(|x| (0..10).map(move |y| Vector2::new(x, y)))
46-
.collect();
47-
48-
positions.par_iter().for_each(|position| {
49-
generator.generate_chunk(&level, block_registry.as_ref(), position);
50-
});
41+
generator.generate_chunk(&level, block_registry.as_ref(), &Vector2::new(0, 0));
5142
}
5243

5344
fn bench_chunk_generation(c: &mut Criterion) {
@@ -60,7 +51,7 @@ fn bench_chunk_generation(c: &mut Criterion) {
6051

6152
criterion_group! {
6253
name = benches;
63-
config = Criterion::default().sample_size(10).measurement_time(std::time::Duration::from_secs(180));
54+
config = Criterion::default().measurement_time(std::time::Duration::from_secs(30));
6455
targets = bench_chunk_generation
6556
}
6657
criterion_main!(benches);

pumpkin-world/src/generation/aquifer_sampler.rs

Lines changed: 103 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ pub enum AquiferSampler {
8484
Aquifer(WorldAquiferSampler),
8585
}
8686

87+
macro_rules! packed_position_index {
88+
($local_x:expr,$local_y:expr,$local_z:expr,$dim_y:expr,$dim_z:expr) => {
89+
($local_x * $dim_z + $local_z) * $dim_y + $local_y
90+
};
91+
}
92+
8793
macro_rules! local_xz {
8894
($xz:expr) => {
8995
floor_div($xz, 16)
@@ -100,10 +106,10 @@ pub struct WorldAquiferSampler {
100106
random_deriver: RandomDeriver,
101107
fluid_level: FluidLevelSampler,
102108
start_x: i32,
103-
size_x: u64,
104109
start_y: i8,
105110
start_z: i32,
106-
size_z: u64,
111+
size_y: usize,
112+
size_z: usize,
107113
levels: Box<[Option<FluidLevel>]>,
108114
packed_positions: Box<[i64]>,
109115
}
@@ -135,19 +141,19 @@ impl WorldAquiferSampler {
135141
) -> Self {
136142
let start_x = local_xz!(chunk_pos::start_block_x(&chunk_pos)) - 1;
137143
let end_x = local_xz!(chunk_pos::end_block_x(&chunk_pos)) + 1;
138-
let size_x = (end_x - start_x) as u64 + 1;
144+
let size_x = (end_x - start_x) as usize + 1;
139145

140146
let start_y = local_y!(minimum_y) - 1;
141147
let end_y = local_y!(minimum_y as i32 + height as i32) + 1;
142-
let size_y = (end_y - start_y as i32) as u64 + 1;
148+
let size_y = (end_y - start_y as i32) as usize + 1;
143149

144150
let start_z = local_xz!(chunk_pos::start_block_z(&chunk_pos)) - 1;
145151
let end_z = local_xz!(chunk_pos::end_block_z(&chunk_pos)) + 1;
146-
let size_z = (end_z - start_z) as u64 + 1;
152+
let size_z = (end_z - start_z) as usize + 1;
147153

148154
let cache_size = size_x * size_y * size_z;
149155

150-
let mut packed_positions = vec![0; cache_size as usize];
156+
let mut packed_positions = vec![0; cache_size];
151157

152158
for offset_x in 0..size_x {
153159
for offset_y in 0..size_y {
@@ -161,7 +167,8 @@ impl WorldAquiferSampler {
161167
let rand_y = y * 12 + random.next_bounded_i32(9);
162168
let rand_z = z * 16 + random.next_bounded_i32(10);
163169

164-
let index = (offset_y * size_z + offset_z) * size_x + offset_x;
170+
let index =
171+
packed_position_index!(offset_x, offset_y, offset_z, size_y, size_z);
165172
packed_positions[index as usize] =
166173
block_pos::packed(&Vector3::new(rand_x, rand_y, rand_z));
167174
}
@@ -172,22 +179,54 @@ impl WorldAquiferSampler {
172179
random_deriver,
173180
fluid_level,
174181
start_x,
175-
size_x,
176182
start_y,
177183
start_z,
184+
size_y,
178185
size_z,
179186
levels: vec![None; cache_size as usize].into(),
180187
packed_positions: packed_positions.into(),
181188
}
182189
}
183190

184-
#[inline]
185-
fn index(&self, x: i32, y: i32, z: i32) -> usize {
186-
let i = (x - self.start_x) as u64;
187-
let j = (y - self.start_y as i32) as u64;
188-
let k = (z - self.start_z) as u64;
191+
fn packed_position_index(&self, x: i32, y: i32, z: i32) -> usize {
192+
let local_x = (x - self.start_x) as usize;
193+
let local_y = (y - self.start_y as i32) as usize;
194+
let local_z = (z - self.start_z) as usize;
195+
196+
packed_position_index!(local_x, local_y, local_z, self.size_y, self.size_z)
197+
}
189198

190-
((j * self.size_z + k) * self.size_x + i) as usize
199+
fn random_positions_for_pos(&self, x: i32, y: i32, z: i32) -> [i64; 12] {
200+
// (x, y - 1, z) to (x + 1, y + 1, z + 1)
201+
// y values are contiguous in packed array:
202+
// ($local_x * $dim_z + $local_z) * $dim_y + $local_y
203+
204+
// (x, y - 1, z)
205+
let x_0_z_0 = self.packed_position_index(x, y - 1, z);
206+
207+
// (x, y - 1, z + 1)
208+
let x_0_z_1 = x_0_z_0 + self.size_y;
209+
210+
// (x + 1, y - 1, z)
211+
let x_1_z_0 = x_0_z_0 + self.size_y * self.size_z;
212+
213+
// (x + 1, y - 1, z + 1)
214+
let x_1_z_1 = x_1_z_0 + self.size_y;
215+
216+
[
217+
self.packed_positions[x_0_z_0],
218+
self.packed_positions[x_0_z_1],
219+
self.packed_positions[x_1_z_0],
220+
self.packed_positions[x_1_z_1],
221+
self.packed_positions[x_0_z_0 + 1],
222+
self.packed_positions[x_0_z_1 + 1],
223+
self.packed_positions[x_1_z_0 + 1],
224+
self.packed_positions[x_1_z_1 + 1],
225+
self.packed_positions[x_0_z_0 + 2],
226+
self.packed_positions[x_0_z_1 + 2],
227+
self.packed_positions[x_1_z_0 + 2],
228+
self.packed_positions[x_1_z_1 + 2],
229+
]
191230
}
192231

193232
#[inline]
@@ -197,8 +236,10 @@ impl WorldAquiferSampler {
197236

198237
fn calculate_density(
199238
&mut self,
239+
barrier_sample: &mut Option<f64>,
200240
pos: &impl NoisePos,
201-
barrier_sample: f64,
241+
router: &mut ChunkNoiseRouter,
242+
sample_options: &ChunkNoiseFunctionSampleOptions,
202243
level_1: FluidLevel,
203244
level_2: FluidLevel,
204245
) -> f64 {
@@ -226,7 +267,7 @@ impl WorldAquiferSampler {
226267
};
227268

228269
let r = if (-2f64..=2f64).contains(&q) {
229-
barrier_sample
270+
*barrier_sample.get_or_insert_with(|| router.barrier_noise(pos, sample_options))
230271
} else {
231272
0f64
232273
};
@@ -253,7 +294,7 @@ impl WorldAquiferSampler {
253294
let local_y = local_y!(y);
254295
let local_z = local_xz!(z);
255296

256-
let index = self.index(local_x, local_y, local_z);
297+
let index = self.packed_position_index(local_x, local_y, local_z);
257298
if let Some(level) = &self.levels[index] {
258299
level.clone()
259300
} else {
@@ -445,55 +486,45 @@ impl WorldAquiferSampler {
445486
if density > 0f64 {
446487
None
447488
} else {
448-
let i = pos.x();
449-
let j = pos.y();
450-
let k = pos.z();
451-
452-
let fluid_level = self.fluid_level.get_fluid_level(i, j, k);
453-
if fluid_level.get_block(j) == &LAVA_BLOCK {
489+
let sample_x = pos.x();
490+
let sample_y = pos.y();
491+
let sample_z = pos.z();
492+
493+
let fluid_level = self
494+
.fluid_level
495+
.get_fluid_level(sample_x, sample_y, sample_z);
496+
if fluid_level.get_block(sample_y) == &LAVA_BLOCK {
454497
Some(LAVA_BLOCK.default_state)
455498
} else {
456-
let scaled_x = floor_div(i - 5, 16);
457-
let scaled_y = floor_div(j + 1, 12);
458-
let scaled_z = floor_div(k - 5, 16);
499+
let scaled_x = local_xz!(sample_x - 5);
500+
let scaled_y = local_y!(sample_y + 1);
501+
let scaled_z = local_xz!(sample_z - 5);
459502

460503
// The 3 closest positions, closest to furthest
461504
let mut packed_block_and_hypots = [(0, i32::MAX); 3];
462-
for offset_y in -1..=1 {
463-
for offset_x in 0..=1 {
464-
for offset_z in 0..=1 {
465-
let x_pos = scaled_x + offset_x;
466-
let y_pos = scaled_y + offset_y;
467-
let z_pos = scaled_z + offset_z;
468-
let index = self.index(x_pos, y_pos, z_pos);
469-
470-
let packed_random = self.packed_positions[index];
505+
for packed_random in self.random_positions_for_pos(scaled_x, scaled_y, scaled_z) {
506+
let unpacked_x = block_pos::unpack_x(packed_random);
507+
let unpacked_y = block_pos::unpack_y(packed_random);
508+
let unpacked_z = block_pos::unpack_z(packed_random);
471509

472-
let unpacked_x = block_pos::unpack_x(packed_random);
473-
let unpacked_y = block_pos::unpack_y(packed_random);
474-
let unpacked_z = block_pos::unpack_z(packed_random);
510+
let local_x = unpacked_x - sample_x;
511+
let local_y = unpacked_y - sample_y;
512+
let local_z = unpacked_z - sample_z;
475513

476-
let local_x = unpacked_x - i;
477-
let local_y = unpacked_y - j;
478-
let local_z = unpacked_z - k;
514+
let hypot_squared = local_x * local_x + local_y * local_y + local_z * local_z;
479515

480-
let hypot_squared =
481-
local_x * local_x + local_y * local_y + local_z * local_z;
482-
483-
if packed_block_and_hypots[2].1 >= hypot_squared {
484-
packed_block_and_hypots[2] = (packed_random, hypot_squared);
485-
}
516+
if packed_block_and_hypots[2].1 >= hypot_squared {
517+
packed_block_and_hypots[2] = (packed_random, hypot_squared);
518+
}
486519

487-
if packed_block_and_hypots[1].1 >= hypot_squared {
488-
packed_block_and_hypots[2] = packed_block_and_hypots[1];
489-
packed_block_and_hypots[1] = (packed_random, hypot_squared);
490-
}
520+
if packed_block_and_hypots[1].1 >= hypot_squared {
521+
packed_block_and_hypots[2] = packed_block_and_hypots[1];
522+
packed_block_and_hypots[1] = (packed_random, hypot_squared);
523+
}
491524

492-
if packed_block_and_hypots[0].1 >= hypot_squared {
493-
packed_block_and_hypots[1] = packed_block_and_hypots[0];
494-
packed_block_and_hypots[0] = (packed_random, hypot_squared);
495-
}
496-
}
525+
if packed_block_and_hypots[0].1 >= hypot_squared {
526+
packed_block_and_hypots[1] = packed_block_and_hypots[0];
527+
packed_block_and_hypots[0] = (packed_random, hypot_squared);
497528
}
498529
}
499530

@@ -505,7 +536,7 @@ impl WorldAquiferSampler {
505536
);
506537
let d =
507538
Self::max_distance(packed_block_and_hypots[0].1, packed_block_and_hypots[1].1);
508-
let block_state = fluid_level2.get_block(j);
539+
let block_state = fluid_level2.get_block(sample_y);
509540

510541
if d <= 0f64 {
511542
// TODO: Handle fluid tick
@@ -514,22 +545,24 @@ impl WorldAquiferSampler {
514545
} else if block_state == &WATER_BLOCK
515546
&& self
516547
.fluid_level
517-
.get_fluid_level(i, j - 1, k)
518-
.get_block(j - 1)
548+
.get_fluid_level(sample_x, sample_y - 1, sample_z)
549+
.get_block(sample_y - 1)
519550
== &LAVA_BLOCK
520551
{
521552
Some(block_state.default_state)
522553
} else {
523-
let barrier_sample = router.barrier_noise(pos, sample_options);
554+
let mut barrier_sample = None;
524555
let fluid_level3 = self.get_water_level(
525556
packed_block_and_hypots[1].0,
526557
router,
527558
height_estimator,
528559
sample_options,
529560
);
530561
let e = d * self.calculate_density(
562+
&mut barrier_sample,
531563
pos,
532-
barrier_sample,
564+
router,
565+
sample_options,
533566
fluid_level2.clone(),
534567
fluid_level3.clone(),
535568
);
@@ -551,8 +584,10 @@ impl WorldAquiferSampler {
551584
let g = d
552585
* f
553586
* self.calculate_density(
587+
&mut barrier_sample,
554588
pos,
555-
barrier_sample,
589+
router,
590+
sample_options,
556591
fluid_level2,
557592
fluid_level4.clone(),
558593
);
@@ -569,8 +604,10 @@ impl WorldAquiferSampler {
569604
let h = d
570605
* g
571606
* self.calculate_density(
607+
&mut barrier_sample,
572608
pos,
573-
barrier_sample,
609+
router,
610+
sample_options,
574611
fluid_level3,
575612
fluid_level4,
576613
);
@@ -1589,9 +1626,10 @@ mod test {
15891626
let level1 = FluidLevel::new(h1, &WATER_BLOCK);
15901627
let level2 = FluidLevel::new(h2, &WATER_BLOCK);
15911628
let pos = UnblendedNoisePos::new(x, y, z);
1592-
let sample = router.barrier_noise(&pos, &env);
1629+
let mut sample = None;
1630+
15931631
assert_eq!(
1594-
aquifer.calculate_density(&pos, sample, level1, level2),
1632+
aquifer.calculate_density(&mut sample, &pos, &mut router, &env, level1, level2),
15951633
result
15961634
);
15971635
}

0 commit comments

Comments
 (0)