Files
tactical-shooter/docs/performance-budget.md
T
shawn e385eae0f5 feat: performance budget profiling setup
- docs/performance-budget.md: 60fps/2GB VRAM budget with CPU, GPU,
  memory, and draw-call targets (P95<16.6ms, P99<50ms)
- scripts/profiling/: SceneTree + Node profilers, test scenes
- scripts/generate_occluders.gd: auto-generate OccluderInstance3D
  from CSG wall pieces (128^3 voxel occlusion culling)
- scripts/convert_csg_to_mesh.gd: CSG->StaticMesh baker with LOD
  slots (LOD1@15m, LOD2@30m)
- project.godot: occlusion culling + LOD settings enabled
- modular scene UV2 data from lightmapping pass
- rcon_command_handler.gd conflict resolved (kept upstream plugin cmd)
- Fixed profiler_node.gd warmup frame bug (60 frames, not 3)
- Fixed convert_csg_to_mesh.gd LOD API (add_lod + distance)
2026-07-01 19:01:03 -04:00

7.2 KiB
Raw Permalink Blame History

Performance Budget & Profiling Methodology

Target hardware: GTX 1050 / RX 560 class (2 GB VRAM) Engine: Godot 4.7 Forward+ renderer Frame target: 60 fps (16.6 ms per frame)


1. Frame Budget (16.6 ms)

Phase Budget Notes
GPU total 8.0 ms Forward+ opaque pass, transparent, sky, tonemap
CPU — physics 1.5 ms 128-tick, capsule sweep, raycasts
CPU — render 1.5 ms Culling, sorting, draw-call submission
CPU — gameplay 3.0 ms Input, animation, network interpolation
Headroom 2.6 ms Buffer for frametime variance (≈15%)

Bottleneck detection thresholds

Metric Green Yellow Red
GPU frame ms < 5.0 5.07.5 > 7.5
CPU frame ms < 10.0 10.013.0 > 13.0
Draw calls < 1200 12001800 > 2000
Triangles / frame < 300K 300K600K > 1M
VRAM used < 1.2 GB 1.21.7 GB > 1.8 GB
Main RAM used < 2.0 GB 2.03.0 GB > 3.5 GB

2. Rendering Budget

Triangle Count

Asset type LOD0 tris LOD1 tris (50%) LOD2 tris (25%) Instances/map
Wall panel 800 400 200 ~600
Floor slab 800 400 200 ~400
Pillar 400 200 100 ~80
Doorway / window 1200 600 300 ~60
Accent panel 400 200 100 ~40

Budget calculation (max visible):

  • Walls ≈ 50 visible × 800 = 40K (LOD0)
  • Floors ≈ 20 visible × 800 = 16K (LOD0)
  • Details ≈ 30 visible × 400 = 12K (LOD0)
  • Total LOD0 tris ≈ 68K — well within budget
  • With LOD + occlusion, visible tris on target GPU < 200K

Draw Calls

Pass Draw calls Notes
Opaque solids 600800 Per-object, one per visible piece
Shadows 200400 Single directional cascade
Transparent 50100 Reflection probes, lightmap
UI 100200 HUD, minimap, scoreboard
Total 9501500 Well within 2000 target

VRAM Budget

Category Size Notes
Texture pool (1K × 7 mats) 75 MB 28 PBR maps
Lightmap atlas 64128 MB 2048 × 2048, DXT5
Shadow map 16 MB 2048 × 2048 atlas
Mesh geometry 2040 MB LOD0LOD2
Reflection probe cubemaps 8 MB 8 × 512 cubemaps
Audio + misc 50 MB
Total base ~300 MB
Headroom 1.7 GB For gameplay assets, streaming

3. LOD Strategy

CSG-based pieces (current)

Since the modular kit uses CSG nodes (procedural geometry), traditional mesh LOD is not directly supported. The equivalent optimizations are:

Technique Benefit How
Visibility ranges Skip rendering past cutoff visibility_range_end on each CSGBox3D/Combiner
Occlusion culling Skip behind-occluder geometry OccluderInstance3D on major walls
CSG → Mesh baking Replace procedural with static mesh convert_csg_to_mesh.gd tool script
Mesh LOD after baking Traditional LOD on static meshes Godot ImporterMesh LOD

Visibility Range Thresholds (CSG phase)

Asset Hide beyond Rationale
Wall panels 50 m OC sightlines rarely exceed 40 m
Floor slabs 60 m Visible as ground plane further
Pillars 30 m Thin silhouette, cull earlier
Beams 30 m Ceiling detail, only visible indoors
Accent panels 20 m Small team-color decals
Doorway / window 40 m Opening shapes visible at medium range

Mesh LOD Targets (baked mesh phase)

LOD Distance Tris % Notes
0 015 m 100% Full detail, panel gaps
1 1540 m 50% Collapse bevels, remove small holes
2 4080 m 25% Planar collapse, aggressive decimate
3 80 m+ CULL Not visible at competitive sightlines

4. Occlusion Culling

Implementation

  • OccluderInstance3D nodes auto-generated from wall CSGBox3D geometry
  • Voxel resolution: 128³ (good balance of accuracy vs memory)
  • Generation script: client/scripts/generate_occluders.gd@tool script
  • Activation: Scene tree → Add OccluderInstance3D → Set occluder shape to box matching wall extents

Occluder Coverage

Occluder origin Covers Shape
Exterior walls Block view of outdoor Box
Interior dividers Lane separation Box
Pillar clusters Mid-range detail Box

Expected culling benefit: 3050% reduction in visible geometry on a 3-lane map with interior dividers.


5. Profiling Methodology

Toolchain

Tool Use
Godot Editor Debugger Real-time frame profiler, monitor, 3D scene debug
profile_scene.gd Headless frame-time capture
GPU vendor tools (NVIDIA NSight / Radeon GPA) GPU-bound profiling
Frame debugger (Godot built-in) Draw-call inspection

Profiling Workflow

  1. CPU baseline: Run profile_scene.gd --headless on target hardware
  2. GPU baseline: Capture 1000+ frames with editor profiler, record p50/p95/p99
  3. Draw call audit: Use frame debugger to count and classify draw calls
  4. Occlusion test: Toggle OccluderInstance3D visibility, measure FPS delta
  5. LOD validation: Check LOD transitions with debug visualization
  6. Thermal test: 30-minute continuous gameplay, log frame-time variance

Pass/Fail Criteria

  • PASS: holds 60 fps on target hardware for 95% of frames across all 3 maps
  • ACCEPTABLE: drops to 4555 fps during intense firefights but recovers within 2 s
  • FAIL: sustained < 45 fps or > 100 ms frame-time spike

6. Reference Frames

kit_demo.tscn (indoor single-room, 5.12 × 5.12 m)

  • ~11 CSG pieces, 8 materials
  • Estimated draw calls: ~2030
  • Estimated triangles: ~8K12K
  • VRAM: ~80 MB (materials + lightmap)
  • Expected: > 200 fps on GTX 1050

template_map.tscn (3-lane showroom, 20 × 16 m)

  • ~25 CSG pieces + prefabs
  • Estimated draw calls: ~150250
  • Estimated triangles: ~40K60K
  • VRAM: ~200 MB (materials + lightmap + probes)
  • Expected: 90120 fps on GTX 1050

Full competitive map (target, ~80 × 60 m)

  • ~800 CSG pieces (when built from modular kit)
  • Estimated draw calls: ~1500 (with LOD + occlusion)
  • Estimated triangles: ~200K400K
  • VRAM: ~500 MB
  • Target: 60 fps on GTX 1050