feat: GPU optimization — lighting, viewport CA, benchmark mode, 531 FPS
- Resolution: 8x8 world cells, 2x2 UI cells (UI_SCALE=4) - GPU lighting: vertex-shader computed, light source list buffer (max 64) instead of O(N×R²) grid scan, O(N×S) per cell - Viewport-aware CA: iterate only active chunks, not all 250×250 - Flat array entity/item/shadow maps instead of HashMaps - Flat 128-entry ASCII atlas array instead of HashMap lookup - Partial grid upload: viewport + 30-cell margin only - Pre-allocated viewport arrays in renderer structs (zero alloc/frame) - Skip CPU lighting for GPU modes (pass None) - Benchmark mode: --mode benchmark with per-subsystem timing - GpuLightSource struct, light_count in push constants - gather_sources_in_range() for viewport-scoped source gathering Benchmark (600 ticks, release): Graphics: 531 FPS (was 386, +38%), render 1013us (was 1699us, -40%) ASCII: 402 FPS (was 313, +28%), render 1502us (was 2346us, -36%) All 171 tests + 14 scenarios pass.
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
use verbatim::ai::AiAction;
|
||||
use verbatim::ai::GameSession;
|
||||
|
||||
fn setup() -> GameSession {
|
||||
let mut s = GameSession::new_seeded(42);
|
||||
s.init_empty();
|
||||
s.clear_area(90, 90, 80, 80);
|
||||
s
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn corpses_do_not_cause_lag() {
|
||||
let mut s = setup();
|
||||
for i in 0..20 {
|
||||
s.perform_action(&AiAction::Spawn {
|
||||
kind: "goblin".into(),
|
||||
x: 100.0 + (i % 5) as f32 * 3.0,
|
||||
y: 100.0 + (i / 5) as f32 * 3.0,
|
||||
});
|
||||
}
|
||||
s.step(20);
|
||||
let ids: Vec<u32> = s
|
||||
.get_entities()
|
||||
.into_iter()
|
||||
.filter(|e| e.kind == "Goblin")
|
||||
.map(|e| e.id)
|
||||
.collect();
|
||||
|
||||
let start_before = std::time::Instant::now();
|
||||
s.step(60);
|
||||
let before_ms = start_before.elapsed().as_secs_f32() * 1000.0 / 60.0;
|
||||
|
||||
for id in &ids {
|
||||
s.perform_action(&AiAction::DamageEntity {
|
||||
id: *id,
|
||||
amount: 100.0,
|
||||
});
|
||||
}
|
||||
let start_after = std::time::Instant::now();
|
||||
s.step(60);
|
||||
let after_ms = start_after.elapsed().as_secs_f32() * 1000.0 / 60.0;
|
||||
|
||||
assert!(
|
||||
after_ms < before_ms * 3.0,
|
||||
"corpse simulation should not be dramatically slower: before={:.2}ms after={:.2}ms",
|
||||
before_ms,
|
||||
after_ms
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user