Performance
What rugen 0.7.0 measured and changed so the engine runs well on old hardware, and how to take the same numbers on your machine.
rugen 0.7.0 was an optimisation-only release. The bar was simple: a match
must run at 60 fps with time to spare on a 2012 dual-core laptop with an
integrated GPU and 4 GB of memory, and a Steam Deck must never notice the
engine. Everything below was measured with rugen bench, before and after,
on the same machine (a 2021 six-core laptop with an integrated AMD GPU),
with the classic 1v1 simulation bit-identical throughout (the golden
checksums in crates/sim pin it).
Before and after
| 0.6.5 | 0.7.0 | |
|---|---|---|
| Convert a 105 MB fighter archive | 20 s, 1.1 GB peak memory | 2.9 s, 0.36 GB |
| Convert Goku (81 MB of sprites) | 29 s, 2.2 GB | 3.5 s, 0.5 GB |
| Same, on one core (old dual-core proxy) | ~130 s | ~12 s |
| Memory of a loaded fighter (Goku) | 109 MB | 40 MB |
| Two fighters loaded, headless match | 138 MB | 48 MB |
| GPU textures kept after a match ends | all of them, forever (973 for one match) | freed |
| Draw calls per fight frame | 60–75 | 40–49 |
| Title screen draw calls | 234 | 55 |
| Frame spikes in the first 5 s of a fight (over 33 ms) | 2–6 (sprite decode, sound decode) | 0 |
| Sim step, 1v1 with supers (mean / worst) | 0.070 / 0.20 ms | 0.064 / 0.19 ms |
| 8-frame rollback re-simulation, 1v1 | 0.56 ms | 0.51 ms |
| Sim step, Simul 4v4 | 0.22 ms | 0.17–0.21 ms |
Fight load from .rgc | 110 ms | 55 ms |
| OpenGL fallback | selected but never actually used | works; auto low-spec mode |
Numbers of a quiet run; mean of several. The simulation was already far inside its budget (an online 8-frame rollback has 4 ms on a slow CPU; it takes 0.5 ms here, so about 2 ms there). The real problems were elsewhere: conversion, memory, textures and first-draw hitches.
What changed
Conversion. Sprites were compressed with zstd at level 19, which was
92 % of the time; level 6 makes files about 10 % larger and eight times
faster. The SFF is streamed through the encoder instead of being decoded
twice into memory, and the written file is checked block by block instead
of being decoded again. Verification reuses the compiled logic and caches
the common files; stage preloading reads the stored bytes instead of
rebuilding a whole SFF. Existing .rgc / .rgs files are untouched and
still load.
Memory. A fighter’s sprite data stays in the file and each sprite is read when it is first drawn; sounds are decoded when played, on a worker thread, into a bank capped at 32 MB; the raw controller text is dropped once a state is compiled. A fight waits for a preload in flight instead of loading the same fighter twice. The match screen now gives back every GPU texture when it ends.
Rendering. One vertex and one index buffer kept across frames, a glyph atlas per font (every character was its own texture and draw call), no per-frame clones of the stage, animations and explod lists, redundant pipeline switches skipped. The device is requested with downlevel limits so OpenGL-only adapters get a device instead of a panic, and the adapter, backend and driver are logged at start.
Hitches. Sprites decode on a worker thread and upload under a per-frame budget (bytes, textures and time), with a look-ahead over every animation on screen; a local fight is loaded on the versus screen and its stage, lifebar and common actions are uploaded there. The hot-reload check runs on its own thread; the frame pacing naps instead of spinning.
Low-spec mode. [video] render_scale draws the fight at 0.75 or 0.5
of the window and scales it up with sharp pixels; auto turns it on for
integrated GPUs on the OpenGL fallback. OPTIONS → VIDEO → RENDER SCALE.

Simulation. The expression VM no longer allocates per trigger line,
bytecode ops shrank from 48 to 24 bytes, name tables use a fast hash, and
helpers without keyctrl carry no command state. A deep checksum (every
field of every player, explod and projectile) sits next to the fast one in
the golden tests so an optimisation cannot change play unnoticed.
Measure your own machine
rugen bench # two fighters from chars/, 3600 frames
rugen bench --chars Goku,Sasuke --convert chars/originals/Goku.zip --out bench.md
RUGEN_FRAMESTATS=1 rugen # per-second frame phases in the log while playing
rugen bench prints a markdown table: simulation step, snapshot, checksum
and a real 8-frame rollback for a 1v1, a Simul 4v4 and an arena match;
load times and peak memory; a 900-frame fight with frame statistics (update,
draw-list build, submit, present, draw calls, textures); and a conversion
in a child process with its own peak memory. --backend gl runs the fight
through the OpenGL fallback.
Something wrong on this page? Edit it on GitHub.