115 lines
3.2 KiB
Markdown
115 lines
3.2 KiB
Markdown
# lofivor sandbox - stress test design
|
|
|
|
a minimal harness for finding entity count ceilings on weak hardware before designing game systems.
|
|
|
|
## goals
|
|
|
|
**purpose:** answer "how many simple entities can we update and render at 60fps?"
|
|
|
|
**target hardware:**
|
|
- primary: intel i5-6500T + HD 530 (thinkcentre m900) @ 1280x1024
|
|
- secondary: windows laptop for dev iteration
|
|
|
|
**what it does:**
|
|
- spawns colored circles that drift toward screen center
|
|
- manual controls to add/remove entities in real-time
|
|
- on-screen metrics: entity count, frame time (ms), update time, render time
|
|
- circles respawn at random edge when reaching center
|
|
|
|
**what it doesn't do (yet):**
|
|
- no collision detection
|
|
- no player input beyond entity count controls
|
|
- no game logic, damage, spawning waves
|
|
- no particles or visual effects
|
|
|
|
**success criteria:**
|
|
- locked 60fps with some meaningful entity count (finding that number is the goal)
|
|
- clear breakdown of where frame time goes (CPU update vs GPU render)
|
|
- stable enough to leave running while tweaking counts
|
|
|
|
## data structures
|
|
|
|
```zig
|
|
const Entity = struct {
|
|
x: f32,
|
|
y: f32,
|
|
vx: f32,
|
|
vy: f32,
|
|
color: u32,
|
|
};
|
|
```
|
|
|
|
simple flat array of entities. no ECS, no spatial partitioning, no indirection. measuring the baseline - fancy structures come later.
|
|
|
|
**memory budget:** 20 bytes per entity. 10k entities = 200KB (fits in L2 cache on skylake).
|
|
|
|
## update loop
|
|
|
|
```
|
|
for each entity:
|
|
x += vx
|
|
y += vy
|
|
if distance_to_center < threshold:
|
|
respawn at random edge
|
|
recalculate vx, vy toward center
|
|
```
|
|
|
|
~5 float ops per entity per frame. no collision, no branching beyond respawn check.
|
|
|
|
**velocity:** on spawn, compute normalized direction to center, multiply by constant speed, store vx/vy.
|
|
|
|
## rendering
|
|
|
|
each frame:
|
|
1. clear screen (dark background #0a0a12)
|
|
2. draw all entities as filled circles (4px radius)
|
|
3. draw metrics overlay
|
|
|
|
**entity color:** cyan (#00ffff) - bright against dark background
|
|
|
|
**metrics overlay (top-left):**
|
|
```
|
|
entities: 5000
|
|
frame: 12.4ms
|
|
update: 8.2ms
|
|
render: 4.1ms
|
|
```
|
|
|
|
## controls
|
|
|
|
| key | action |
|
|
|-----|--------|
|
|
| `=` / `+` | add 100 entities |
|
|
| `-` | remove 100 entities |
|
|
| `shift + =` | add 1000 entities |
|
|
| `shift + -` | remove 1000 entities |
|
|
| `space` | pause update loop (render continues) |
|
|
| `r` | reset to 0 entities |
|
|
|
|
pause isolates render cost from update cost.
|
|
|
|
## what we're measuring
|
|
|
|
**key questions:**
|
|
1. what's the entity ceiling at 60fps? (where frame time crosses 16.6ms)
|
|
2. is it CPU-bound or GPU-bound? (compare update vs render time)
|
|
3. where does it fall apart? (gradual degradation or sudden cliff?)
|
|
|
|
**hypotheses to test:**
|
|
- HD 530 might struggle with thousands of individual draw calls (GPU-bound)
|
|
- if CPU-bound, update loop needs SIMD or better memory access
|
|
- skylake's 4 cores are untouched - parallelism is a future lever
|
|
|
|
## next steps based on results
|
|
|
|
| bottleneck | next experiment |
|
|
|------------|-----------------|
|
|
| render (draw calls) | batch rendering - instancing, sprite batches |
|
|
| update (CPU) | SIMD, struct-of-arrays layout, multithreading |
|
|
| both equally | optimize either for gains |
|
|
|
|
## stretch measurements
|
|
|
|
- memory bandwidth (cache-bound?)
|
|
- draw call count vs batched draws
|
|
- fixed-point vs float update cost comparison
|