MONKEY (perf): WOW_PERF_CROWD probe crowd; perf measurement notes in LIGHTING.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
pkuzic
2026-09-26 04:01:34 +01:00
co-authored by Claude Opus 5.5
parent 18effa6e78
commit 891a4da5a3
3 changed files with 85 additions and 1 deletions
+9
View File
@@ -178,6 +178,8 @@ is its own module, documented in `WATER.md`.
by `cargo check`.
- Exterior point lights are selected per draw unit (12 slots, ranked against the chunk's box); the
cube-map occlusion is evaluated for the nearest three.
- Portal bleed fixtures (`update_bleed_fixtures`, `daylight.rs`) are re-evaluated at 10 Hz, not per
frame; a new doorway or a dial change runs it at once. Sources are bucketed per placement.
## Build
@@ -188,6 +190,13 @@ cargo build --release -p benilla
Debug tracing: `WOW_TORCH_TRACE=1`, `WOW_POINTS_DUMP=1`, `WOW_SHADOW_TRACE=1`, and the cvar
`interiorDebug` 1..4.
Performance: measure a `play`/release build, never `dev`. `WOW_CAPTURE=<scenario>
WOW_FPS_PROBE=600 WOW_FPS_JOURNAL=<csv> WOW_GPU_PASSES=1 WOW_WIN=2560x1440` prints frame, CPU and
per-pass GPU times; `BENILLA_HOME=<dir>` supplies the `config.toml` (a capture never seeds the
Graphics Preset, so write the rows out). `WOW_PERF_CROWD=<n>` stands n players at the look point.
Night fixtures: `perf-northshire-night`, `perf-abbey-night`. Per-system CPU: build with
`--features benilla-app/trace_chrome`.
## Licence
Same as upstream: MIT OR Apache-2.0. Code and techniques taken from other projects (WarcraftXL,
@@ -1834,3 +1834,76 @@ fn seed_equipped_bags(
}
}
}
/// MONKEY (perf): `WOW_PERF_CROWD=<n>` stands `n` naked human players (display 49) in a grid
/// around the scenario's look point, on the ground — a start zone's crowd for the FPS probe, so the
/// per-unit costs (animation, the shadow lanes' CPU skinning) are in the measurement. Off unset.
pub(super) fn seed_perf_crowd(
mut commands: Commands,
ctx: Res<CaptureCtx>,
progress: Res<WorldLoadProgress>,
spatial: avian3d::prelude::SpatialQuery,
mut seeded: Local<bool>,
) {
let Some(n) = std::env::var("WOW_PERF_CROWD").ok().and_then(|v| v.parse::<u32>().ok()) else {
return;
};
let Some(scenario) = ctx.scenario else {
return;
};
if *seeded || !(progress.total > 0 && progress.ready == progress.total) {
return;
}
*seeded = true;
use benilla_protocol::messages::ObjectFields;
let per_row = 6u32;
for i in 0..n {
let (row, col) = ((i / per_row) as f32, (i % per_row) as f32);
let wow = [
scenario.look[0] + (row - 1.0) * 2.5,
scenario.look[1] + (col - per_row as f32 * 0.5) * 2.5,
scenario.look[2] + 40.0,
];
let mut pos = wow_to_bevy(wow);
if let Some(hit) = spatial.cast_ray(
pos,
Dir3::NEG_Y,
200.0,
true,
&benilla_world::collision::WorldCollision::body_filter(),
) {
pos.y -= hit.distance;
}
commands.spawn((
crate::net::Guid(0x5100 + u64::from(i)),
crate::net::NetEntity {
kind: benilla_protocol::EntityKind::Player,
display_id: Some(49),
scale: 1.0,
},
crate::net::ObjectStore(ObjectFields::from_pairs(&[
(22, 100),
(28, 100),
(34, 12),
(35, 1),
(36, 1 | 1 << 8),
])),
crate::entities::Equipment {
settled: true,
..default()
},
benilla_world::world_unit::WorldUnit {
wades: true,
scale: 1.0,
height: crate::entities::CollisionHeight::default().0,
bound: None,
},
Transform {
translation: pos,
rotation: Quat::from_rotation_y(i as f32 * 0.7),
..default()
},
Visibility::default(),
));
}
}
+3 -1
View File
@@ -119,7 +119,7 @@ mod probes;
mod scenarios;
use crate::run_mode::CaptureMode;
pub(crate) use depth_probe::DepthProbePlugin;
use fixtures::{seed_ui_fixture, seed_wind_player};
use fixtures::{seed_perf_crowd, seed_ui_fixture, seed_wind_player};
pub(crate) use live_shot::LiveShotPlugin;
pub(crate) use phase_probe::PhaseProbePlugin;
pub(crate) use pick_probe::PickProbePlugin;
@@ -913,6 +913,8 @@ impl Plugin for CapturePlugin {
})
.add_systems(Update, pin_scene.in_set(WorldStage::Present))
.add_systems(Update, seed_wind_player)
// MONKEY (perf): the probe crowd (`WOW_PERF_CROWD`).
.add_systems(Update, seed_perf_crowd)
// Before the UnitFeed pass: the seed stands in for wire data that in live play
// filled the app caches on EARLIER frames, so the same frame's feeds (item-template
// / player-req pushes, then the merchant paint) must all see it. Unordered, the