forked from mirror/DotRecast
Limiting the number of tasks during build
This commit is contained in:
parent
573386c473
commit
82027dffd7
|
@ -97,7 +97,8 @@ namespace DotRecast.Recast.Toolset.Builder
|
||||||
filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans,
|
filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans,
|
||||||
SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true);
|
SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true);
|
||||||
RcBuilder rcBuilder = new RcBuilder();
|
RcBuilder rcBuilder = new RcBuilder();
|
||||||
return rcBuilder.BuildTiles(geom, cfg, Task.Factory);
|
var task = rcBuilder.BuildTilesAsync(geom, cfg, Environment.ProcessorCount + 1, Task.Factory);
|
||||||
|
return task.Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtNavMesh BuildNavMesh(IInputGeomProvider geom, List<DtMeshData> meshData, float cellSize, int tileSize, int vertsPerPoly)
|
public DtNavMesh BuildNavMesh(IInputGeomProvider geom, List<DtMeshData> meshData, float cellSize, int tileSize, int vertsPerPoly)
|
||||||
|
|
|
@ -19,7 +19,9 @@ freely, subject to the following restrictions:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
|
@ -45,115 +47,93 @@ namespace DotRecast.Recast
|
||||||
_progressListener = progressListener;
|
_progressListener = progressListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RcBuilderResult> BuildTiles(IInputGeomProvider geom, RcConfig cfg, TaskFactory taskFactory)
|
public Task<List<RcBuilderResult>> BuildTilesAsync(IInputGeomProvider geom, RcConfig cfg,
|
||||||
|
int threads = 0, TaskFactory taskFactory = null, CancellationToken cancellation = default)
|
||||||
{
|
{
|
||||||
RcVec3f bmin = geom.GetMeshBoundsMin();
|
RcVec3f bmin = geom.GetMeshBoundsMin();
|
||||||
RcVec3f bmax = geom.GetMeshBoundsMax();
|
RcVec3f bmax = geom.GetMeshBoundsMax();
|
||||||
CalcTileCount(bmin, bmax, cfg.Cs, cfg.TileSizeX, cfg.TileSizeZ, out var tw, out var th);
|
CalcTileCount(bmin, bmax, cfg.Cs, cfg.TileSizeX, cfg.TileSizeZ, out var tw, out var th);
|
||||||
List<RcBuilderResult> results = new List<RcBuilderResult>();
|
|
||||||
if (null != taskFactory)
|
if (1 < threads)
|
||||||
{
|
{
|
||||||
BuildMultiThreadAsync(geom, cfg, bmin, bmax, tw, th, results, taskFactory, default);
|
return BuildMultiThreadAsync(geom, cfg, bmin, bmax, tw, th, threads, taskFactory ?? Task.Factory, cancellation);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
var results = BuildSingleThread(geom, cfg, bmin, bmax, tw, th);
|
||||||
|
return Task.FromResult(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<RcBuilderResult> BuildSingleThread(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tw, int th)
|
||||||
|
{
|
||||||
|
var results = new List<RcBuilderResult>(th * tw);
|
||||||
|
RcAtomicInteger counter = new RcAtomicInteger(0);
|
||||||
|
|
||||||
|
for (int y = 0; y < th; ++y)
|
||||||
{
|
{
|
||||||
BuildSingleThreadAsync(geom, cfg, bmin, bmax, tw, th, results);
|
for (int x = 0; x < tw; ++x)
|
||||||
|
{
|
||||||
|
var result = BuildTile(geom, cfg, bmin, bmax, x, y, counter, tw * th);
|
||||||
|
results.Add(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<List<RcBuilderResult>> BuildMultiThreadAsync(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tw, int th,
|
||||||
public Task BuildTilesAsync(IInputGeomProvider geom, RcConfig cfg, int threads, List<RcBuilderResult> results, TaskFactory taskFactory, CancellationToken cancellationToken)
|
int threads, TaskFactory taskFactory, CancellationToken cancellation)
|
||||||
{
|
{
|
||||||
RcVec3f bmin = geom.GetMeshBoundsMin();
|
var results = new ConcurrentQueue<RcBuilderResult>();
|
||||||
RcVec3f bmax = geom.GetMeshBoundsMax();
|
RcAtomicInteger progress = new RcAtomicInteger(0);
|
||||||
CalcTileCount(bmin, bmax, cfg.Cs, cfg.TileSizeX, cfg.TileSizeZ, out var tw, out var th);
|
|
||||||
Task task;
|
|
||||||
if (1 < threads)
|
|
||||||
{
|
|
||||||
task = BuildMultiThreadAsync(geom, cfg, bmin, bmax, tw, th, results, taskFactory, cancellationToken);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
task = BuildSingleThreadAsync(geom, cfg, bmin, bmax, tw, th, results);
|
|
||||||
}
|
|
||||||
|
|
||||||
return task;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task BuildSingleThreadAsync(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax,
|
|
||||||
int tw, int th, List<RcBuilderResult> results)
|
|
||||||
{
|
|
||||||
RcAtomicInteger counter = new RcAtomicInteger(0);
|
|
||||||
for (int y = 0; y < th; ++y)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < tw; ++x)
|
|
||||||
{
|
|
||||||
results.Add(BuildTile(geom, cfg, bmin, bmax, x, y, counter, tw * th));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task BuildMultiThreadAsync(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax,
|
|
||||||
int tw, int th, List<RcBuilderResult> results, TaskFactory taskFactory, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
RcAtomicInteger counter = new RcAtomicInteger(0);
|
|
||||||
CountdownEvent latch = new CountdownEvent(tw * th);
|
|
||||||
List<Task> tasks = new List<Task>();
|
|
||||||
|
|
||||||
|
List<Task> limits = new List<Task>(threads);
|
||||||
for (int x = 0; x < tw; ++x)
|
for (int x = 0; x < tw; ++x)
|
||||||
{
|
{
|
||||||
for (int y = 0; y < th; ++y)
|
for (int y = 0; y < th; ++y)
|
||||||
{
|
{
|
||||||
int tx = x;
|
int tx = x;
|
||||||
int ty = y;
|
int ty = y;
|
||||||
var task = taskFactory.StartNew(() =>
|
var task = taskFactory.StartNew(state =>
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellation.IsCancellationRequested)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
RcBuilderResult tile = BuildTile(geom, cfg, bmin, bmax, tx, ty, counter, tw * th);
|
RcBuilderResult result = BuildTile(geom, cfg, bmin, bmax, tx, ty, progress, tw * th);
|
||||||
lock (results)
|
results.Enqueue(result);
|
||||||
{
|
|
||||||
results.Add(tile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Console.WriteLine(e);
|
Console.WriteLine(e);
|
||||||
}
|
}
|
||||||
|
}, null);
|
||||||
|
|
||||||
|
limits.Add(task);
|
||||||
latch.Signal();
|
if (threads <= limits.Count)
|
||||||
}, cancellationToken);
|
{
|
||||||
|
await Task.WhenAll(limits);
|
||||||
tasks.Add(task);
|
limits.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
if (0 < limits.Count)
|
||||||
{
|
|
||||||
latch.Wait();
|
|
||||||
}
|
|
||||||
catch (ThreadInterruptedException)
|
|
||||||
{
|
{
|
||||||
|
await Task.WhenAll(limits);
|
||||||
|
limits.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.WhenAll(tasks.ToArray());
|
var list = results.ToList();
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RcBuilderResult BuildTile(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tx,
|
public RcBuilderResult BuildTile(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tx, int ty, RcAtomicInteger progress, int total)
|
||||||
int ty, RcAtomicInteger counter, int total)
|
|
||||||
{
|
{
|
||||||
RcBuilderResult result = Build(geom, new RcBuilderConfig(cfg, bmin, bmax, tx, ty));
|
RcBuilderResult result = Build(geom, new RcBuilderConfig(cfg, bmin, bmax, tx, ty));
|
||||||
if (_progressListener != null)
|
if (_progressListener != null)
|
||||||
{
|
{
|
||||||
_progressListener.OnProgress(counter.IncrementAndGet(), total);
|
_progressListener.OnProgress(progress.IncrementAndGet(), total);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -205,7 +185,7 @@ namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
// Prepare for region partitioning, by calculating distance field along the walkable surface.
|
// Prepare for region partitioning, by calculating distance field along the walkable surface.
|
||||||
RcRegions.BuildDistanceField(ctx, chf);
|
RcRegions.BuildDistanceField(ctx, chf);
|
||||||
|
|
||||||
// Partition the walkable surface into simple regions without holes.
|
// Partition the walkable surface into simple regions without holes.
|
||||||
RcRegions.BuildRegions(ctx, chf, cfg.MinRegionArea, cfg.MergeRegionArea);
|
RcRegions.BuildRegions(ctx, chf, cfg.MinRegionArea, cfg.MergeRegionArea);
|
||||||
}
|
}
|
||||||
|
@ -298,7 +278,7 @@ namespace DotRecast.Recast
|
||||||
RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(ctx, geom, builderCfg);
|
RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(ctx, geom, builderCfg);
|
||||||
FilterHeightfield(ctx, solid, builderCfg.cfg);
|
FilterHeightfield(ctx, solid, builderCfg.cfg);
|
||||||
RcCompactHeightfield chf = BuildCompactHeightfield(ctx, geom, builderCfg.cfg, solid);
|
RcCompactHeightfield chf = BuildCompactHeightfield(ctx, geom, builderCfg.cfg, solid);
|
||||||
|
|
||||||
RcLayers.BuildHeightfieldLayers(ctx, chf, builderCfg.cfg.BorderSize, builderCfg.cfg.WalkableHeight, out var lset);
|
RcLayers.BuildHeightfieldLayers(ctx, chf, builderCfg.cfg.BorderSize, builderCfg.cfg.WalkableHeight, out var lset);
|
||||||
return lset;
|
return lset;
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,8 @@ public class TestTiledNavMeshBuilder
|
||||||
true, true, true,
|
true, true, true,
|
||||||
SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true);
|
SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true);
|
||||||
RcBuilder rcBuilder = new RcBuilder();
|
RcBuilder rcBuilder = new RcBuilder();
|
||||||
List<RcBuilderResult> rcResult = rcBuilder.BuildTiles(geom, cfg, null);
|
var task = rcBuilder.BuildTilesAsync(geom, cfg);
|
||||||
|
List<RcBuilderResult> rcResult = task.Result;
|
||||||
|
|
||||||
// Add tiles to nav mesh
|
// Add tiles to nav mesh
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@ using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Recast.Test;
|
namespace DotRecast.Recast.Test;
|
||||||
|
|
||||||
|
|
||||||
public class RecastTileMeshTest
|
public class RecastTileMeshTest
|
||||||
{
|
{
|
||||||
private const float m_cellSize = 0.3f;
|
private const float m_cellSize = 0.3f;
|
||||||
|
@ -138,8 +137,8 @@ public class RecastTileMeshTest
|
||||||
private void Build(IInputGeomProvider geom, RcBuilder builder, RcConfig cfg, int threads, bool validate)
|
private void Build(IInputGeomProvider geom, RcBuilder builder, RcConfig cfg, int threads, bool validate)
|
||||||
{
|
{
|
||||||
CancellationTokenSource cts = new CancellationTokenSource();
|
CancellationTokenSource cts = new CancellationTokenSource();
|
||||||
List<RcBuilderResult> tiles = new();
|
var task = builder.BuildTilesAsync(geom, cfg, threads, Task.Factory, cts.Token);
|
||||||
var task = builder.BuildTilesAsync(geom, cfg, threads, tiles, Task.Factory, cts.Token);
|
List<RcBuilderResult> tiles = task.Result;
|
||||||
if (validate)
|
if (validate)
|
||||||
{
|
{
|
||||||
RcBuilderResult rcResult = GetTile(tiles, 7, 8);
|
RcBuilderResult rcResult = GetTile(tiles, 7, 8);
|
||||||
|
|
Loading…
Reference in New Issue