Changed memory handling to use stackalloc in DtNavMeshQuery.GetPolyWallSegments for reducing SOH

Refactored to use stack-allocated Span<DtSegInterval> instead of dynamically allocating List<DtSegInterval>. This reduces potential heap allocations and improves performance by efficiently managing memory within a fixed size context.
This commit is contained in:
ikpil 2024-07-14 23:51:04 +09:00
parent c562f8f6a1
commit 84419b1d52
2 changed files with 45 additions and 25 deletions

View File

@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Changed
- Changed data structure of 'neis' from List<byte> to byte[] for optimized memory usage and improved access speed in `DtLayerMonotoneRegion`
- Changed new RcVec3f[3] to stackalloc RcVec3f[3] in DtNavMesh.GetPolyHeight() to reduce heap allocation
- Changed memory handling to use stackalloc in DtNavMeshQuery.GetPolyWallSegments for reducing SOH
### Removed
- Nothing

View File

@ -3090,11 +3090,14 @@ namespace DotRecast.Detour
}
protected void InsertInterval(List<DtSegInterval> ints, int tmin, int tmax, long refs)
protected void InsertInterval(Span<DtSegInterval> ints, ref int nints, int maxInts, int tmin, int tmax, long refs)
{
if (nints + 1 > maxInts)
return;
// Find insertion point.
int idx = 0;
while (idx < ints.Count)
while (idx < nints)
{
if (tmax <= ints[idx].tmin)
{
@ -3104,8 +3107,15 @@ namespace DotRecast.Detour
idx++;
}
// Move current results.
if (0 != nints - idx)
{
RcSpans.Move(ints, idx, idx + 1, nints - idx);
}
// Store
ints.Insert(idx, new DtSegInterval(refs, tmin, tmax));
ints[idx] = new DtSegInterval(refs, tmin, tmax);
nints++;
}
/// @par
@ -3134,7 +3144,7 @@ namespace DotRecast.Detour
segmentVerts.Clear();
segmentRefs.Clear();
var status = m_nav.GetTileAndPolyByRef(refs, out var tile, out var poly);
DtStatus status = m_nav.GetTileAndPolyByRef(refs, out var tile, out var poly);
if (status.Failed())
{
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
@ -3145,11 +3155,17 @@ namespace DotRecast.Detour
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
}
List<DtSegInterval> ints = new List<DtSegInterval>(16);
int n = 0;
const int MAX_INTERVAL = 16;
Span<DtSegInterval> ints = stackalloc DtSegInterval[MAX_INTERVAL];
int nints;
status = DtStatus.DT_SUCCESS;
for (int i = 0, j = poly.vertCount - 1; i < poly.vertCount; j = i++)
{
// Skip non-solid edges.
ints.Clear();
nints = 0;
if ((poly.neis[j] & DT_EXT_LINK) != 0)
{
// Tile border.
@ -3163,7 +3179,7 @@ namespace DotRecast.Detour
m_nav.GetTileAndPolyByRefUnsafe(link.refs, out var neiTile, out var neiPoly);
if (filter.PassFilter(link.refs, neiTile, neiPoly))
{
InsertInterval(ints, link.bmin, link.bmax, link.refs);
InsertInterval(ints, ref nints, MAX_INTERVAL, link.bmin, link.bmax, link.refs);
}
}
}
@ -3198,17 +3214,18 @@ namespace DotRecast.Detour
// RcArrays.Copy(tile.data.verts, ivi, seg, 3, 3);
segmentVerts.Add(seg);
segmentRefs.Add(neiRef);
n++;
continue;
}
// Add sentinels
InsertInterval(ints, -1, 0, 0);
InsertInterval(ints, 255, 256, 0);
InsertInterval(ints, ref nints, MAX_INTERVAL, -1, 0, 0);
InsertInterval(ints, ref nints, MAX_INTERVAL, 255, 256, 0);
// Store segments.
int vj = poly.verts[j] * 3;
int vi = poly.verts[i] * 3;
for (int k = 1; k < ints.Count; ++k)
for (int k = 1; k < nints; ++k)
{
// Portal segment.
if (storePortals && ints[k].refs != 0)
@ -3220,6 +3237,7 @@ namespace DotRecast.Detour
seg.vmax = RcVec.Lerp(tile.data.verts, vj, vi, tmax);
segmentVerts.Add(seg);
segmentRefs.Add(ints[k].refs);
n++;
}
// Wall segment.
@ -3234,11 +3252,12 @@ namespace DotRecast.Detour
seg.vmax = RcVec.Lerp(tile.data.verts, vj, vi, tmax);
segmentVerts.Add(seg);
segmentRefs.Add(0L);
n++;
}
}
}
return DtStatus.DT_SUCCESS;
return status;
}
/// @par