add scoped timer

This commit is contained in:
ikpil 2023-07-08 12:20:20 +09:00
parent deeee5e9d2
commit bc14092125
13 changed files with 205 additions and 110 deletions

View File

@ -0,0 +1,20 @@
using System;
namespace DotRecast.Core
{
public struct RcAnonymousDisposable : IDisposable
{
private Action _dispose;
public RcAnonymousDisposable(Action dispose)
{
_dispose = dispose;
}
public void Dispose()
{
_dispose?.Invoke();
_dispose = null;
}
}
}

View File

@ -35,16 +35,23 @@ namespace DotRecast.Core
_timerAccum = new ConcurrentDictionary<string, RcAtomicLong>(); _timerAccum = new ConcurrentDictionary<string, RcAtomicLong>();
} }
public void StartTimer(string name) public IDisposable ScopedTimer(RcTimerLabel label)
{ {
_timerStart.Value[name] = new RcAtomicLong(RcFrequency.Ticks); StartTimer(label);
return new RcAnonymousDisposable(() => StopTimer(label));
} }
public void StopTimer(string name) public void StartTimer(RcTimerLabel label)
{
_timerStart.Value[label.Name] = new RcAtomicLong(RcFrequency.Ticks);
}
public void StopTimer(RcTimerLabel label)
{ {
_timerAccum _timerAccum
.GetOrAdd(name, _ => new RcAtomicLong(0)) .GetOrAdd(label.Name, _ => new RcAtomicLong(0))
.AddAndGet(RcFrequency.Ticks - _timerStart.Value?[name].Read() ?? 0); .AddAndGet(RcFrequency.Ticks - _timerStart.Value?[label.Name].Read() ?? 0);
} }
public void Warn(string message) public void Warn(string message)

View File

@ -0,0 +1,109 @@
namespace DotRecast.Core
{
/// Recast performance timer categories.
/// @see rcContext
public class RcTimerLabel
{
/// The user defined total time of the build.
public static readonly RcTimerLabel RC_TIMER_TOTAL = new RcTimerLabel(nameof(RC_TIMER_TOTAL));
/// A user defined build time.
public static readonly RcTimerLabel RC_TIMER_TEMP = new RcTimerLabel(nameof(RC_TIMER_TEMP));
/// The time to rasterize the triangles. (See: #rcRasterizeTriangle)
public static readonly RcTimerLabel RC_TIMER_RASTERIZE_TRIANGLES = new RcTimerLabel(nameof(RC_TIMER_RASTERIZE_TRIANGLES));
public static readonly RcTimerLabel RC_TIMER_RASTERIZE_SPHERE = new RcTimerLabel(nameof(RC_TIMER_RASTERIZE_SPHERE));
public static readonly RcTimerLabel RC_TIMER_RASTERIZE_CAPSULE = new RcTimerLabel(nameof(RC_TIMER_RASTERIZE_CAPSULE));
public static readonly RcTimerLabel RC_TIMER_RASTERIZE_CYLINDER = new RcTimerLabel(nameof(RC_TIMER_RASTERIZE_CYLINDER));
public static readonly RcTimerLabel RC_TIMER_RASTERIZE_BOX = new RcTimerLabel(nameof(RC_TIMER_RASTERIZE_BOX));
public static readonly RcTimerLabel RC_TIMER_RASTERIZE_CONVEX = new RcTimerLabel(nameof(RC_TIMER_RASTERIZE_CONVEX));
/// The time to build the compact heightfield. (See: #rcBuildCompactHeightfield)
public static readonly RcTimerLabel RC_TIMER_BUILD_COMPACTHEIGHTFIELD = new RcTimerLabel(nameof(RC_TIMER_BUILD_COMPACTHEIGHTFIELD));
/// The total time to build the contours. (See: #rcBuildContours)
public static readonly RcTimerLabel RC_TIMER_BUILD_CONTOURS = new RcTimerLabel(nameof(RC_TIMER_BUILD_CONTOURS));
/// The time to trace the boundaries of the contours. (See: #rcBuildContours)
public static readonly RcTimerLabel RC_TIMER_BUILD_CONTOURS_TRACE = new RcTimerLabel(nameof(RC_TIMER_BUILD_CONTOURS_TRACE));
public static readonly RcTimerLabel RC_TIMER_BUILD_CONTOURS_WALK = new RcTimerLabel(nameof(RC_TIMER_BUILD_CONTOURS_WALK));
/// The time to simplify the contours. (See: #rcBuildContours)
public static readonly RcTimerLabel RC_TIMER_BUILD_CONTOURS_SIMPLIFY = new RcTimerLabel(nameof(RC_TIMER_BUILD_CONTOURS_SIMPLIFY));
/// The time to filter ledge spans. (See: #rcFilterLedgeSpans)
public static readonly RcTimerLabel RC_TIMER_FILTER_BORDER = new RcTimerLabel(nameof(RC_TIMER_FILTER_BORDER));
/// The time to filter low height spans. (See: #rcFilterWalkableLowHeightSpans)
public static readonly RcTimerLabel RC_TIMER_FILTER_WALKABLE = new RcTimerLabel(nameof(RC_TIMER_FILTER_WALKABLE));
/// The time to apply the median filter. (See: #rcMedianFilterWalkableArea)
public static readonly RcTimerLabel RC_TIMER_MEDIAN_AREA = new RcTimerLabel(nameof(RC_TIMER_MEDIAN_AREA));
/// The time to filter low obstacles. (See: #rcFilterLowHangingWalkableObstacles)
public static readonly RcTimerLabel RC_TIMER_FILTER_LOW_OBSTACLES = new RcTimerLabel(nameof(RC_TIMER_FILTER_LOW_OBSTACLES));
/// The time to build the polygon mesh. (See: #rcBuildPolyMesh)
public static readonly RcTimerLabel RC_TIMER_BUILD_POLYMESH = new RcTimerLabel(nameof(RC_TIMER_BUILD_POLYMESH));
/// The time to merge polygon meshes. (See: #rcMergePolyMeshes)
public static readonly RcTimerLabel RC_TIMER_MERGE_POLYMESH = new RcTimerLabel(nameof(RC_TIMER_MERGE_POLYMESH));
/// The time to erode the walkable area. (See: #rcErodeWalkableArea)
public static readonly RcTimerLabel RC_TIMER_ERODE_AREA = new RcTimerLabel(nameof(RC_TIMER_ERODE_AREA));
/// The time to mark a box area. (See: #rcMarkBoxArea)
public static readonly RcTimerLabel RC_TIMER_MARK_BOX_AREA = new RcTimerLabel(nameof(RC_TIMER_MARK_BOX_AREA));
/// The time to mark a cylinder area. (See: #rcMarkCylinderArea)
public static readonly RcTimerLabel RC_TIMER_MARK_CYLINDER_AREA = new RcTimerLabel(nameof(RC_TIMER_MARK_CYLINDER_AREA));
/// The time to mark a convex polygon area. (See: #rcMarkConvexPolyArea)
public static readonly RcTimerLabel RC_TIMER_MARK_CONVEXPOLY_AREA = new RcTimerLabel(nameof(RC_TIMER_MARK_CONVEXPOLY_AREA));
/// The total time to build the distance field. (See: #rcBuildDistanceField)
public static readonly RcTimerLabel RC_TIMER_BUILD_DISTANCEFIELD = new RcTimerLabel(nameof(RC_TIMER_BUILD_DISTANCEFIELD));
/// The time to build the distances of the distance field. (See: #rcBuildDistanceField)
public static readonly RcTimerLabel RC_TIMER_BUILD_DISTANCEFIELD_DIST = new RcTimerLabel(nameof(RC_TIMER_BUILD_DISTANCEFIELD_DIST));
/// The time to blur the distance field. (See: #rcBuildDistanceField)
public static readonly RcTimerLabel RC_TIMER_BUILD_DISTANCEFIELD_BLUR = new RcTimerLabel(nameof(RC_TIMER_BUILD_DISTANCEFIELD_BLUR));
/// The total time to build the regions. (See: #rcBuildRegions, #rcBuildRegionsMonotone)
public static readonly RcTimerLabel RC_TIMER_BUILD_REGIONS = new RcTimerLabel(nameof(RC_TIMER_BUILD_REGIONS));
/// The total time to apply the watershed algorithm. (See: #rcBuildRegions)
public static readonly RcTimerLabel RC_TIMER_BUILD_REGIONS_WATERSHED = new RcTimerLabel(nameof(RC_TIMER_BUILD_REGIONS_WATERSHED));
/// The time to expand regions while applying the watershed algorithm. (See: #rcBuildRegions)
public static readonly RcTimerLabel RC_TIMER_BUILD_REGIONS_EXPAND = new RcTimerLabel(nameof(RC_TIMER_BUILD_REGIONS_EXPAND));
/// The time to flood regions while applying the watershed algorithm. (See: #rcBuildRegions)
public static readonly RcTimerLabel RC_TIMER_BUILD_REGIONS_FLOOD = new RcTimerLabel(nameof(RC_TIMER_BUILD_REGIONS_FLOOD));
/// The time to filter out small regions. (See: #rcBuildRegions, #rcBuildRegionsMonotone)
public static readonly RcTimerLabel RC_TIMER_BUILD_REGIONS_FILTER = new RcTimerLabel(nameof(RC_TIMER_BUILD_REGIONS_FILTER));
/// The time to build heightfield layers. (See: #rcBuildHeightfieldLayers)
public static readonly RcTimerLabel RC_TIMER_BUILD_LAYERS = new RcTimerLabel(nameof(RC_TIMER_BUILD_LAYERS));
/// The time to build the polygon mesh detail. (See: #rcBuildPolyMeshDetail)
public static readonly RcTimerLabel RC_TIMER_BUILD_POLYMESHDETAIL = new RcTimerLabel(nameof(RC_TIMER_BUILD_POLYMESHDETAIL));
/// The time to merge polygon mesh details. (See: #rcMergePolyMeshDetails)
public static readonly RcTimerLabel RC_TIMER_MERGE_POLYMESHDETAIL = new RcTimerLabel(nameof(RC_TIMER_MERGE_POLYMESHDETAIL));
/// The maximum number of timers. (Used for iterating timers.)
public static readonly RcTimerLabel RC_MAX_TIMERS = new RcTimerLabel(nameof(RC_MAX_TIMERS));
public readonly string Name;
private RcTimerLabel(string name)
{
Name = name;
}
};
}

View File

@ -39,7 +39,7 @@ namespace DotRecast.Recast
{ {
int w = chf.width; int w = chf.width;
int h = chf.height; int h = chf.height;
ctx.StartTimer("ERODE_AREA"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_ERODE_AREA);
int[] dist = new int[chf.spanCount]; int[] dist = new int[chf.spanCount];
Array.Fill(dist, 255); Array.Fill(dist, 255);
@ -205,8 +205,6 @@ namespace DotRecast.Recast
for (int i = 0; i < chf.spanCount; ++i) for (int i = 0; i < chf.spanCount; ++i)
if (dist[i] < thr) if (dist[i] < thr)
chf.areas[i] = RC_NULL_AREA; chf.areas[i] = RC_NULL_AREA;
ctx.StopTimer("ERODE_AREA");
} }
/// @par /// @par
@ -220,7 +218,7 @@ namespace DotRecast.Recast
int w = chf.width; int w = chf.width;
int h = chf.height; int h = chf.height;
ctx.StartTimer("MEDIAN_AREA"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_MEDIAN_AREA);
int[] areas = new int[chf.spanCount]; int[] areas = new int[chf.spanCount];
@ -273,8 +271,6 @@ namespace DotRecast.Recast
chf.areas = areas; chf.areas = areas;
ctx.StopTimer("MEDIAN_AREA");
return true; return true;
} }
@ -285,7 +281,7 @@ namespace DotRecast.Recast
/// @see rcCompactHeightfield, rcMedianFilterWalkableArea /// @see rcCompactHeightfield, rcMedianFilterWalkableArea
public static void MarkBoxArea(RcTelemetry ctx, float[] bmin, float[] bmax, AreaModification areaMod, RcCompactHeightfield chf) public static void MarkBoxArea(RcTelemetry ctx, float[] bmin, float[] bmax, AreaModification areaMod, RcCompactHeightfield chf)
{ {
ctx.StartTimer("MARK_BOX_AREA"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_MARK_BOX_AREA);
int minx = (int)((bmin[0] - chf.bmin.x) / chf.cs); int minx = (int)((bmin[0] - chf.bmin.x) / chf.cs);
int miny = (int)((bmin[1] - chf.bmin.y) / chf.ch); int miny = (int)((bmin[1] - chf.bmin.y) / chf.ch);
@ -328,8 +324,6 @@ namespace DotRecast.Recast
} }
} }
} }
ctx.StopTimer("MARK_BOX_AREA");
} }
static bool PointInPoly(float[] verts, RcVec3f p) static bool PointInPoly(float[] verts, RcVec3f p)
@ -360,7 +354,7 @@ namespace DotRecast.Recast
public static void MarkConvexPolyArea(RcTelemetry ctx, float[] verts, float hmin, float hmax, AreaModification areaMod, public static void MarkConvexPolyArea(RcTelemetry ctx, float[] verts, float hmin, float hmax, AreaModification areaMod,
RcCompactHeightfield chf) RcCompactHeightfield chf)
{ {
ctx.StartTimer("MARK_CONVEXPOLY_AREA"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_MARK_CONVEXPOLY_AREA);
RcVec3f bmin = new RcVec3f(); RcVec3f bmin = new RcVec3f();
RcVec3f bmax = new RcVec3f(); RcVec3f bmax = new RcVec3f();
@ -426,8 +420,6 @@ namespace DotRecast.Recast
} }
} }
} }
ctx.StopTimer("MARK_CONVEXPOLY_AREA");
} }
/// @par /// @par
@ -437,7 +429,7 @@ namespace DotRecast.Recast
/// @see rcCompactHeightfield, rcMedianFilterWalkableArea /// @see rcCompactHeightfield, rcMedianFilterWalkableArea
public static void MarkCylinderArea(RcTelemetry ctx, float[] pos, float r, float h, AreaModification areaMod, RcCompactHeightfield chf) public static void MarkCylinderArea(RcTelemetry ctx, float[] pos, float r, float h, AreaModification areaMod, RcCompactHeightfield chf)
{ {
ctx.StartTimer("MARK_CYLINDER_AREA"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_MARK_CYLINDER_AREA);
RcVec3f bmin = new RcVec3f(); RcVec3f bmin = new RcVec3f();
RcVec3f bmax = new RcVec3f(); RcVec3f bmax = new RcVec3f();
@ -501,8 +493,6 @@ namespace DotRecast.Recast
} }
} }
} }
ctx.StopTimer("MARK_CYLINDER_AREA");
} }
} }
} }

View File

@ -41,7 +41,7 @@ namespace DotRecast.Recast
public static RcCompactHeightfield BuildCompactHeightfield(RcTelemetry ctx, int walkableHeight, int walkableClimb, public static RcCompactHeightfield BuildCompactHeightfield(RcTelemetry ctx, int walkableHeight, int walkableClimb,
RcHeightfield hf) RcHeightfield hf)
{ {
ctx.StartTimer("BUILD_COMPACTHEIGHTFIELD"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
RcCompactHeightfield chf = new RcCompactHeightfield(); RcCompactHeightfield chf = new RcCompactHeightfield();
int w = hf.width; int w = hf.width;
@ -161,7 +161,6 @@ namespace DotRecast.Recast
+ " (max: " + MAX_LAYERS + ")"); + " (max: " + MAX_LAYERS + ")");
} }
ctx.StopTimer("BUILD_COMPACTHEIGHTFIELD");
return chf; return chf;
} }

View File

@ -722,7 +722,8 @@ namespace DotRecast.Recast
int borderSize = chf.borderSize; int borderSize = chf.borderSize;
RcContourSet cset = new RcContourSet(); RcContourSet cset = new RcContourSet();
ctx.StartTimer("CONTOURS"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_CONTOURS);
cset.bmin = chf.bmin; cset.bmin = chf.bmin;
cset.bmax = chf.bmax; cset.bmax = chf.bmax;
if (borderSize > 0) if (borderSize > 0)
@ -744,7 +745,7 @@ namespace DotRecast.Recast
int[] flags = new int[chf.spanCount]; int[] flags = new int[chf.spanCount];
ctx.StartTimer("CONTOURS_TRACE"); ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_CONTOURS_TRACE);
// Mark boundaries. // Mark boundaries.
for (int y = 0; y < h; ++y) for (int y = 0; y < h; ++y)
@ -782,7 +783,7 @@ namespace DotRecast.Recast
} }
} }
ctx.StopTimer("CONTOURS_TRACE"); ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_CONTOURS_TRACE);
List<int> verts = new List<int>(256); List<int> verts = new List<int>(256);
List<int> simplified = new List<int>(64); List<int> simplified = new List<int>(64);
@ -808,14 +809,14 @@ namespace DotRecast.Recast
verts.Clear(); verts.Clear();
simplified.Clear(); simplified.Clear();
ctx.StartTimer("CONTOURS_WALK"); ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_CONTOURS_WALK);
WalkContour(x, y, i, chf, flags, verts); WalkContour(x, y, i, chf, flags, verts);
ctx.StopTimer("CONTOURS_WALK"); ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_CONTOURS_WALK);
ctx.StartTimer("CONTOURS_SIMPLIFY"); ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_CONTOURS_SIMPLIFY);
SimplifyContour(verts, simplified, maxError, maxEdgeLen, buildFlags); SimplifyContour(verts, simplified, maxError, maxEdgeLen, buildFlags);
RemoveDegenerateSegments(simplified); RemoveDegenerateSegments(simplified);
ctx.StopTimer("CONTOURS_SIMPLIFY"); ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_CONTOURS_SIMPLIFY);
// Store region->contour remap info. // Store region->contour remap info.
// Create contour. // Create contour.
@ -956,7 +957,6 @@ namespace DotRecast.Recast
} }
} }
ctx.StopTimer("CONTOURS");
return cset; return cset;
} }
} }

View File

@ -31,7 +31,7 @@ namespace DotRecast.Recast
public static void RasterizeSphere(RcHeightfield hf, RcVec3f center, float radius, int area, int flagMergeThr, RcTelemetry ctx) public static void RasterizeSphere(RcHeightfield hf, RcVec3f center, float radius, int area, int flagMergeThr, RcTelemetry ctx)
{ {
ctx.StartTimer("RASTERIZE_SPHERE"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_SPHERE);
float[] bounds = float[] bounds =
{ {
center.x - radius, center.y - radius, center.z - radius, center.x + radius, center.y + radius, center.x - radius, center.y - radius, center.z - radius, center.x + radius, center.y + radius,
@ -39,13 +39,12 @@ namespace DotRecast.Recast
}; };
RasterizationFilledShape(hf, bounds, area, flagMergeThr, RasterizationFilledShape(hf, bounds, area, flagMergeThr,
rectangle => IntersectSphere(rectangle, center, radius * radius)); rectangle => IntersectSphere(rectangle, center, radius * radius));
ctx.StopTimer("RASTERIZE_SPHERE");
} }
public static void RasterizeCapsule(RcHeightfield hf, RcVec3f start, RcVec3f end, float radius, int area, int flagMergeThr, public static void RasterizeCapsule(RcHeightfield hf, RcVec3f start, RcVec3f end, float radius, int area, int flagMergeThr,
RcTelemetry ctx) RcTelemetry ctx)
{ {
ctx.StartTimer("RASTERIZE_CAPSULE"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_CAPSULE);
float[] bounds = float[] bounds =
{ {
Math.Min(start.x, end.x) - radius, Math.Min(start.y, end.y) - radius, Math.Min(start.x, end.x) - radius, Math.Min(start.y, end.y) - radius,
@ -55,13 +54,12 @@ namespace DotRecast.Recast
RcVec3f axis = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z); RcVec3f axis = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
RasterizationFilledShape(hf, bounds, area, flagMergeThr, RasterizationFilledShape(hf, bounds, area, flagMergeThr,
rectangle => IntersectCapsule(rectangle, start, end, axis, radius * radius)); rectangle => IntersectCapsule(rectangle, start, end, axis, radius * radius));
ctx.StopTimer("RASTERIZE_CAPSULE");
} }
public static void RasterizeCylinder(RcHeightfield hf, RcVec3f start, RcVec3f end, float radius, int area, int flagMergeThr, public static void RasterizeCylinder(RcHeightfield hf, RcVec3f start, RcVec3f end, float radius, int area, int flagMergeThr,
RcTelemetry ctx) RcTelemetry ctx)
{ {
ctx.StartTimer("RASTERIZE_CYLINDER"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_CYLINDER);
float[] bounds = float[] bounds =
{ {
Math.Min(start.x, end.x) - radius, Math.Min(start.y, end.y) - radius, Math.Min(start.x, end.x) - radius, Math.Min(start.y, end.y) - radius,
@ -71,13 +69,12 @@ namespace DotRecast.Recast
RcVec3f axis = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z); RcVec3f axis = RcVec3f.Of(end.x - start.x, end.y - start.y, end.z - start.z);
RasterizationFilledShape(hf, bounds, area, flagMergeThr, RasterizationFilledShape(hf, bounds, area, flagMergeThr,
rectangle => IntersectCylinder(rectangle, start, end, axis, radius * radius)); rectangle => IntersectCylinder(rectangle, start, end, axis, radius * radius));
ctx.StopTimer("RASTERIZE_CYLINDER");
} }
public static void RasterizeBox(RcHeightfield hf, RcVec3f center, RcVec3f[] halfEdges, int area, int flagMergeThr, public static void RasterizeBox(RcHeightfield hf, RcVec3f center, RcVec3f[] halfEdges, int area, int flagMergeThr,
RcTelemetry ctx) RcTelemetry ctx)
{ {
ctx.StartTimer("RASTERIZE_BOX"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_BOX);
RcVec3f[] normals = RcVec3f[] normals =
{ {
RcVec3f.Of(halfEdges[0].x, halfEdges[0].y, halfEdges[0].z), RcVec3f.Of(halfEdges[0].x, halfEdges[0].y, halfEdges[0].z),
@ -123,13 +120,12 @@ namespace DotRecast.Recast
} }
RasterizationFilledShape(hf, bounds, area, flagMergeThr, rectangle => IntersectBox(rectangle, vertices, planes)); RasterizationFilledShape(hf, bounds, area, flagMergeThr, rectangle => IntersectBox(rectangle, vertices, planes));
ctx.StopTimer("RASTERIZE_BOX");
} }
public static void RasterizeConvex(RcHeightfield hf, float[] vertices, int[] triangles, int area, int flagMergeThr, public static void RasterizeConvex(RcHeightfield hf, float[] vertices, int[] triangles, int area, int flagMergeThr,
RcTelemetry ctx) RcTelemetry ctx)
{ {
ctx.StartTimer("RASTERIZE_CONVEX"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_CONVEX);
float[] bounds = new float[] { vertices[0], vertices[1], vertices[2], vertices[0], vertices[1], vertices[2] }; float[] bounds = new float[] { vertices[0], vertices[1], vertices[2], vertices[0], vertices[1], vertices[2] };
for (int i = 0; i < vertices.Length; i += 3) for (int i = 0; i < vertices.Length; i += 3)
{ {
@ -179,7 +175,6 @@ namespace DotRecast.Recast
RasterizationFilledShape(hf, bounds, area, flagMergeThr, RasterizationFilledShape(hf, bounds, area, flagMergeThr,
rectangle => IntersectConvex(rectangle, triangles, vertices, planes, triBounds)); rectangle => IntersectConvex(rectangle, triangles, vertices, planes, triBounds));
ctx.StopTimer("RASTERIZE_CONVEX");
} }
private static void Plane(float[][] planes, int p, float[] v1, float[] v2, float[] vertices, int vert) private static void Plane(float[][] planes, int p, float[] v1, float[] v2, float[] vertices, int vert)

View File

@ -40,7 +40,7 @@ namespace DotRecast.Recast
/// @see rcHeightfield, rcConfig /// @see rcHeightfield, rcConfig
public static void FilterLowHangingWalkableObstacles(RcTelemetry ctx, int walkableClimb, RcHeightfield solid) public static void FilterLowHangingWalkableObstacles(RcTelemetry ctx, int walkableClimb, RcHeightfield solid)
{ {
ctx.StartTimer("FILTER_LOW_OBSTACLES"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_FILTER_LOW_OBSTACLES);
int w = solid.width; int w = solid.width;
int h = solid.height; int h = solid.height;
@ -71,8 +71,6 @@ namespace DotRecast.Recast
} }
} }
} }
ctx.StopTimer("FILTER_LOW_OBSTACLES");
} }
/// @par /// @par
@ -87,7 +85,7 @@ namespace DotRecast.Recast
/// @see rcHeightfield, rcConfig /// @see rcHeightfield, rcConfig
public static void FilterLedgeSpans(RcTelemetry ctx, int walkableHeight, int walkableClimb, RcHeightfield solid) public static void FilterLedgeSpans(RcTelemetry ctx, int walkableHeight, int walkableClimb, RcHeightfield solid)
{ {
ctx.StartTimer("FILTER_LEDGE"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_FILTER_BORDER);
int w = solid.width; int w = solid.width;
int h = solid.height; int h = solid.height;
@ -168,8 +166,6 @@ namespace DotRecast.Recast
} }
} }
} }
ctx.StopTimer("FILTER_LEDGE");
} }
/// @par /// @par
@ -180,7 +176,7 @@ namespace DotRecast.Recast
/// @see rcHeightfield, rcConfig /// @see rcHeightfield, rcConfig
public static void FilterWalkableLowHeightSpans(RcTelemetry ctx, int walkableHeight, RcHeightfield solid) public static void FilterWalkableLowHeightSpans(RcTelemetry ctx, int walkableHeight, RcHeightfield solid)
{ {
ctx.StartTimer("FILTER_WALKABLE"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_FILTER_WALKABLE);
int w = solid.width; int w = solid.width;
int h = solid.height; int h = solid.height;
@ -200,8 +196,6 @@ namespace DotRecast.Recast
} }
} }
} }
ctx.StopTimer("FILTER_WALKABLE");
} }
} }
} }

View File

@ -53,7 +53,8 @@ namespace DotRecast.Recast
public static RcHeightfieldLayerSet BuildHeightfieldLayers(RcTelemetry ctx, RcCompactHeightfield chf, int walkableHeight) public static RcHeightfieldLayerSet BuildHeightfieldLayers(RcTelemetry ctx, RcCompactHeightfield chf, int walkableHeight)
{ {
ctx.StartTimer("RC_TIMER_BUILD_LAYERS"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_LAYERS);
int w = chf.width; int w = chf.width;
int h = chf.height; int h = chf.height;
int borderSize = chf.borderSize; int borderSize = chf.borderSize;
@ -397,7 +398,7 @@ namespace DotRecast.Recast
// No layers, return empty. // No layers, return empty.
if (layerId == 0) if (layerId == 0)
{ {
// ctx.StopTimer(RC_TIMER_BUILD_LAYERS); // ctx.Stop(RC_TIMER_BUILD_LAYERS);
return null; return null;
} }

View File

@ -966,7 +966,8 @@ namespace DotRecast.Recast
/// @see rcAllocPolyMesh, rcContourSet, rcPolyMesh, rcConfig /// @see rcAllocPolyMesh, rcContourSet, rcPolyMesh, rcConfig
public static RcPolyMesh BuildPolyMesh(RcTelemetry ctx, RcContourSet cset, int nvp) public static RcPolyMesh BuildPolyMesh(RcTelemetry ctx, RcContourSet cset, int nvp)
{ {
ctx.StartTimer("POLYMESH"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_POLYMESH);
RcPolyMesh mesh = new RcPolyMesh(); RcPolyMesh mesh = new RcPolyMesh();
mesh.bmin = cset.bmin; mesh.bmin = cset.bmin;
mesh.bmax = cset.bmax; mesh.bmax = cset.bmax;
@ -1204,7 +1205,6 @@ namespace DotRecast.Recast
+ " (max " + MAX_MESH_VERTS_POLY + "). Data can be corrupted."); + " (max " + MAX_MESH_VERTS_POLY + "). Data can be corrupted.");
} }
ctx.StopTimer("POLYMESH");
return mesh; return mesh;
} }
@ -1214,7 +1214,8 @@ namespace DotRecast.Recast
if (nmeshes == 0 || meshes == null) if (nmeshes == 0 || meshes == null)
return null; return null;
ctx.StartTimer("MERGE_POLYMESH"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_MERGE_POLYMESH);
RcPolyMesh mesh = new RcPolyMesh(); RcPolyMesh mesh = new RcPolyMesh();
mesh.nvp = meshes[0].nvp; mesh.nvp = meshes[0].nvp;
mesh.cs = meshes[0].cs; mesh.cs = meshes[0].cs;
@ -1333,8 +1334,6 @@ namespace DotRecast.Recast
+ " (max " + MAX_MESH_VERTS_POLY + "). Data can be corrupted."); + " (max " + MAX_MESH_VERTS_POLY + "). Data can be corrupted.");
} }
ctx.StopTimer("MERGE_POLYMESH");
return mesh; return mesh;
} }

View File

@ -1426,7 +1426,7 @@ namespace DotRecast.Recast
public static RcPolyMeshDetail BuildPolyMeshDetail(RcTelemetry ctx, RcPolyMesh mesh, RcCompactHeightfield chf, public static RcPolyMeshDetail BuildPolyMeshDetail(RcTelemetry ctx, RcPolyMesh mesh, RcCompactHeightfield chf,
float sampleDist, float sampleMaxError) float sampleDist, float sampleMaxError)
{ {
ctx.StartTimer("POLYMESHDETAIL"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_POLYMESHDETAIL);
if (mesh.nverts == 0 || mesh.npolys == 0) if (mesh.nverts == 0 || mesh.npolys == 0)
{ {
return null; return null;
@ -1610,16 +1610,15 @@ namespace DotRecast.Recast
} }
} }
ctx.StopTimer("POLYMESHDETAIL");
return dmesh; return dmesh;
} }
/// @see rcAllocPolyMeshDetail, rcPolyMeshDetail /// @see rcAllocPolyMeshDetail, rcPolyMeshDetail
private static RcPolyMeshDetail MergePolyMeshDetails(RcTelemetry ctx, RcPolyMeshDetail[] meshes, int nmeshes) private static RcPolyMeshDetail MergePolyMeshDetails(RcTelemetry ctx, RcPolyMeshDetail[] meshes, int nmeshes)
{ {
RcPolyMeshDetail mesh = new RcPolyMeshDetail(); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_MERGE_POLYMESHDETAIL);
ctx.StartTimer("MERGE_POLYMESHDETAIL"); RcPolyMeshDetail mesh = new RcPolyMeshDetail();
int maxVerts = 0; int maxVerts = 0;
int maxTris = 0; int maxTris = 0;
@ -1680,7 +1679,6 @@ namespace DotRecast.Recast
} }
} }
ctx.StopTimer("MERGE_POLYMESHDETAIL");
return mesh; return mesh;
} }
} }

View File

@ -400,14 +400,12 @@ namespace DotRecast.Recast
public static void RasterizeTriangle(RcHeightfield heightfield, float[] verts, int v0, int v1, int v2, int area, public static void RasterizeTriangle(RcHeightfield heightfield, float[] verts, int v0, int v1, int v2, int area,
int flagMergeThreshold, RcTelemetry ctx) int flagMergeThreshold, RcTelemetry ctx)
{ {
ctx.StartTimer("RASTERIZE_TRIANGLES"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
float inverseCellSize = 1.0f / heightfield.cs; float inverseCellSize = 1.0f / heightfield.cs;
float inverseCellHeight = 1.0f / heightfield.ch; float inverseCellHeight = 1.0f / heightfield.ch;
RasterizeTri(verts, v0, v1, v2, area, heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, inverseCellSize, RasterizeTri(verts, v0, v1, v2, area, heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, inverseCellSize,
inverseCellHeight, flagMergeThreshold); inverseCellHeight, flagMergeThreshold);
ctx.StopTimer("RASTERIZE_TRIANGLES");
} }
/** /**
@ -431,7 +429,7 @@ namespace DotRecast.Recast
public static void RasterizeTriangles(RcHeightfield heightfield, float[] verts, int[] tris, int[] areaIds, int numTris, public static void RasterizeTriangles(RcHeightfield heightfield, float[] verts, int[] tris, int[] areaIds, int numTris,
int flagMergeThreshold, RcTelemetry ctx) int flagMergeThreshold, RcTelemetry ctx)
{ {
ctx.StartTimer("RASTERIZE_TRIANGLES"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
float inverseCellSize = 1.0f / heightfield.cs; float inverseCellSize = 1.0f / heightfield.cs;
float inverseCellHeight = 1.0f / heightfield.ch; float inverseCellHeight = 1.0f / heightfield.ch;
@ -443,8 +441,6 @@ namespace DotRecast.Recast
RasterizeTri(verts, v0, v1, v2, areaIds[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, RasterizeTri(verts, v0, v1, v2, areaIds[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs,
inverseCellSize, inverseCellHeight, flagMergeThreshold); inverseCellSize, inverseCellHeight, flagMergeThreshold);
} }
ctx.StopTimer("RASTERIZE_TRIANGLES");
} }
/** /**
@ -468,7 +464,7 @@ namespace DotRecast.Recast
public static void RasterizeTriangles(RcHeightfield heightfield, float[] verts, int[] areaIds, int numTris, public static void RasterizeTriangles(RcHeightfield heightfield, float[] verts, int[] areaIds, int numTris,
int flagMergeThreshold, RcTelemetry ctx) int flagMergeThreshold, RcTelemetry ctx)
{ {
ctx.StartTimer("RASTERIZE_TRIANGLES"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
float inverseCellSize = 1.0f / heightfield.cs; float inverseCellSize = 1.0f / heightfield.cs;
float inverseCellHeight = 1.0f / heightfield.ch; float inverseCellHeight = 1.0f / heightfield.ch;
@ -480,8 +476,6 @@ namespace DotRecast.Recast
RasterizeTri(verts, v0, v1, v2, areaIds[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, RasterizeTri(verts, v0, v1, v2, areaIds[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs,
inverseCellSize, inverseCellHeight, flagMergeThreshold); inverseCellSize, inverseCellHeight, flagMergeThreshold);
} }
ctx.StopTimer("RASTERIZE_TRIANGLES");
} }
} }
} }

View File

@ -580,7 +580,6 @@ namespace DotRecast.Recast
} }
private static void RemoveAdjacentNeighbours(RcRegion reg) private static void RemoveAdjacentNeighbours(RcRegion reg)
{ {
// Remove adjacent duplicates. // Remove adjacent duplicates.
@ -1418,16 +1417,16 @@ namespace DotRecast.Recast
/// @see rcCompactHeightfield, rcBuildRegions, rcBuildRegionsMonotone /// @see rcCompactHeightfield, rcBuildRegions, rcBuildRegionsMonotone
public static void BuildDistanceField(RcTelemetry ctx, RcCompactHeightfield chf) public static void BuildDistanceField(RcTelemetry ctx, RcCompactHeightfield chf)
{ {
ctx.StartTimer("DISTANCEFIELD"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_DISTANCEFIELD);
int[] src = new int[chf.spanCount];
ctx.StartTimer("DISTANCEFIELD_DIST");
int[] src = new int[chf.spanCount];
ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_DISTANCEFIELD_DIST);
int maxDist = CalculateDistanceField(chf, src); int maxDist = CalculateDistanceField(chf, src);
chf.maxDistance = maxDist; chf.maxDistance = maxDist;
ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_DISTANCEFIELD_DIST);
ctx.StopTimer("DISTANCEFIELD_DIST"); ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_DISTANCEFIELD_BLUR);
ctx.StartTimer("DISTANCEFIELD_BLUR");
// Blur // Blur
src = BoxBlur(chf, 1, src); src = BoxBlur(chf, 1, src);
@ -1435,9 +1434,7 @@ namespace DotRecast.Recast
// Store distance. // Store distance.
chf.dist = src; chf.dist = src;
ctx.StopTimer("DISTANCEFIELD_BLUR"); ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_DISTANCEFIELD_BLUR);
ctx.StopTimer("DISTANCEFIELD");
} }
private static void PaintRectRegion(int minx, int maxx, int miny, int maxy, int regId, RcCompactHeightfield chf, private static void PaintRectRegion(int minx, int maxx, int miny, int maxy, int regId, RcCompactHeightfield chf,
@ -1482,7 +1479,7 @@ namespace DotRecast.Recast
public static void BuildRegionsMonotone(RcTelemetry ctx, RcCompactHeightfield chf, int minRegionArea, public static void BuildRegionsMonotone(RcTelemetry ctx, RcCompactHeightfield chf, int minRegionArea,
int mergeRegionArea) int mergeRegionArea)
{ {
ctx.StartTimer("REGIONS"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS);
int w = chf.width; int w = chf.width;
int h = chf.height; int h = chf.height;
@ -1624,23 +1621,19 @@ namespace DotRecast.Recast
} }
} }
ctx.StartTimer("REGIONS_FILTER"); ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER);
// Merge regions and filter out small regions. // Merge regions and filter out small regions.
List<int> overlaps = new List<int>(); List<int> overlaps = new List<int>();
chf.maxRegions = MergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, id, chf, srcReg, overlaps); chf.maxRegions = MergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, id, chf, srcReg, overlaps);
// Monotone partitioning does not generate overlapping regions. // Monotone partitioning does not generate overlapping regions.
ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER);
ctx.StopTimer("REGIONS_FILTER");
// Store the result out. // Store the result out.
for (int i = 0; i < chf.spanCount; ++i) for (int i = 0; i < chf.spanCount; ++i)
{ {
chf.spans[i].reg = srcReg[i]; chf.spans[i].reg = srcReg[i];
} }
ctx.StopTimer("REGIONS");
} }
/// @par /// @par
@ -1665,13 +1658,13 @@ namespace DotRecast.Recast
public static void BuildRegions(RcTelemetry ctx, RcCompactHeightfield chf, int minRegionArea, public static void BuildRegions(RcTelemetry ctx, RcCompactHeightfield chf, int minRegionArea,
int mergeRegionArea) int mergeRegionArea)
{ {
ctx.StartTimer("REGIONS"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS);
int w = chf.width; int w = chf.width;
int h = chf.height; int h = chf.height;
int borderSize = chf.borderSize; int borderSize = chf.borderSize;
ctx.StartTimer("REGIONS_WATERSHED"); ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_WATERSHED);
int LOG_NB_STACKS = 3; int LOG_NB_STACKS = 3;
int NB_STACKS = 1 << LOG_NB_STACKS; int NB_STACKS = 1 << LOG_NB_STACKS;
@ -1732,14 +1725,14 @@ namespace DotRecast.Recast
// ctx->StopTimer(RC_TIMER_DIVIDE_TO_LEVELS); // ctx->StopTimer(RC_TIMER_DIVIDE_TO_LEVELS);
ctx.StartTimer("REGIONS_EXPAND"); ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_EXPAND);
// Expand current regions until no empty connected cells found. // Expand current regions until no empty connected cells found.
ExpandRegions(expandIters, level, chf, srcReg, srcDist, lvlStacks[sId], false); ExpandRegions(expandIters, level, chf, srcReg, srcDist, lvlStacks[sId], false);
ctx.StopTimer("REGIONS_EXPAND"); ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_EXPAND);
ctx.StartTimer("REGIONS_FLOOD"); ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FLOOD);
// Mark new regions with IDs. // Mark new regions with IDs.
for (int j = 0; j < lvlStacks[sId].Count; j += 3) for (int j = 0; j < lvlStacks[sId].Count; j += 3)
@ -1756,15 +1749,15 @@ namespace DotRecast.Recast
} }
} }
ctx.StopTimer("REGIONS_FLOOD"); ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FLOOD);
} }
// Expand current regions until no empty connected cells found. // Expand current regions until no empty connected cells found.
ExpandRegions(expandIters * 8, 0, chf, srcReg, srcDist, stack, true); ExpandRegions(expandIters * 8, 0, chf, srcReg, srcDist, stack, true);
ctx.StopTimer("REGIONS_WATERSHED"); ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_WATERSHED);
ctx.StartTimer("REGIONS_FILTER"); ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER);
// Merge regions and filter out smalle regions. // Merge regions and filter out smalle regions.
List<int> overlaps = new List<int>(); List<int> overlaps = new List<int>();
@ -1776,20 +1769,18 @@ namespace DotRecast.Recast
ctx.Warn("rcBuildRegions: " + overlaps.Count + " overlapping regions."); ctx.Warn("rcBuildRegions: " + overlaps.Count + " overlapping regions.");
} }
ctx.StopTimer("REGIONS_FILTER"); ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER);
// Write the result out. // Write the result out.
for (int i = 0; i < chf.spanCount; ++i) for (int i = 0; i < chf.spanCount; ++i)
{ {
chf.spans[i].reg = srcReg[i]; chf.spans[i].reg = srcReg[i];
} }
ctx.StopTimer("REGIONS");
} }
public static void BuildLayerRegions(RcTelemetry ctx, RcCompactHeightfield chf, int minRegionArea) public static void BuildLayerRegions(RcTelemetry ctx, RcCompactHeightfield chf, int minRegionArea)
{ {
ctx.StartTimer("REGIONS"); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS);
int w = chf.width; int w = chf.width;
int h = chf.height; int h = chf.height;
@ -1930,21 +1921,19 @@ namespace DotRecast.Recast
} }
} }
ctx.StartTimer("REGIONS_FILTER"); ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER);
// Merge monotone regions to layers and remove small regions. // Merge monotone regions to layers and remove small regions.
List<int> overlaps = new List<int>(); List<int> overlaps = new List<int>();
chf.maxRegions = MergeAndFilterLayerRegions(ctx, minRegionArea, id, chf, srcReg, overlaps); chf.maxRegions = MergeAndFilterLayerRegions(ctx, minRegionArea, id, chf, srcReg, overlaps);
ctx.StopTimer("REGIONS_FILTER"); ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER);
// Store the result out. // Store the result out.
for (int i = 0; i < chf.spanCount; ++i) for (int i = 0; i < chf.spanCount; ++i)
{ {
chf.spans[i].reg = srcReg[i]; chf.spans[i].reg = srcReg[i];
} }
ctx.StopTimer("REGIONS");
} }
} }
} }