Compare commits

...

6 Commits

Author SHA1 Message Date
wrenge 0876d3adcf Merge branch 'risky_optimizations' 2024-11-13 13:55:25 +03:00
wrenge 1fa0320845 precache collections 2024-11-13 13:55:02 +03:00
wrenge 815a83e3cb Use precached queue instead of linked list 2024-11-13 13:42:43 +03:00
wrenge 592ecebe1e Proximity grid list reuse 2024-11-13 13:25:13 +03:00
wrenge b2a217d4a3 Object pool 2024-11-13 13:21:41 +03:00
wrenge 5c0ba9dba1 Reuse grid instead of creating new 2024-11-13 13:14:32 +03:00
3 changed files with 28 additions and 17 deletions

View File

@ -130,7 +130,7 @@ namespace DotRecast.Detour.Crowd
private readonly DtObstacleAvoidanceParams[] _obstacleQueryParams; private readonly DtObstacleAvoidanceParams[] _obstacleQueryParams;
private readonly DtObstacleAvoidanceQuery _obstacleQuery; private readonly DtObstacleAvoidanceQuery _obstacleQuery;
private DtProximityGrid _grid; private readonly DtProximityGrid _grid;
private int _maxPathResult; private int _maxPathResult;
private readonly RcVec3f _agentPlacementHalfExtents; private readonly RcVec3f _agentPlacementHalfExtents;
@ -175,6 +175,7 @@ namespace DotRecast.Detour.Crowd
_agentIdx = new RcAtomicInteger(0); _agentIdx = new RcAtomicInteger(0);
_agents = new Dictionary<int, DtCrowdAgent>(); _agents = new Dictionary<int, DtCrowdAgent>();
_activeAgents = new List<DtCrowdAgent>(); _activeAgents = new List<DtCrowdAgent>();
_grid = new DtProximityGrid(_config.maxAgentRadius * 3);
// The navQuery is mostly used for local searches, no need for large node pool. // The navQuery is mostly used for local searches, no need for large node pool.
SetNavMesh(nav); SetNavMesh(nav);
@ -565,14 +566,18 @@ namespace DotRecast.Detour.Crowd
} }
} }
private readonly RcSortedQueue<DtCrowdAgent> UpdateMoveRequest_queue = new RcSortedQueue<DtCrowdAgent>((a1, a2) => a2.targetReplanTime.CompareTo(a1.targetReplanTime));
private readonly List<long> UpdateMoveRequest_reqPath = new List<long>();
private void UpdateMoveRequest(IList<DtCrowdAgent> agents, float dt) private void UpdateMoveRequest(IList<DtCrowdAgent> agents, float dt)
{ {
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.UpdateMoveRequest); using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.UpdateMoveRequest);
RcSortedQueue<DtCrowdAgent> queue = new RcSortedQueue<DtCrowdAgent>((a1, a2) => a2.targetReplanTime.CompareTo(a1.targetReplanTime)); RcSortedQueue<DtCrowdAgent> queue = UpdateMoveRequest_queue;
queue.Clear();
// Fire off new requests. // Fire off new requests.
List<long> reqPath = new List<long>(); List<long> reqPath = UpdateMoveRequest_reqPath;
reqPath.Clear();
for (var i = 0; i < agents.Count; i++) for (var i = 0; i < agents.Count; i++)
{ {
var ag = agents[i]; var ag = agents[i];
@ -865,7 +870,7 @@ namespace DotRecast.Detour.Crowd
{ {
using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.BuildProximityGrid); using var timer = _telemetry.ScopedTimer(DtCrowdTimerLabel.BuildProximityGrid);
_grid = new DtProximityGrid(_config.maxAgentRadius * 3); _grid.Clear();
for (var i = 0; i < agents.Count; i++) for (var i = 0; i < agents.Count; i++)
{ {

View File

@ -22,6 +22,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using DotRecast.Core.Buffers;
namespace DotRecast.Detour.Crowd namespace DotRecast.Detour.Crowd
{ {
@ -30,12 +31,14 @@ namespace DotRecast.Detour.Crowd
private readonly float _cellSize; private readonly float _cellSize;
private readonly float _invCellSize; private readonly float _invCellSize;
private readonly Dictionary<long, List<DtCrowdAgent>> _items; private readonly Dictionary<long, List<DtCrowdAgent>> _items;
private readonly RcObjectPool<List<DtCrowdAgent>> _listPool;
public DtProximityGrid(float cellSize) public DtProximityGrid(float cellSize)
{ {
_cellSize = cellSize; _cellSize = cellSize;
_invCellSize = 1.0f / cellSize; _invCellSize = 1.0f / cellSize;
_items = new Dictionary<long, List<DtCrowdAgent>>(); _items = new Dictionary<long, List<DtCrowdAgent>>();
_listPool = new RcObjectPool<List<DtCrowdAgent>>(() => new List<DtCrowdAgent>());
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -57,6 +60,8 @@ namespace DotRecast.Detour.Crowd
public void Clear() public void Clear()
{ {
foreach (var pair in _items)
_listPool.Return(pair.Value);
_items.Clear(); _items.Clear();
} }
@ -74,7 +79,7 @@ namespace DotRecast.Detour.Crowd
long key = CombineKey(x, y); long key = CombineKey(x, y);
if (!_items.TryGetValue(key, out var ids)) if (!_items.TryGetValue(key, out var ids))
{ {
ids = new List<DtCrowdAgent>(); ids = _listPool.Get();
_items.Add(key, ids); _items.Add(key, ids);
} }

View File

@ -1842,6 +1842,7 @@ namespace DotRecast.Detour
return DtStatus.DT_SUCCESS | (straightPathCount >= maxStraightPath ? DtStatus.DT_BUFFER_TOO_SMALL : DtStatus.DT_STATUS_NOTHING); return DtStatus.DT_SUCCESS | (straightPathCount >= maxStraightPath ? DtStatus.DT_BUFFER_TOO_SMALL : DtStatus.DT_STATUS_NOTHING);
} }
private readonly Queue<DtNode> MoveAlongSurface_queue = new Queue<DtNode>();
/// @par /// @par
/// ///
/// This method is optimized for small delta movement and a small number of /// This method is optimized for small delta movement and a small number of
@ -1897,8 +1898,8 @@ namespace DotRecast.Detour
startNode.total = 0; startNode.total = 0;
startNode.id = startRef; startNode.id = startRef;
startNode.flags = DtNodeFlags.DT_NODE_CLOSED; startNode.flags = DtNodeFlags.DT_NODE_CLOSED;
LinkedList<DtNode> stack = new LinkedList<DtNode>(); MoveAlongSurface_queue.Clear();
stack.AddLast(startNode); MoveAlongSurface_queue.Enqueue(startNode);
RcVec3f bestPos = new RcVec3f(); RcVec3f bestPos = new RcVec3f();
float bestDist = float.MaxValue; float bestDist = float.MaxValue;
@ -1914,11 +1915,10 @@ namespace DotRecast.Detour
const int MAX_NEIS = 8; const int MAX_NEIS = 8;
Span<long> neis = stackalloc long[MAX_NEIS]; Span<long> neis = stackalloc long[MAX_NEIS];
while (0 < stack.Count) while (0 < MoveAlongSurface_queue.Count)
{ {
// Pop front. // Pop front.
DtNode curNode = stack.First?.Value; DtNode curNode = MoveAlongSurface_queue.Dequeue();
stack.RemoveFirst();
// Get poly and tile. // Get poly and tile.
// The API input has been checked already, skip checking internal data. // The API input has been checked already, skip checking internal data.
@ -2017,7 +2017,7 @@ namespace DotRecast.Detour
// Mark as the node as visited and push to queue. // Mark as the node as visited and push to queue.
neighbourNode.pidx = m_tinyNodePool.GetNodeIdx(curNode); neighbourNode.pidx = m_tinyNodePool.GetNodeIdx(curNode);
neighbourNode.flags |= DtNodeFlags.DT_NODE_CLOSED; neighbourNode.flags |= DtNodeFlags.DT_NODE_CLOSED;
stack.AddLast(neighbourNode); MoveAlongSurface_queue.Enqueue(neighbourNode);
} }
} }
} }
@ -2908,6 +2908,7 @@ namespace DotRecast.Detour
return DtStatus.DT_SUCCESS; return DtStatus.DT_SUCCESS;
} }
private readonly Queue<DtNode> FindLocalNeighbourhood_queue = new Queue<DtNode>();
/// @par /// @par
/// ///
/// This method is optimized for a small search radius and small number of result /// This method is optimized for a small search radius and small number of result
@ -2959,8 +2960,8 @@ namespace DotRecast.Detour
startNode.pidx = 0; startNode.pidx = 0;
startNode.id = startRef; startNode.id = startRef;
startNode.flags = DtNodeFlags.DT_NODE_CLOSED; startNode.flags = DtNodeFlags.DT_NODE_CLOSED;
LinkedList<DtNode> stack = new LinkedList<DtNode>(); FindLocalNeighbourhood_queue.Clear();
stack.AddLast(startNode); FindLocalNeighbourhood_queue.Enqueue(startNode);
resultRef.Add(startNode.id); resultRef.Add(startNode.id);
resultParent.Add(0L); resultParent.Add(0L);
@ -2970,11 +2971,11 @@ namespace DotRecast.Detour
Span<float> pa = stackalloc float[m_nav.GetMaxVertsPerPoly() * 3]; Span<float> pa = stackalloc float[m_nav.GetMaxVertsPerPoly() * 3];
Span<float> pb = stackalloc float[m_nav.GetMaxVertsPerPoly() * 3]; Span<float> pb = stackalloc float[m_nav.GetMaxVertsPerPoly() * 3];
while (0 < stack.Count) while (0 < FindLocalNeighbourhood_queue.Count)
{ {
// Pop front. // Pop front.
DtNode curNode = stack.First?.Value;
stack.RemoveFirst(); DtNode curNode = FindLocalNeighbourhood_queue.Dequeue();
// Get poly and tile. // Get poly and tile.
// The API input has been checked already, skip checking internal data. // The API input has been checked already, skip checking internal data.
@ -3087,7 +3088,7 @@ namespace DotRecast.Detour
resultRef.Add(neighbourRef); resultRef.Add(neighbourRef);
resultParent.Add(curRef); resultParent.Add(curRef);
stack.AddLast(neighbourNode); FindLocalNeighbourhood_queue.Enqueue(neighbourNode);
} }
} }