From 891a4da5a3a3f3eb6aa4249c7a8ff0b33cd80238 Mon Sep 17 00:00:00 2001 From: pkuzic Date: Sat, 26 Sep 2026 03:00:37 +0100 Subject: [PATCH] MONKEY (perf): WOW_PERF_CROWD probe crowd; perf measurement notes in LIGHTING.md Co-Authored-By: Claude Opus 5.5 --- LIGHTING.md | 9 +++ crates/benilla-app/src/capture/fixtures.rs | 73 ++++++++++++++++++++++ crates/benilla-app/src/capture/mod.rs | 4 +- 3 files changed, 85 insertions(+), 1 deletion(-) diff --git a/LIGHTING.md b/LIGHTING.md index 18a1a6c4..2b40ac08 100644 --- a/LIGHTING.md +++ b/LIGHTING.md @@ -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= +WOW_FPS_PROBE=600 WOW_FPS_JOURNAL= WOW_GPU_PASSES=1 WOW_WIN=2560x1440` prints frame, CPU and +per-pass GPU times; `BENILLA_HOME=` supplies the `config.toml` (a capture never seeds the +Graphics Preset, so write the rows out). `WOW_PERF_CROWD=` 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, diff --git a/crates/benilla-app/src/capture/fixtures.rs b/crates/benilla-app/src/capture/fixtures.rs index 756b8968..ec1dbd0c 100644 --- a/crates/benilla-app/src/capture/fixtures.rs +++ b/crates/benilla-app/src/capture/fixtures.rs @@ -1834,3 +1834,76 @@ fn seed_equipped_bags( } } } + +/// MONKEY (perf): `WOW_PERF_CROWD=` 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, + progress: Res, + spatial: avian3d::prelude::SpatialQuery, + mut seeded: Local, +) { + let Some(n) = std::env::var("WOW_PERF_CROWD").ok().and_then(|v| v.parse::().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(), + )); + } +} diff --git a/crates/benilla-app/src/capture/mod.rs b/crates/benilla-app/src/capture/mod.rs index 331752d9..7d3bc400 100644 --- a/crates/benilla-app/src/capture/mod.rs +++ b/crates/benilla-app/src/capture/mod.rs @@ -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