Avoid RenderGroupKey allocations
This would allocate a lot easily 60Mb/s.
Instead of a dedicated struct we now compute a 64bit hash and use that for render grouping.
Remove per frame HashSet, List and LINQ allocations
Fixes timing scopes to more accurately represent a per-frame main thread breakdown, and prevents spikes when GC is executed.
- **GcPause**
- New separate timing scope showing time spent in GC per frame
- GC pause time is subtracted from all other scopes, so each scope now only tracks its own code execution and no longer includes GC overhead
- e.g. when GC occurs during the audio scope, the audio scope no longer spikes to 20ms
- **AudioMixingThread** removed from the main scopes
- Runs on a separate thread, so its timings are effectively meaningless in the main thread view
- All other scopes are main thread only
- No longer relevant given the audio optimisation work done over the past months
- **Scene** scope removed
- Didn't make much sense as it was an aggregate wrapping many other timing scopes
- Replaced with a finer `Update` scope that tracks `Component.FixedUpdate`/`Update`
- **Editor** scope no longer shows in-game
- Scopes reschuffled
- e.g. verlet rope physics traces are now tracked under the physics scope
- Audio occlusion queries are now tracked under the audio scope
https://files.facepunch.com/lolleko/2026/March/02_12-59-QuixoticMarten.png