diff --git a/src/DotRecast.Core/RcAnonymousDisposable.cs b/src/DotRecast.Core/RcAnonymousDisposable.cs new file mode 100644 index 0000000..6cf1050 --- /dev/null +++ b/src/DotRecast.Core/RcAnonymousDisposable.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/src/DotRecast.Core/RcTelemetry.cs b/src/DotRecast.Core/RcTelemetry.cs index 6deec47..03e3f8d 100644 --- a/src/DotRecast.Core/RcTelemetry.cs +++ b/src/DotRecast.Core/RcTelemetry.cs @@ -35,16 +35,23 @@ namespace DotRecast.Core _timerAccum = new ConcurrentDictionary(); } - 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 StartTimer(RcTimerLabel label) + { + _timerStart.Value[label.Name] = new RcAtomicLong(RcFrequency.Ticks); } - public void StopTimer(string name) + + public void StopTimer(RcTimerLabel label) { _timerAccum - .GetOrAdd(name, _ => new RcAtomicLong(0)) - .AddAndGet(RcFrequency.Ticks - _timerStart.Value?[name].Read() ?? 0); + .GetOrAdd(label.Name, _ => new RcAtomicLong(0)) + .AddAndGet(RcFrequency.Ticks - _timerStart.Value?[label.Name].Read() ?? 0); } public void Warn(string message) diff --git a/src/DotRecast.Core/RcTimerLabel.cs b/src/DotRecast.Core/RcTimerLabel.cs new file mode 100644 index 0000000..4492cf0 --- /dev/null +++ b/src/DotRecast.Core/RcTimerLabel.cs @@ -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; + } + }; +} \ No newline at end of file diff --git a/src/DotRecast.Recast/RecastArea.cs b/src/DotRecast.Recast/RecastArea.cs index 5efa778..b33f1d0 100644 --- a/src/DotRecast.Recast/RecastArea.cs +++ b/src/DotRecast.Recast/RecastArea.cs @@ -39,7 +39,7 @@ namespace DotRecast.Recast { int w = chf.width; int h = chf.height; - ctx.StartTimer("ERODE_AREA"); + using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_ERODE_AREA); int[] dist = new int[chf.spanCount]; Array.Fill(dist, 255); @@ -205,8 +205,6 @@ namespace DotRecast.Recast for (int i = 0; i < chf.spanCount; ++i) if (dist[i] < thr) chf.areas[i] = RC_NULL_AREA; - - ctx.StopTimer("ERODE_AREA"); } /// @par @@ -220,7 +218,7 @@ namespace DotRecast.Recast int w = chf.width; int h = chf.height; - ctx.StartTimer("MEDIAN_AREA"); + using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_MEDIAN_AREA); int[] areas = new int[chf.spanCount]; @@ -273,8 +271,6 @@ namespace DotRecast.Recast chf.areas = areas; - ctx.StopTimer("MEDIAN_AREA"); - return true; } @@ -285,7 +281,7 @@ namespace DotRecast.Recast /// @see rcCompactHeightfield, rcMedianFilterWalkableArea 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 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) @@ -360,7 +354,7 @@ namespace DotRecast.Recast public static void MarkConvexPolyArea(RcTelemetry ctx, float[] verts, float hmin, float hmax, AreaModification areaMod, RcCompactHeightfield chf) { - ctx.StartTimer("MARK_CONVEXPOLY_AREA"); + using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_MARK_CONVEXPOLY_AREA); RcVec3f bmin = new RcVec3f(); RcVec3f bmax = new RcVec3f(); @@ -368,8 +362,8 @@ namespace DotRecast.Recast RcVec3f.Copy(ref bmax, verts, 0); for (int i = 3; i < verts.Length; i += 3) { - bmin.Min(verts, i); - bmax.Max(verts, i); + bmin.Min(verts, i); + bmax.Max(verts, i); } bmin.y = hmin; @@ -426,8 +420,6 @@ namespace DotRecast.Recast } } } - - ctx.StopTimer("MARK_CONVEXPOLY_AREA"); } /// @par @@ -437,7 +429,7 @@ namespace DotRecast.Recast /// @see rcCompactHeightfield, rcMedianFilterWalkableArea 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 bmax = new RcVec3f(); @@ -501,8 +493,6 @@ namespace DotRecast.Recast } } } - - ctx.StopTimer("MARK_CYLINDER_AREA"); } } -} +} \ No newline at end of file diff --git a/src/DotRecast.Recast/RecastCompact.cs b/src/DotRecast.Recast/RecastCompact.cs index 0834e0d..dffe87d 100644 --- a/src/DotRecast.Recast/RecastCompact.cs +++ b/src/DotRecast.Recast/RecastCompact.cs @@ -41,7 +41,7 @@ namespace DotRecast.Recast public static RcCompactHeightfield BuildCompactHeightfield(RcTelemetry ctx, int walkableHeight, int walkableClimb, RcHeightfield hf) { - ctx.StartTimer("BUILD_COMPACTHEIGHTFIELD"); + using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_COMPACTHEIGHTFIELD); RcCompactHeightfield chf = new RcCompactHeightfield(); int w = hf.width; @@ -161,7 +161,6 @@ namespace DotRecast.Recast + " (max: " + MAX_LAYERS + ")"); } - ctx.StopTimer("BUILD_COMPACTHEIGHTFIELD"); return chf; } diff --git a/src/DotRecast.Recast/RecastContour.cs b/src/DotRecast.Recast/RecastContour.cs index e688a37..1271e22 100644 --- a/src/DotRecast.Recast/RecastContour.cs +++ b/src/DotRecast.Recast/RecastContour.cs @@ -722,7 +722,8 @@ namespace DotRecast.Recast int borderSize = chf.borderSize; RcContourSet cset = new RcContourSet(); - ctx.StartTimer("CONTOURS"); + using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_CONTOURS); + cset.bmin = chf.bmin; cset.bmax = chf.bmax; if (borderSize > 0) @@ -744,7 +745,7 @@ namespace DotRecast.Recast int[] flags = new int[chf.spanCount]; - ctx.StartTimer("CONTOURS_TRACE"); + ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_CONTOURS_TRACE); // Mark boundaries. 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 verts = new List(256); List simplified = new List(64); @@ -808,14 +809,14 @@ namespace DotRecast.Recast verts.Clear(); simplified.Clear(); - ctx.StartTimer("CONTOURS_WALK"); + ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_CONTOURS_WALK); 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); RemoveDegenerateSegments(simplified); - ctx.StopTimer("CONTOURS_SIMPLIFY"); + ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_CONTOURS_SIMPLIFY); // Store region->contour remap info. // Create contour. @@ -956,7 +957,6 @@ namespace DotRecast.Recast } } - ctx.StopTimer("CONTOURS"); return cset; } } diff --git a/src/DotRecast.Recast/RecastFilledVolumeRasterization.cs b/src/DotRecast.Recast/RecastFilledVolumeRasterization.cs index c92e2a0..0defe09 100644 --- a/src/DotRecast.Recast/RecastFilledVolumeRasterization.cs +++ b/src/DotRecast.Recast/RecastFilledVolumeRasterization.cs @@ -31,7 +31,7 @@ namespace DotRecast.Recast 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 = { 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, 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, RcTelemetry ctx) { - ctx.StartTimer("RASTERIZE_CAPSULE"); + using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_CAPSULE); float[] bounds = { 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); RasterizationFilledShape(hf, bounds, area, flagMergeThr, 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, RcTelemetry ctx) { - ctx.StartTimer("RASTERIZE_CYLINDER"); + using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_CYLINDER); float[] bounds = { 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); RasterizationFilledShape(hf, bounds, area, flagMergeThr, 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, RcTelemetry ctx) { - ctx.StartTimer("RASTERIZE_BOX"); + using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_BOX); RcVec3f[] normals = { 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)); - ctx.StopTimer("RASTERIZE_BOX"); } public static void RasterizeConvex(RcHeightfield hf, float[] vertices, int[] triangles, int area, int flagMergeThr, 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] }; for (int i = 0; i < vertices.Length; i += 3) { @@ -179,7 +175,6 @@ namespace DotRecast.Recast RasterizationFilledShape(hf, bounds, area, flagMergeThr, 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) @@ -796,4 +791,4 @@ namespace DotRecast.Recast return overlap; } } -} +} \ No newline at end of file diff --git a/src/DotRecast.Recast/RecastFilter.cs b/src/DotRecast.Recast/RecastFilter.cs index cfd4102..821d074 100644 --- a/src/DotRecast.Recast/RecastFilter.cs +++ b/src/DotRecast.Recast/RecastFilter.cs @@ -40,7 +40,7 @@ namespace DotRecast.Recast /// @see rcHeightfield, rcConfig 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 h = solid.height; @@ -71,8 +71,6 @@ namespace DotRecast.Recast } } } - - ctx.StopTimer("FILTER_LOW_OBSTACLES"); } /// @par @@ -87,7 +85,7 @@ namespace DotRecast.Recast /// @see rcHeightfield, rcConfig 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 h = solid.height; @@ -168,8 +166,6 @@ namespace DotRecast.Recast } } } - - ctx.StopTimer("FILTER_LEDGE"); } /// @par @@ -180,7 +176,7 @@ namespace DotRecast.Recast /// @see rcHeightfield, rcConfig 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 h = solid.height; @@ -200,8 +196,6 @@ namespace DotRecast.Recast } } } - - ctx.StopTimer("FILTER_WALKABLE"); } } } \ No newline at end of file diff --git a/src/DotRecast.Recast/RecastLayers.cs b/src/DotRecast.Recast/RecastLayers.cs index 5b4a4c2..b6bc27a 100644 --- a/src/DotRecast.Recast/RecastLayers.cs +++ b/src/DotRecast.Recast/RecastLayers.cs @@ -53,7 +53,8 @@ namespace DotRecast.Recast 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 h = chf.height; int borderSize = chf.borderSize; @@ -397,7 +398,7 @@ namespace DotRecast.Recast // No layers, return empty. if (layerId == 0) { - // ctx.StopTimer(RC_TIMER_BUILD_LAYERS); + // ctx.Stop(RC_TIMER_BUILD_LAYERS); return null; } diff --git a/src/DotRecast.Recast/RecastMesh.cs b/src/DotRecast.Recast/RecastMesh.cs index 653c84a..efff93e 100644 --- a/src/DotRecast.Recast/RecastMesh.cs +++ b/src/DotRecast.Recast/RecastMesh.cs @@ -966,7 +966,8 @@ namespace DotRecast.Recast /// @see rcAllocPolyMesh, rcContourSet, rcPolyMesh, rcConfig 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(); mesh.bmin = cset.bmin; mesh.bmax = cset.bmax; @@ -1204,7 +1205,6 @@ namespace DotRecast.Recast + " (max " + MAX_MESH_VERTS_POLY + "). Data can be corrupted."); } - ctx.StopTimer("POLYMESH"); return mesh; } @@ -1214,7 +1214,8 @@ namespace DotRecast.Recast if (nmeshes == 0 || meshes == null) return null; - ctx.StartTimer("MERGE_POLYMESH"); + using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_MERGE_POLYMESH); + RcPolyMesh mesh = new RcPolyMesh(); mesh.nvp = meshes[0].nvp; mesh.cs = meshes[0].cs; @@ -1333,8 +1334,6 @@ namespace DotRecast.Recast + " (max " + MAX_MESH_VERTS_POLY + "). Data can be corrupted."); } - ctx.StopTimer("MERGE_POLYMESH"); - return mesh; } diff --git a/src/DotRecast.Recast/RecastMeshDetail.cs b/src/DotRecast.Recast/RecastMeshDetail.cs index 3f3760d..811991f 100644 --- a/src/DotRecast.Recast/RecastMeshDetail.cs +++ b/src/DotRecast.Recast/RecastMeshDetail.cs @@ -1009,8 +1009,8 @@ namespace DotRecast.Recast RcVec3f.Copy(ref bmax, @in, 0); for (int i = 1; i < nin; ++i) { - bmin.Min(@in, i * 3); - bmax.Max(@in, i * 3); + bmin.Min(@in, i * 3); + bmax.Max(@in, i * 3); } int x0 = (int)Math.Floor(bmin.x / sampleDist); @@ -1426,7 +1426,7 @@ namespace DotRecast.Recast public static RcPolyMeshDetail BuildPolyMeshDetail(RcTelemetry ctx, RcPolyMesh mesh, RcCompactHeightfield chf, float sampleDist, float sampleMaxError) { - ctx.StartTimer("POLYMESHDETAIL"); + using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_POLYMESHDETAIL); if (mesh.nverts == 0 || mesh.npolys == 0) { return null; @@ -1610,16 +1610,15 @@ namespace DotRecast.Recast } } - ctx.StopTimer("POLYMESHDETAIL"); return dmesh; } /// @see rcAllocPolyMeshDetail, rcPolyMeshDetail 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 maxTris = 0; @@ -1680,7 +1679,6 @@ namespace DotRecast.Recast } } - ctx.StopTimer("MERGE_POLYMESHDETAIL"); return mesh; } } diff --git a/src/DotRecast.Recast/RecastRasterization.cs b/src/DotRecast.Recast/RecastRasterization.cs index 16c9975..36a853c 100644 --- a/src/DotRecast.Recast/RecastRasterization.cs +++ b/src/DotRecast.Recast/RecastRasterization.cs @@ -400,14 +400,12 @@ namespace DotRecast.Recast public static void RasterizeTriangle(RcHeightfield heightfield, float[] verts, int v0, int v1, int v2, int area, 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 inverseCellHeight = 1.0f / heightfield.ch; RasterizeTri(verts, v0, v1, v2, area, heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, inverseCellSize, 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, 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 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, 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, 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 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, inverseCellSize, inverseCellHeight, flagMergeThreshold); } - - ctx.StopTimer("RASTERIZE_TRIANGLES"); } } } \ No newline at end of file diff --git a/src/DotRecast.Recast/RecastRegion.cs b/src/DotRecast.Recast/RecastRegion.cs index a3b1641..9c3a4c6 100644 --- a/src/DotRecast.Recast/RecastRegion.cs +++ b/src/DotRecast.Recast/RecastRegion.cs @@ -580,7 +580,6 @@ namespace DotRecast.Recast } - private static void RemoveAdjacentNeighbours(RcRegion reg) { // Remove adjacent duplicates. @@ -1418,16 +1417,16 @@ namespace DotRecast.Recast /// @see rcCompactHeightfield, rcBuildRegions, rcBuildRegionsMonotone public static void BuildDistanceField(RcTelemetry ctx, RcCompactHeightfield chf) { - ctx.StartTimer("DISTANCEFIELD"); - int[] src = new int[chf.spanCount]; - ctx.StartTimer("DISTANCEFIELD_DIST"); + using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_DISTANCEFIELD); + int[] src = new int[chf.spanCount]; + + ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_DISTANCEFIELD_DIST); int maxDist = CalculateDistanceField(chf, src); chf.maxDistance = maxDist; + ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_DISTANCEFIELD_DIST); - ctx.StopTimer("DISTANCEFIELD_DIST"); - - ctx.StartTimer("DISTANCEFIELD_BLUR"); + ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_DISTANCEFIELD_BLUR); // Blur src = BoxBlur(chf, 1, src); @@ -1435,9 +1434,7 @@ namespace DotRecast.Recast // Store distance. chf.dist = src; - ctx.StopTimer("DISTANCEFIELD_BLUR"); - - ctx.StopTimer("DISTANCEFIELD"); + ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_DISTANCEFIELD_BLUR); } 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, int mergeRegionArea) { - ctx.StartTimer("REGIONS"); + using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS); int w = chf.width; 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. List overlaps = new List(); chf.maxRegions = MergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, id, chf, srcReg, overlaps); // Monotone partitioning does not generate overlapping regions. - - ctx.StopTimer("REGIONS_FILTER"); + ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER); // Store the result out. for (int i = 0; i < chf.spanCount; ++i) { chf.spans[i].reg = srcReg[i]; } - - ctx.StopTimer("REGIONS"); } /// @par @@ -1665,13 +1658,13 @@ namespace DotRecast.Recast public static void BuildRegions(RcTelemetry ctx, RcCompactHeightfield chf, int minRegionArea, int mergeRegionArea) { - ctx.StartTimer("REGIONS"); + using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS); int w = chf.width; int h = chf.height; int borderSize = chf.borderSize; - ctx.StartTimer("REGIONS_WATERSHED"); + ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_WATERSHED); int LOG_NB_STACKS = 3; int NB_STACKS = 1 << LOG_NB_STACKS; @@ -1732,14 +1725,14 @@ namespace DotRecast.Recast // 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. 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. 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. 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. List overlaps = new List(); @@ -1776,20 +1769,18 @@ namespace DotRecast.Recast ctx.Warn("rcBuildRegions: " + overlaps.Count + " overlapping regions."); } - ctx.StopTimer("REGIONS_FILTER"); + ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER); // Write the result out. for (int i = 0; i < chf.spanCount; ++i) { chf.spans[i].reg = srcReg[i]; } - - ctx.StopTimer("REGIONS"); } 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 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. List overlaps = new List(); 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. for (int i = 0; i < chf.spanCount; ++i) { chf.spans[i].reg = srcReg[i]; } - - ctx.StopTimer("REGIONS"); } } -} +} \ No newline at end of file