Files
sbox-public/engine/Sandbox.Engine/Scene/GameObjectSystems/VerletRopeSystem.cs
Lorenz Junglas 7258b356f8 Improve performance timing scopes (#4176)
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
2026-03-02 13:05:45 +01:00

30 lines
806 B
C#

using System.Collections.Concurrent;
namespace Sandbox;
/// <summary>
/// Simulates VerletRope components in parallel during PrePhysicsStep
/// </summary>
internal sealed class VerletRopeGameSystem : GameObjectSystem
{
private readonly List<VerletRope> _ropes = new();
public VerletRopeGameSystem( Scene scene ) : base( scene )
{
// Listen to StartFixedUpdate to run before physics
Listen( Stage.StartFixedUpdate, -100, UpdateRopes, "UpdateRopes" );
}
void UpdateRopes()
{
using var _ = PerformanceStats.Timings.Physics.Scope();
_ropes.Clear();
Scene.GetAll<VerletRope>( _ropes );
if ( _ropes.Count == 0 ) return;
var timeDelta = Time.Delta;
System.Threading.Tasks.Parallel.ForEach( Partitioner.Create( _ropes, loadBalance: true ), rope => rope.Simulate( timeDelta ) );
}
}