mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Turn broadphase contacts into a job (#5245)
Okay when I said no more physics this was a low-hanging fruit as we can get rid of the mapmanager getmapentityid for every contact so.
This commit is contained in:
@@ -31,11 +31,14 @@ namespace Robust.Shared.Physics.Systems
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
|
||||
private EntityQuery<BroadphaseComponent> _broadphaseQuery;
|
||||
private EntityQuery<FixturesComponent> _fixturesQuery;
|
||||
private EntityQuery<MapGridComponent> _gridQuery;
|
||||
private EntityQuery<PhysicsComponent> _physicsQuery;
|
||||
private EntityQuery<TransformComponent> _xformQuery;
|
||||
private EntityQuery<PhysicsMapComponent> _mapQuery;
|
||||
|
||||
private float _broadphaseExpand;
|
||||
|
||||
/*
|
||||
* Okay so Box2D has its own "MoveProxy" stuff so you can easily find new contacts when required.
|
||||
* Our problem is that we have nested broadphases (rather than being on separate maps) which makes this
|
||||
@@ -43,23 +46,21 @@ namespace Robust.Shared.Physics.Systems
|
||||
* Hence we need to check which broadphases it does intersect and checkar for colliding bodies.
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// How much to expand bounds by to check cross-broadphase collisions.
|
||||
/// Ideally you want to set this to your largest body size.
|
||||
/// This only has a noticeable performance impact where multiple broadphases are in close proximity.
|
||||
/// </summary>
|
||||
private float _broadphaseExpand;
|
||||
|
||||
private const int PairBufferParallel = 8;
|
||||
|
||||
private ObjectPool<List<FixtureProxy>> _bufferPool =
|
||||
new DefaultObjectPool<List<FixtureProxy>>(new ListPolicy<FixtureProxy>(), 2048);
|
||||
private BroadphaseContactJob _contactJob;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_contactJob = new()
|
||||
{
|
||||
_mapManager = _mapManager,
|
||||
System = this,
|
||||
BroadphaseExpand = _broadphaseExpand,
|
||||
};
|
||||
|
||||
_broadphaseQuery = GetEntityQuery<BroadphaseComponent>();
|
||||
_fixturesQuery = GetEntityQuery<FixturesComponent>();
|
||||
_gridQuery = GetEntityQuery<MapGridComponent>();
|
||||
_physicsQuery = GetEntityQuery<PhysicsComponent>();
|
||||
_xformQuery = GetEntityQuery<TransformComponent>();
|
||||
@@ -71,7 +72,11 @@ namespace Robust.Shared.Physics.Systems
|
||||
Subs.CVar(_cfg, CVars.BroadphaseExpand, SetBroadphaseExpand, true);
|
||||
}
|
||||
|
||||
private void SetBroadphaseExpand(float value) => _broadphaseExpand = value;
|
||||
private void SetBroadphaseExpand(float value)
|
||||
{
|
||||
_contactJob.BroadphaseExpand = value;
|
||||
_broadphaseExpand = value;
|
||||
}
|
||||
|
||||
#region Find Contacts
|
||||
|
||||
@@ -176,65 +181,34 @@ namespace Robust.Shared.Physics.Systems
|
||||
if (moveBuffer.Count == 0)
|
||||
return;
|
||||
|
||||
var count = moveBuffer.Count;
|
||||
var contactBuffer = ArrayPool<List<FixtureProxy>>.Shared.Rent(count);
|
||||
var pMoveBuffer = ArrayPool<(FixtureProxy Proxy, Box2 AABB)>.Shared.Rent(count);
|
||||
|
||||
var idx = 0;
|
||||
_contactJob.MapUid = _mapManager.GetMapEntityIdOrThrow(mapId);
|
||||
_contactJob.MoveBuffer.Clear();
|
||||
|
||||
foreach (var (proxy, aabb) in moveBuffer)
|
||||
{
|
||||
contactBuffer[idx] = _bufferPool.Get();
|
||||
pMoveBuffer[idx++] = (proxy, aabb);
|
||||
_contactJob.MoveBuffer.Add((proxy, aabb));
|
||||
}
|
||||
|
||||
var options = new ParallelOptions
|
||||
for (var i = _contactJob.ContactBuffer.Count; i < _contactJob.MoveBuffer.Count; i++)
|
||||
{
|
||||
MaxDegreeOfParallelism = _parallel.ParallelProcessCount,
|
||||
};
|
||||
_contactJob.ContactBuffer.Add(new List<FixtureProxy>());
|
||||
}
|
||||
|
||||
var batches = (int)MathF.Ceiling((float) count / PairBufferParallel);
|
||||
var count = moveBuffer.Count;
|
||||
|
||||
Parallel.For(0, batches, options, i =>
|
||||
{
|
||||
var start = i * PairBufferParallel;
|
||||
var end = Math.Min(start + PairBufferParallel, count);
|
||||
|
||||
for (var j = start; j < end; j++)
|
||||
{
|
||||
var (proxy, worldAABB) = pMoveBuffer[j];
|
||||
var buffer = contactBuffer[j];
|
||||
|
||||
var proxyBody = proxy.Body;
|
||||
DebugTools.Assert(!proxyBody.Deleted);
|
||||
|
||||
var state = (this, proxy, worldAABB, buffer);
|
||||
|
||||
// Get every broadphase we may be intersecting.
|
||||
_mapManager.FindGridsIntersecting(mapId, worldAABB.Enlarged(_broadphaseExpand), ref state,
|
||||
static (EntityUid uid, MapGridComponent _, ref (
|
||||
SharedBroadphaseSystem system,
|
||||
FixtureProxy proxy,
|
||||
Box2 worldAABB,
|
||||
List<FixtureProxy> pairBuffer) tuple) =>
|
||||
{
|
||||
ref var buffer = ref tuple.pairBuffer;
|
||||
tuple.system.FindPairs(tuple.proxy, tuple.worldAABB, uid, buffer);
|
||||
return true;
|
||||
}, approx: true, includeMap: false);
|
||||
|
||||
// Struct ref moment, I have no idea what's fastest.
|
||||
buffer = state.buffer;
|
||||
FindPairs(proxy, worldAABB, _mapManager.GetMapEntityId(mapId), buffer);
|
||||
}
|
||||
});
|
||||
_parallel.ProcessNow(_contactJob, count);
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var proxyA = pMoveBuffer[i].Proxy;
|
||||
var proxies = contactBuffer[i];
|
||||
var proxies = _contactJob.ContactBuffer[i];
|
||||
|
||||
if (proxies.Count == 0)
|
||||
continue;
|
||||
|
||||
var proxyA = _contactJob.MoveBuffer[i].Proxy;
|
||||
var proxyABody = proxyA.Body;
|
||||
FixturesComponent? manager = null;
|
||||
|
||||
_fixturesQuery.TryGetComponent(proxyA.Entity, out var manager);
|
||||
|
||||
foreach (var other in proxies)
|
||||
{
|
||||
@@ -253,13 +227,8 @@ namespace Robust.Shared.Physics.Systems
|
||||
|
||||
_physicsSystem.AddPair(proxyA.FixtureId, other.FixtureId, proxyA, other);
|
||||
}
|
||||
|
||||
_bufferPool.Return(contactBuffer[i]);
|
||||
pMoveBuffer[i] = default;
|
||||
}
|
||||
|
||||
ArrayPool<List<FixtureProxy>>.Shared.Return(contactBuffer);
|
||||
ArrayPool<(FixtureProxy Proxy, Box2 AABB)>.Shared.Return(pMoveBuffer);
|
||||
moveBuffer.Clear();
|
||||
movedGrids.Clear();
|
||||
}
|
||||
@@ -516,5 +485,51 @@ namespace Robust.Shared.Physics.Systems
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private record struct BroadphaseContactJob() : IParallelRobustJob
|
||||
{
|
||||
public SharedBroadphaseSystem System = default!;
|
||||
public IMapManager _mapManager = default!;
|
||||
|
||||
public float BroadphaseExpand;
|
||||
|
||||
public EntityUid MapUid;
|
||||
|
||||
public List<List<FixtureProxy>> ContactBuffer = new();
|
||||
public List<(FixtureProxy Proxy, Box2 WorldAABB)> MoveBuffer = new();
|
||||
|
||||
public int BatchSize => 8;
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
var (proxy, worldAABB) = MoveBuffer[index];
|
||||
var buffer = ContactBuffer[index];
|
||||
buffer.Clear();
|
||||
|
||||
var proxyBody = proxy.Body;
|
||||
DebugTools.Assert(!proxyBody.Deleted);
|
||||
|
||||
var state = (System, proxy, worldAABB, buffer);
|
||||
|
||||
// Get every broadphase we may be intersecting.
|
||||
_mapManager.FindGridsIntersecting(MapUid, worldAABB.Enlarged(BroadphaseExpand), ref state,
|
||||
static (EntityUid uid, MapGridComponent _, ref (
|
||||
SharedBroadphaseSystem system,
|
||||
FixtureProxy proxy,
|
||||
Box2 worldAABB,
|
||||
List<FixtureProxy> pairBuffer) tuple) =>
|
||||
{
|
||||
ref var buffer = ref tuple.pairBuffer;
|
||||
tuple.system.FindPairs(tuple.proxy, tuple.worldAABB, uid, buffer);
|
||||
return true;
|
||||
},
|
||||
approx: true,
|
||||
includeMap: false);
|
||||
|
||||
// Struct ref moment, I have no idea what's fastest.
|
||||
buffer = state.buffer;
|
||||
System.FindPairs(proxy, worldAABB, MapUid, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user