Skip to content

bench: crowd load test — N-avatar ceiling (~22 @ 60fps) gating #199 - #350

Draft
arkavo-com wants to merge 2 commits into
mainfrom
perf/crowd-loadtest
Draft

bench: crowd load test — N-avatar ceiling (~22 @ 60fps) gating #199#350
arkavo-com wants to merge 2 commits into
mainfrom
perf/crowd-loadtest

Conversation

@arkavo-com

Copy link
Copy Markdown
Contributor

Summary

A VRMBenchmark --mode crowd load test to empirically find the N-avatar ceiling of the current single-avatar-per-renderer architecture, plus a library-level test of the crowd render path. This gates the decision on #199 (GPU occlusion culling): build it only if the target crowd size/density warrants it.

Draft — opened to share the measurements; not intended to merge as-is.

How it works

N renderers share one loaded model (1× geometry memory), each draws once per frame into a shared color+depth target (depth stored so avatars occlude), positioned by baking a grid offset into the view matrix under a shared projection (so depth stays consistent and avatars occlude correctly). Static pose to isolate render throughput. --count N sets the sweep ceiling; --stack overlaps avatars to measure the occlusion opportunity.

Results (M4 mini, 1024², MSAA 1×, static)

Avatars Frame (median) FPS 60fps 120fps
8 6.3 ms 159
16 11.8 ms 85
32 22.3 ms 45
64 43.3 ms 23
128 85.6 ms 12

Ceiling: ~22 avatars @ 60 fps, ~11 @ 120 fps. Cost is linear, ~0.62 ms/avatar — no batching/LOD/occlusion culling.

The occlusion measurement (gates #199)

--stack (63 of 64 avatars hidden behind the front one) costs 39.7 ms vs 43.3 ms spread — only ~8% cheaper. The renderer pays ~full price for invisible avatars; the 8% is just GPU early-Z skipping some occluded fragments. The dominant per-avatar cost (CPU encode, skinning, draw-call overhead) is paid regardless of visibility.

Conclusion on #199

Tests

  • CrowdRenderTests — validates the shared-model, shared-depth multi-renderer path renders, doesn't deadlock (5 avatars > 3 in-flight slots), and places distinct avatars.

🤖 Generated with Claude Code

arkavo-com and others added 2 commits June 13, 2026 21:59
)

VRMBenchmark --mode crowd [--count N] [--stack]: N renderers share one loaded
model, each drawn once per frame into a shared color+depth target (depth stored
so avatars occlude), positioned by baking a grid offset into the view matrix with
a shared projection. Sweeps N upward and reports the avatar count that fits the
60/120fps budget. --stack overlaps avatars (heavy occlusion) to measure how much
occlusion culling could recover.

Findings on this M4: ~22 avatars @ 60fps, ~11 @ 120fps, ~linear (~0.62ms/avatar).
Stacked (63 of 64 occluded) costs ~the same as spread (only ~8% cheaper from GPU
early-Z), confirming the renderer does NO occlusion culling — so #199 would help
dense/occluded crowds (recover hidden avatars' full cost) but not spread ones
(which need instancing/LOD).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Library-level test for the pattern the crowd load test (and future #199 work)
relies on: N renderers share one loaded model and draw once each into a shared
color+depth target, positioned via a per-renderer view offset under a shared
projection. Asserts it renders, doesn't deadlock on the per-renderer in-flight
semaphore (5 avatars > 3 slots), and places distinct avatars (5 cover more than 1).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant