diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1001d74..0093ad1 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -49,7 +49,7 @@ jobs: uses: actions/checkout@v4 - name: Set up .NET 8.0 - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: 8.x diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 972fa7a..af233a5 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -37,7 +37,7 @@ jobs: fetch-depth: 0 # Get all history to allow automatic versioning using MinVer - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ matrix.dotnet-version }}.x diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index a849a60..f00fc9f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -33,7 +33,7 @@ jobs: fetch-depth: 0 # Get all history to allow automatic versioning using MinVer - name: Setup Dotnet - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: '8.x' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7f14ed1..2e75fbe 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,7 @@ jobs: fetch-depth: 0 # Get all history to allow automatic versioning using MinVer - name: Setup Dotnet - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: '8.x' diff --git a/src/DotRecast.Core/RcSpans.cs b/src/DotRecast.Core/RcSpans.cs new file mode 100644 index 0000000..474f492 --- /dev/null +++ b/src/DotRecast.Core/RcSpans.cs @@ -0,0 +1,22 @@ +using System; +using System.Runtime.CompilerServices; + +namespace DotRecast.Core +{ + public static class RcSpans + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Copy(Span source, Span destination) + { + Copy(source, 0, destination, 0, source.Length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Copy(Span source, int sourceIdx, Span destination, int destinationIdx, int length) + { + var src = source.Slice(sourceIdx, length); + var dst = destination.Slice(destinationIdx); + src.CopyTo(dst); + } + } +} \ No newline at end of file diff --git a/src/DotRecast.Detour.Dynamic/DtDynamicTile.cs b/src/DotRecast.Detour.Dynamic/DtDynamicTile.cs index 7712497..4f31dcd 100644 --- a/src/DotRecast.Detour.Dynamic/DtDynamicTile.cs +++ b/src/DotRecast.Detour.Dynamic/DtDynamicTile.cs @@ -100,7 +100,7 @@ namespace DotRecast.Detour.Dynamic Math.Min(DtDynamicNavMesh.MAX_VERTS_PER_POLY, config.vertsPerPoly), config.detailSampleDistance, config.detailSampleMaxError, true, true, true, default, true); - RcBuilderResult r = builder.Build(context, vt.tileX, vt.tileZ, null, rcConfig, heightfield); + RcBuilderResult r = builder.Build(context, vt.tileX, vt.tileZ, null, rcConfig, heightfield, false); if (config.keepIntermediateResults) { recastResult = r; diff --git a/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj b/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj index 399aa50..b231327 100644 --- a/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj +++ b/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj @@ -27,8 +27,8 @@ - - + + diff --git a/src/DotRecast.Recast.Demo/Draw/GLCheckerTexture.cs b/src/DotRecast.Recast.Demo/Draw/GLCheckerTexture.cs index 061ab23..e044757 100644 --- a/src/DotRecast.Recast.Demo/Draw/GLCheckerTexture.cs +++ b/src/DotRecast.Recast.Demo/Draw/GLCheckerTexture.cs @@ -32,15 +32,18 @@ public class GLCheckerTexture _gl = gl; } - public void Release() + public unsafe void Release() { if (m_texId != 0) { - _gl.DeleteTextures(1, m_texId); + fixed (uint* p = &m_texId) + { + _gl.DeleteTextures(1, p); + } } } - public void Bind() + public unsafe void Bind() { if (m_texId == 0) { @@ -50,7 +53,11 @@ public class GLCheckerTexture uint TSIZE = 64; int[] data = new int[TSIZE * TSIZE]; - _gl.GenTextures(1, out m_texId); + fixed (uint* p = &m_texId) + { + _gl.GenTextures(1, p); + } + _gl.BindTexture(GLEnum.Texture2D, m_texId); int level = 0; @@ -70,8 +77,10 @@ public class GLCheckerTexture level++; } - _gl.TexParameterI(GLEnum.Texture2D, GLEnum.TextureMinFilter, (uint)GLEnum.LinearMipmapNearest); - _gl.TexParameterI(GLEnum.Texture2D, GLEnum.TextureMagFilter, (uint)GLEnum.Linear); + uint linearMipmapNearest = (uint)GLEnum.LinearMipmapNearest; + uint linear = (uint)GLEnum.Linear; + _gl.TexParameterI(GLEnum.Texture2D, GLEnum.TextureMinFilter, &linearMipmapNearest); + _gl.TexParameterI(GLEnum.Texture2D, GLEnum.TextureMagFilter, &linear); } else { diff --git a/src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs b/src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs index 71d2c0f..10b4c09 100644 --- a/src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs +++ b/src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs @@ -80,22 +80,7 @@ namespace DotRecast.Recast.Toolset.Builder { RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax()); RcBuilder rcBuilder = new RcBuilder(); - var result = rcBuilder.Build(geom, bcfg); - if (!keepInterResults) - { - return new RcBuilderResult( - result.TileX, - result.TileZ, - null, - null, - null, - result.Mesh, - result.MeshDetail, - result.Context - ); - } - - return result; + return rcBuilder.Build(geom, bcfg, keepInterResults); } public DtMeshData BuildMeshData(DemoInputGeomProvider geom, diff --git a/src/DotRecast.Recast/RcBuilder.cs b/src/DotRecast.Recast/RcBuilder.cs index 8cad533..0620809 100644 --- a/src/DotRecast.Recast/RcBuilder.cs +++ b/src/DotRecast.Recast/RcBuilder.cs @@ -132,30 +132,17 @@ namespace DotRecast.Recast public RcBuilderResult BuildTile(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tx, int ty, RcAtomicInteger progress, int total, bool keepInterResults) { var bcfg = new RcBuilderConfig(cfg, bmin, bmax, tx, ty); - RcBuilderResult result = Build(geom, bcfg); + RcBuilderResult result = Build(geom, bcfg, keepInterResults); if (_progressListener != null) { _progressListener.OnProgress(progress.IncrementAndGet(), total); } - if (!keepInterResults) - { - return new RcBuilderResult( - result.TileX, - result.TileZ, - null, - null, - null, - result.Mesh, - result.MeshDetail, - result.Context - ); - } return result; } - public RcBuilderResult Build(IInputGeomProvider geom, RcBuilderConfig bcfg) + public RcBuilderResult Build(IInputGeomProvider geom, RcBuilderConfig bcfg, bool keepInterResults) { RcConfig cfg = bcfg.cfg; RcContext ctx = new RcContext(); @@ -163,10 +150,10 @@ namespace DotRecast.Recast // Step 1. Rasterize input polygon soup. // RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(ctx, geom, bcfg); - return Build(ctx, bcfg.tileX, bcfg.tileZ, geom, cfg, solid); + return Build(ctx, bcfg.tileX, bcfg.tileZ, geom, cfg, solid, keepInterResults); } - public RcBuilderResult Build(RcContext ctx, int tileX, int tileZ, IInputGeomProvider geom, RcConfig cfg, RcHeightfield solid) + public RcBuilderResult Build(RcContext ctx, int tileX, int tileZ, IInputGeomProvider geom, RcConfig cfg, RcHeightfield solid, bool keepInterResults) { FilterHeightfield(ctx, solid, cfg); RcCompactHeightfield chf = BuildCompactHeightfield(ctx, geom, cfg, solid); @@ -237,7 +224,17 @@ namespace DotRecast.Recast RcPolyMeshDetail dmesh = cfg.BuildMeshDetail ? RcMeshDetails.BuildPolyMeshDetail(ctx, pmesh, chf, cfg.DetailSampleDist, cfg.DetailSampleMaxError) : null; - return new RcBuilderResult(tileX, tileZ, solid, chf, cset, pmesh, dmesh, ctx); + + return new RcBuilderResult( + tileX, + tileZ, + keepInterResults ? solid : null, + keepInterResults ? chf : null, + keepInterResults ? cset : null, + pmesh, + dmesh, + ctx + ); } /* diff --git a/test/DotRecast.Core.Test/DotRecast.Core.Test.csproj b/test/DotRecast.Core.Test/DotRecast.Core.Test.csproj index ebef2b5..343e1ce 100644 --- a/test/DotRecast.Core.Test/DotRecast.Core.Test.csproj +++ b/test/DotRecast.Core.Test/DotRecast.Core.Test.csproj @@ -11,7 +11,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/DotRecast.Core.Test/RcArrayBenchmarkTests.cs b/test/DotRecast.Core.Test/RcArrayBenchmarkTests.cs index 1296d88..3117e7d 100644 --- a/test/DotRecast.Core.Test/RcArrayBenchmarkTests.cs +++ b/test/DotRecast.Core.Test/RcArrayBenchmarkTests.cs @@ -1,6 +1,7 @@ using System; using System.Buffers; using System.Collections.Generic; +using System.Net.Sockets; using DotRecast.Core.Buffers; using DotRecast.Core.Collections; using NUnit.Framework; @@ -84,18 +85,73 @@ public class RcArrayBenchmarkTests [Test] public void TestBenchmarkArrays() { - var list = new List<(string title, long ticks)>(); - list.Add(Bench("new int[len]", RoundForArray)); - list.Add(Bench("ArrayPool.Shared.Rent(len)", RoundForPureRentArray)); - list.Add(Bench("RcRentedArray.Rent(len)", RoundForRcRentedArray)); - list.Add(Bench("new RcStackArray512()", RoundForRcStackArray)); - list.Add(Bench("stackalloc int[len]", RoundForStackalloc)); + var results = new List<(string title, long ticks)>(); + results.Add(Bench("new int[len]", RoundForArray)); + results.Add(Bench("ArrayPool.Shared.Rent(len)", RoundForPureRentArray)); + results.Add(Bench("RcRentedArray.Rent(len)", RoundForRcRentedArray)); + results.Add(Bench("new RcStackArray512()", RoundForRcStackArray)); + results.Add(Bench("stackalloc int[len]", RoundForStackalloc)); - list.Sort((x, y) => x.ticks.CompareTo(y.ticks)); + results.Sort((x, y) => x.ticks.CompareTo(y.ticks)); - foreach (var t in list) + foreach (var t in results) { Console.WriteLine($"{t.title} {t.ticks / (double)TimeSpan.TicksPerMillisecond} ms"); } } + + [Test] + public void TestSpanVsArray() + { + var r = new RcRand(); + var list = new List<(long[] src, long[] dest)>(); + for (int i = 0; i < 14; ++i) + { + var s = new long[(int)Math.Pow(2, i + 1)]; + var d = new long[(int)Math.Pow(2, i + 1)]; + for (int ii = 0; ii < s.Length; ++ii) + { + s[ii] = r.NextInt32(); + } + + list.Add((s, d)); + } + + var results = new List<(string title, long ticks)>(); + for (int i = 0; i < list.Count; ++i) + { + var seq = i; + + Array.Fill(list[seq].dest, 0); + var resultLong = Bench($"long[{list[seq].src.Length}]", _ => + { + var v = list[seq]; + RcArrays.Copy(v.src, 0, v.dest, 0, v.src.Length); + }); + + + Array.Fill(list[seq].dest, 0); + var resultSpan = Bench($"Span", _ => + { + var v = list[seq]; + RcSpans.Copy(v.src, 0, v.dest, 0, v.src.Length); + }); + + + results.Add(resultLong); + results.Add(resultSpan); + } + + + int newLine = 0; + foreach (var t in results) + { + Console.WriteLine($"{t.title}: {t.ticks / (double)TimeSpan.TicksPerMillisecond} ms"); + newLine += 1; + if (0 == (newLine % 2)) + { + Console.WriteLine(""); + } + } + } } \ No newline at end of file diff --git a/test/DotRecast.Detour.Crowd.Test/DotRecast.Detour.Crowd.Test.csproj b/test/DotRecast.Detour.Crowd.Test/DotRecast.Detour.Crowd.Test.csproj index e416f45..55953c2 100644 --- a/test/DotRecast.Detour.Crowd.Test/DotRecast.Detour.Crowd.Test.csproj +++ b/test/DotRecast.Detour.Crowd.Test/DotRecast.Detour.Crowd.Test.csproj @@ -11,7 +11,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/DotRecast.Detour.Crowd.Test/RecastTestMeshBuilder.cs b/test/DotRecast.Detour.Crowd.Test/RecastTestMeshBuilder.cs index 7fd70c3..bacecb9 100644 --- a/test/DotRecast.Detour.Crowd.Test/RecastTestMeshBuilder.cs +++ b/test/DotRecast.Detour.Crowd.Test/RecastTestMeshBuilder.cs @@ -72,7 +72,7 @@ public class RecastTestMeshBuilder SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax()); RcBuilder rcBuilder = new RcBuilder(); - RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg); + RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg, false); RcPolyMesh m_pmesh = rcResult.Mesh; for (int i = 0; i < m_pmesh.npolys; ++i) { diff --git a/test/DotRecast.Detour.Dynamic.Test/DotRecast.Detour.Dynamic.Test.csproj b/test/DotRecast.Detour.Dynamic.Test/DotRecast.Detour.Dynamic.Test.csproj index 153236f..57e7160 100644 --- a/test/DotRecast.Detour.Dynamic.Test/DotRecast.Detour.Dynamic.Test.csproj +++ b/test/DotRecast.Detour.Dynamic.Test/DotRecast.Detour.Dynamic.Test.csproj @@ -11,7 +11,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/DotRecast.Detour.Extras.Test/DotRecast.Detour.Extras.Test.csproj b/test/DotRecast.Detour.Extras.Test/DotRecast.Detour.Extras.Test.csproj index 9af54f1..a11f9e8 100644 --- a/test/DotRecast.Detour.Extras.Test/DotRecast.Detour.Extras.Test.csproj +++ b/test/DotRecast.Detour.Extras.Test/DotRecast.Detour.Extras.Test.csproj @@ -11,7 +11,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/DotRecast.Detour.Test/DotRecast.Detour.Test.csproj b/test/DotRecast.Detour.Test/DotRecast.Detour.Test.csproj index aae8db2..c4e8dd5 100644 --- a/test/DotRecast.Detour.Test/DotRecast.Detour.Test.csproj +++ b/test/DotRecast.Detour.Test/DotRecast.Detour.Test.csproj @@ -11,7 +11,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/DotRecast.Detour.Test/RecastTestMeshBuilder.cs b/test/DotRecast.Detour.Test/RecastTestMeshBuilder.cs index b1830bb..12c618e 100644 --- a/test/DotRecast.Detour.Test/RecastTestMeshBuilder.cs +++ b/test/DotRecast.Detour.Test/RecastTestMeshBuilder.cs @@ -72,7 +72,7 @@ public class RecastTestMeshBuilder SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax()); RcBuilder rcBuilder = new RcBuilder(); - RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg); + RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg, false); RcPolyMesh m_pmesh = rcResult.Mesh; for (int i = 0; i < m_pmesh.npolys; ++i) { diff --git a/test/DotRecast.Detour.Test/TestDetourBuilder.cs b/test/DotRecast.Detour.Test/TestDetourBuilder.cs index d7b9268..4df7c6d 100644 --- a/test/DotRecast.Detour.Test/TestDetourBuilder.cs +++ b/test/DotRecast.Detour.Test/TestDetourBuilder.cs @@ -27,7 +27,7 @@ public class TestDetourBuilder : DetourBuilder float agentMaxClimb, int x, int y, bool applyRecastDemoFlags) { RcBuilder rcBuilder = new RcBuilder(); - RcBuilderResult rcResult = rcBuilder.Build(geom, rcConfig); + RcBuilderResult rcResult = rcBuilder.Build(geom, rcConfig, false); RcPolyMesh pmesh = rcResult.Mesh; if (applyRecastDemoFlags) diff --git a/test/DotRecast.Detour.TileCache.Test/DotRecast.Detour.TileCache.Test.csproj b/test/DotRecast.Detour.TileCache.Test/DotRecast.Detour.TileCache.Test.csproj index d7247b0..4278add 100644 --- a/test/DotRecast.Detour.TileCache.Test/DotRecast.Detour.TileCache.Test.csproj +++ b/test/DotRecast.Detour.TileCache.Test/DotRecast.Detour.TileCache.Test.csproj @@ -11,7 +11,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/DotRecast.Recast.Test/DotRecast.Recast.Test.csproj b/test/DotRecast.Recast.Test/DotRecast.Recast.Test.csproj index cd9cbc4..bd28373 100644 --- a/test/DotRecast.Recast.Test/DotRecast.Recast.Test.csproj +++ b/test/DotRecast.Recast.Test/DotRecast.Recast.Test.csproj @@ -11,7 +11,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/DotRecast.Recast.Test/RecastTileMeshTest.cs b/test/DotRecast.Recast.Test/RecastTileMeshTest.cs index 8d98546..6fa4676 100644 --- a/test/DotRecast.Recast.Test/RecastTileMeshTest.cs +++ b/test/DotRecast.Recast.Test/RecastTileMeshTest.cs @@ -69,27 +69,27 @@ public class RecastTileMeshTest true, true, true, SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 7, 8); - RcBuilderResult rcResult = builder.Build(geom, bcfg); + RcBuilderResult rcResult = builder.Build(geom, bcfg, false); Assert.That(rcResult.Mesh.npolys, Is.EqualTo(1)); Assert.That(rcResult.Mesh.nverts, Is.EqualTo(5)); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 6, 9); - rcResult = builder.Build(geom, bcfg); + rcResult = builder.Build(geom, bcfg, false); Assert.That(rcResult.Mesh.npolys, Is.EqualTo(2)); Assert.That(rcResult.Mesh.nverts, Is.EqualTo(7)); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 2, 9); - rcResult = builder.Build(geom, bcfg); + rcResult = builder.Build(geom, bcfg, false); Assert.That(rcResult.Mesh.npolys, Is.EqualTo(2)); Assert.That(rcResult.Mesh.nverts, Is.EqualTo(9)); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 4, 3); - rcResult = builder.Build(geom, bcfg); + rcResult = builder.Build(geom, bcfg, false); Assert.That(rcResult.Mesh.npolys, Is.EqualTo(3)); Assert.That(rcResult.Mesh.nverts, Is.EqualTo(6)); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 2, 8); - rcResult = builder.Build(geom, bcfg); + rcResult = builder.Build(geom, bcfg, false); Assert.That(rcResult.Mesh.npolys, Is.EqualTo(5)); Assert.That(rcResult.Mesh.nverts, Is.EqualTo(17)); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 0, 8); - rcResult = builder.Build(geom, bcfg); + rcResult = builder.Build(geom, bcfg, false); Assert.That(rcResult.Mesh.npolys, Is.EqualTo(6)); Assert.That(rcResult.Mesh.nverts, Is.EqualTo(15)); }