Repository navigation
Conversation
…cells Part of horizon-rust#9996. The terrain noise (old_blended_noise) is a lerp between two 16-octave smeared Perlin stacks. Lerp reads its first branch only where alpha is not 1 and its second only where alpha is not 0, and in the overworld about 37% of the coarse points have alpha 1 and 50% alpha 0. The lerp now passes each branch a bit per Y of each column it reads, and a noise volume skips the others (DensitySampler::sample_needed, Noise::add_to_needed; samplers without it still sample everything). When a column's Y cells change at every Y, as in the stacks' high-frequency octaves, four Ys in four cells now go through the same vectorized lane code as four Ys in one cell, each lane with its own cell's corner terms. Gradient lookups are a loop rather than array::map, which LLVM had left out of line. Every value is computed by the same operations in the same order: snapshots match byte for byte and the tests compare against the unbatched, unmasked loops. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fekd3xkgubE8VfXrALh2td
This was referenced Nov 5, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
Part of #9996.
PerlinNoise::add_volumeand the scalarPerlinNoise::sampleare the largest share of terrain generation in the issue's flamegraphs. Profilingchunkgen_bench(overworld, seed 12345, 1 thread) agrees: 10.6% of the proto phase inadd_volume, 3.8% insampleand an out-of-linearray::map. About half ofadd_volume's time is the terrain noise,old_blended_noise: a lerp between two 16-octave smeared Perlin stacks (min_limit,max_limit) by an 8-octave alpha, whose high octaves change Y cell at every Y of a column.Three changes, all in
horizon-core, each value computed by the same operations in the same order:LerpSampler's volume path readsfirstonly where alpha is not 1 andsecondonly where it is not 0 (NaN reads both). In the overworld 37% of the terrain noise's coarse points have alpha exactly 1 and 50% exactly 0. The lerp now gives each sampled branch a bit per Y of each X/Z column it reads (DensitySampler::sample_needed,Noise::add_to_needed), and a Perlin volume skips the other Ys and wholly unread columns. Samplers without the method sample everything, as before, so caches and other nodes are untouched. Vanilla'sLerpFunction.Sampler.sampleVolumesamples both branches everywhere; the skipped values are never read.add_fouras four Ys in one cell, each lane taking its own cell's corner terms fromCornerTerms. Before, each such Y went one at a time.gradients_atusedarray::map, whose closure LLVM had left out of line (1.1% of the profile on its own); a loop now.sampleis inlined intoget3with it.Instruction counts (callgrind,
generate_protoonly, 64 overworld chunks):add_volume(withCornerTerms::new, now out of line) 842 M → 684 M (−19%), the scalar path (sample+map+get3) 273 M → 188 M (−31%), the whole proto phase 6.50 G → 6.26 G (−3.6%).Kind
Benchmark
Method of docs/surface-generation-benchmark.md: cases declared before editing, one discarded pair, then 5 alternating baseline/candidate pairs, identical
--profile fastbuilds ofcrates/horizon-world/examples/chunkgen_bench.rs(baseline origin/main 624c4f6). Common arguments:--seed 12345 --size 16 --center 0 0 --warmup --json --no-map(256 proto chunks, 196 decorated). Proto ms/chunk =wall_s× 1000 / 256 (not the thread-multiplied display).Proto ms/chunk, baseline → candidate:
Laptop (AMD Ryzen 7 7840HS, 8 cores / 16 threads, Linux, Rust 1.99.0; governor
performance, platform profileperformance, boost on, on AC). Every runtaskset -c 8-15(cores 4–7, both threads of each), sequential, nothing else heavy running. A laptop's boost and heat vary; each pair runs the baseline first, so heat building up within a pair would favour the baseline.Under full load, the way the game's worker pool runs (same laptop, no
taskset,--size 32: 1024 proto chunks, same seed and method, the baseline first in each pair):Every pair is faster with the change (0.4% to 7.0%). Decoration, ms per decorated chunk (median of the 5 pairs; this change does not target it): 1.922 → 1.856, 0.585 → 0.567, 0.336 → 0.351.
A remote build VM, for the record (Rust 1.99.1; every run
taskset -c 40-55, builds and other jobs on 0–39). Its speed flips between two levels about 2× apart for seconds to minutes at a time, even with the guest idle, so single pairs swing by ±30% and its medians say nothing at this size. The second round's binaries in both trees also carried an identical, unused local timing hook.Instruction counts on that VM do not depend on its speed (callgrind,
generate_protoonly,--size 8, no warm-up): overworld 6.50 G → 6.26 G (−3.6%), nether 2.97 G → 2.88 G (−3.3%).Exactness
--snapshot(terrain and decorated,--threads 4) byte for byte against the baseline: overworld seed 12345 at (0, 0), overworld seed −1 at (32, −32), the nether and the end: all 8 files identical.batched_volume_is_bit_identicalnow also runs the batched loop with masks of needed Ys (none, all, two random sets) against the one-at-a-time loop: needed Ys bit-identical, the others either the same value or untouched.lerp_samples_its_branches_only_where_alpha_reads_them: the overworld's compiled terrain noise over four volumes (with and without masks, 49, 64 and 65 Ys) against the same lerp whose branches hidesample_needed, bit for bit.Parity harnesses, on a remote build VM, all 10 pass in 17.5 min:
noise density terrain worldgen worldgen_random chunk_generation biome_generation material_surface structure_density flat_generation.cargo test -p horizon-core -p horizon-world --lib: 127 and 359 passed.cargo clippy -p horizon-core -p horizon-world --all-targets -- -D warnings: clean.Other projects' code
none
Self-check
pr_ready (
tools/pr_ready.py --quick, against origin/main at 624c4f6, 2 min 9 s)The touched files are unchanged on main since 624c4f6 (now ff4b4b1); the branch merges cleanly.
https://claude.ai/code/session_01WZzq8LUjYucp4kaN6UfSg7
🤖 Generated with Claude Code