Skip to content

Tyre smoke without particle emitters: 1–3 hitches per race instead of 14–46 - #19

Merged
mbeczynski merged 2 commits into
mainfrom
perf/race-frame
Oct 21, 2026
Merged

mbeczynski merged 2 commits into
mainfrom
perf/race-frame

Conversation

@mbeczynski

Copy link
Copy Markdown
Contributor

Problem

On iOS 27 (iPad M5 simulator), every active ParticleEmitterComponent drops the race to 12–15 fps for as long as it emits. The cost does not depend on the particle count or size: 5 particles/s cost as much as 110. Each drift therefore meant ~2 s of stutter. The smoke "warm-up" under the loading screen also caused stutter for ~1.2 s after the scene was revealed.

Found by: CPU work per frame was 0.4 ms, so the cost was not in game code. The hitches lined up with the player's drift to within a second. In A/B with -holdDrift, -noSmoke removed them (2 vs 40–100), -noSkids changed nothing, and a frozen frame at the same spot was smooth. On iOS 18 the emitter costs nothing.

Change

  • DriftSmoke: puffs are camera-facing quads in one LowLevelMesh rewritten every frame, with the same parameters as the old emitter (birth box, cone, lift, growth, spin, linear fade). Fading picks one of 16 copies of the texture by age, because UnlitMaterial has no vertex colour. writesDepth = false.
  • -noSmoke, -noSkids, -smokeLook (Debug/Family) for A/B, and track position in the hitch log.
  • tools/perf-run.sh: loading time, frame times, hitches, CPU and memory for each region.

Measurement (iPad M5 iOS 27 simulator, all 5 regions, A/B alternating against main)

main this PR
hitches per race (>25 ms) 14–46 1–3
longest frame 101–150 ms 33–50 ms
loading 8.7–9.5 s 8.0–8.6 s
memory 267–299 MB 253–283 MB

The smoke looks the same in screenshots mid-drift (old vs new).

Tests

  • swift test 65/65
  • Debug / Family / Release build
  • XCUITest on a clean install: GameplayUITests 7/7, GarageColorsUITests, AllTracksUITests (every track and every car to the finish), all passed; no new crash reports

Not measured on a physical iPad.

🤖 Generated with Claude Code

On iOS 27 every active RealityKit particle emitter cut the race to
12-15 fps for as long as it emitted, whatever its particle count or size
(5 particles/s cost as much as 110). Drifting cars - and the smoke warm-up
under the loading screen - caused 14-46 hitches per race.

DriftSmoke keeps the same look (birth box, cone, lift, growth, spin, linear
fade) as camera-facing quads in one LowLevelMesh rewritten every frame;
fading picks one of 16 copies of the puff texture by age, because
UnlitMaterial has no vertex colour.

Simulator iPad M5 iOS 27, all five regions, A/B against main:
hitches 14-46 -> 1-3 per race, longest frame 101-150 -> 33-50 ms,
loading 0.7 s faster, memory 15 MB lower.

Also: -noSmoke / -noSkids / -smokeLook for A/B, track position in hitch
logs, tools/perf-run.sh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mbeczynski mbeczynski self-assigned this Oct 21, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mbeczynski
mbeczynski merged commit 78c7566 into main Oct 21, 2026
1 check passed
@mbeczynski
mbeczynski deleted the perf/race-frame branch October 21, 2026 12:03
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