feat(Tools/MMapsGenerator): Improve multithreading of mmaps_generator (#10963)

* cherry-pick commit (699edaa014)

Co-authored-by: Giacomo Pozzoni <giacomopoz@gmail.com>
This commit is contained in:
IntelligentQuantum
2022-05-01 00:09:51 +04:30
committed by GitHub
parent 26c66e0d79
commit 769eea2cc0
5 changed files with 258 additions and 86 deletions

View File

@@ -26,15 +26,43 @@
namespace MMAP
{
TileBuilder::TileBuilder(MapBuilder* mapBuilder, bool skipLiquid, bool bigBaseUnit, bool debugOutput) :
m_bigBaseUnit(bigBaseUnit),
m_debugOutput(debugOutput),
m_mapBuilder(mapBuilder),
m_terrainBuilder(nullptr),
m_workerThread(&TileBuilder::WorkerThread, this),
m_rcContext(nullptr)
{
m_terrainBuilder = new TerrainBuilder(skipLiquid);
m_rcContext = new rcContext(false);
}
TileBuilder::~TileBuilder()
{
WaitCompletion();
delete m_terrainBuilder;
delete m_rcContext;
}
void TileBuilder::WaitCompletion()
{
if (m_workerThread.joinable())
m_workerThread.join();
}
MapBuilder::MapBuilder(Optional<float> maxWalkableAngle, Optional<float> maxWalkableAngleNotSteep, bool skipLiquid,
bool skipContinents, bool skipJunkMaps, bool skipBattlegrounds,
bool debugOutput, bool bigBaseUnit, int mapid, const char* offMeshFilePath) :
bool debugOutput, bool bigBaseUnit, int mapid, const char* offMeshFilePath, unsigned int threads) :
m_debugOutput (debugOutput),
m_offMeshFilePath (offMeshFilePath),
m_threads (threads),
m_skipContinents (skipContinents),
m_skipJunkMaps (skipJunkMaps),
m_skipBattlegrounds (skipBattlegrounds),
m_skipLiquid (skipLiquid),
m_maxWalkableAngle (maxWalkableAngle),
m_maxWalkableAngleNotSteep (maxWalkableAngleNotSteep),
m_bigBaseUnit (bigBaseUnit),
@@ -48,6 +76,9 @@ namespace MMAP
m_rcContext = new rcContext(false);
// At least 1 thread is needed
m_threads = std::max(1u, m_threads);
discoverTiles();
}
@@ -170,29 +201,26 @@ namespace MMAP
}
/**************************************************************************/
void MapBuilder::buildAllMaps(unsigned int threads)
void MapBuilder::buildMaps(Optional<uint32> mapID)
{
printf("Using %u threads to extract mmaps\n", threads);
printf("Using %u threads to generate mmaps\n", m_threads);
for (unsigned int i = 0; i < threads; ++i)
for (unsigned int i = 0; i < m_threads; ++i)
{
_workerThreads.emplace_back(&MapBuilder::WorkerThread, this);
m_tileBuilders.push_back(new TileBuilder(this, m_skipLiquid, m_bigBaseUnit, m_debugOutput));
}
m_tiles.sort([](MapTiles a, MapTiles b)
if (mapID)
{
return a.m_tiles->size() > b.m_tiles->size();
});
for (auto & m_tile : m_tiles)
buildMap(*mapID);
}
else
{
uint32 mapId = m_tile.m_mapId;
if (!shouldSkipMap(mapId))
// Build all maps if no map id has been specified
for (TileList::iterator it = m_tiles.begin(); it != m_tiles.end(); ++it)
{
if (threads > 0)
_queue.Push(mapId);
else
buildMap(mapId);
if (!shouldSkipMap(it->m_mapId))
buildMap(it->m_mapId);
}
}
@@ -205,10 +233,10 @@ namespace MMAP
_queue.Cancel();
for (auto& thread : _workerThreads)
{
thread.join();
}
for (auto& builder : m_tileBuilders)
delete builder;
m_tileBuilders.clear();
}
/**************************************************************************/
@@ -337,7 +365,8 @@ namespace MMAP
getTileBounds(tileX, tileY, data.solidVerts.getCArray(), data.solidVerts.size() / 3, bmin, bmax);
// build navmesh tile
buildMoveMapTile(mapId, tileX, tileY, data, bmin, bmax, navMesh);
TileBuilder tileBuilder = TileBuilder(this, m_skipLiquid, m_bigBaseUnit, m_debugOutput);
tileBuilder.buildMoveMapTile(mapId, tileX, tileY, data, bmin, bmax, navMesh);
fclose(file);
}
@@ -352,22 +381,39 @@ namespace MMAP
return;
}
buildTile(mapID, tileX, tileY, navMesh);
// ToDo: delete the old tile as the user clearly wants to rebuild it
TileBuilder tileBuilder = TileBuilder(this, m_skipLiquid, m_bigBaseUnit, m_debugOutput);
tileBuilder.buildTile(mapID, tileX, tileY, navMesh);
dtFreeNavMesh(navMesh);
_cancelationToken = true;
_queue.Cancel();
}
void MapBuilder::WorkerThread()
void TileBuilder::WorkerThread()
{
while (true)
{
uint32 mapId = 0;
TileInfo tileInfo;
_queue.WaitAndPop(mapId);
m_mapBuilder->_queue.WaitAndPop(tileInfo);
if (_cancelationToken)
if (m_mapBuilder->_cancelationToken)
return;
buildMap(mapId);
dtNavMesh* navMesh = dtAllocNavMesh();
if (!navMesh->init(&tileInfo.m_navMeshParams))
{
printf("[Map %04i] Failed creating navmesh for tile %i,%i !\n", tileInfo.m_mapId, tileInfo.m_tileX, tileInfo.m_tileY);
dtFreeNavMesh(navMesh);
return;
}
buildTile(tileInfo.m_mapId, tileInfo.m_tileX, tileInfo.m_tileY, navMesh);
dtFreeNavMesh(navMesh);
}
}
@@ -397,22 +443,28 @@ namespace MMAP
// unpack tile coords
StaticMapTree::unpackTileID(tile, tileX, tileY);
if (!shouldSkipTile(mapID, tileX, tileY))
buildTile(mapID, tileX, tileY, navMesh);
++m_totalTilesProcessed;
TileInfo tileInfo;
tileInfo.m_mapId = mapID;
tileInfo.m_tileX = tileX;
tileInfo.m_tileY = tileY;
memcpy(&tileInfo.m_navMeshParams, navMesh->getParams(), sizeof(dtNavMeshParams));
_queue.Push(tileInfo);
}
dtFreeNavMesh(navMesh);
}
printf("[Map %03i] Complete!\n", mapID);
}
/**************************************************************************/
void MapBuilder::buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh)
void TileBuilder::buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh)
{
printf("%u%% [Map %03i] Building tile [%02u,%02u]\n", percentageDone(m_totalTiles, m_totalTilesProcessed), mapID, tileX, tileY);
if(shouldSkipTile(mapID, tileX, tileY))
{
++m_mapBuilder->m_totalTilesProcessed;
return;
}
printf("%u%% [Map %04i] Building tile [%02u,%02u]\n", m_mapBuilder->currentPercentageDone(), mapID, tileX, tileY);
MeshData meshData;
@@ -424,7 +476,10 @@ namespace MMAP
// if there is no data, give up now
if (!meshData.solidVerts.size() && !meshData.liquidVerts.size())
{
++m_mapBuilder->m_totalTilesProcessed;
return;
}
// remove unused vertices
TerrainBuilder::cleanVertices(meshData.solidVerts, meshData.solidTris);
@@ -436,16 +491,21 @@ namespace MMAP
allVerts.append(meshData.solidVerts);
if (!allVerts.size())
{
++m_mapBuilder->m_totalTilesProcessed;
return;
}
// get bounds of current tile
float bmin[3], bmax[3];
getTileBounds(tileX, tileY, allVerts.getCArray(), allVerts.size() / 3, bmin, bmax);
m_mapBuilder->getTileBounds(tileX, tileY, allVerts.getCArray(), allVerts.size() / 3, bmin, bmax);
m_terrainBuilder->loadOffMeshConnections(mapID, tileX, tileY, meshData, m_offMeshFilePath);
m_terrainBuilder->loadOffMeshConnections(mapID, tileX, tileY, meshData, m_mapBuilder->m_offMeshFilePath);
// build navmesh tile
buildMoveMapTile(mapID, tileX, tileY, meshData, bmin, bmax, navMesh);
++m_mapBuilder->m_totalTilesProcessed;
}
/**************************************************************************/
@@ -524,7 +584,7 @@ namespace MMAP
}
/**************************************************************************/
void MapBuilder::buildMoveMapTile(uint32 mapID, uint32 tileX, uint32 tileY,
void TileBuilder::buildMoveMapTile(uint32 mapID, uint32 tileX, uint32 tileY,
MeshData& meshData, float bmin[3], float bmax[3],
dtNavMesh* navMesh)
{
@@ -549,7 +609,7 @@ namespace MMAP
const TileConfig tileConfig = TileConfig(m_bigBaseUnit);
int TILES_PER_MAP = tileConfig.TILES_PER_MAP;
float BASE_UNIT_DIM = tileConfig.BASE_UNIT_DIM;
rcConfig config = GetMapSpecificConfig(mapID, bmin, bmax, tileConfig);
rcConfig config = m_mapBuilder->GetMapSpecificConfig(mapID, bmin, bmax, tileConfig);
// this sets the dimensions of the heightfield - should maybe happen before border padding
rcCalcGridSize(config.bmin, config.bmax, config.cs, &config.width, &config.height);
@@ -852,7 +912,7 @@ namespace MMAP
}
/**************************************************************************/
void MapBuilder::getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax)
void MapBuilder::getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax) const
{
// this is for elevation
if (verts && vertCount)
@@ -871,7 +931,7 @@ namespace MMAP
}
/**************************************************************************/
bool MapBuilder::shouldSkipMap(uint32 mapID)
bool MapBuilder::shouldSkipMap(uint32 mapID) const
{
if (m_mapid >= 0)
return static_cast<uint32>(m_mapid) != mapID;
@@ -927,7 +987,7 @@ namespace MMAP
}
/**************************************************************************/
bool MapBuilder::isTransportMap(uint32 mapID)
bool MapBuilder::isTransportMap(uint32 mapID) const
{
switch (mapID)
{
@@ -967,7 +1027,7 @@ namespace MMAP
}
/**************************************************************************/
bool MapBuilder::shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY)
bool TileBuilder::shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY) const
{
char fileName[255];
sprintf(fileName, "mmaps/%03u%02i%02i.mmtile", mapID, tileY, tileX);
@@ -990,7 +1050,7 @@ namespace MMAP
return true;
}
rcConfig MapBuilder::GetMapSpecificConfig(uint32 mapID, float bmin[3], float bmax[3], const TileConfig &tileConfig)
rcConfig MapBuilder::GetMapSpecificConfig(uint32 mapID, float bmin[3], float bmax[3], const TileConfig &tileConfig) const
{
rcConfig config;
memset(&config, 0, sizeof(rcConfig));
@@ -1039,11 +1099,16 @@ namespace MMAP
}
/**************************************************************************/
uint32 MapBuilder::percentageDone(uint32 totalTiles, uint32 totalTilesBuilt)
uint32 MapBuilder::percentageDone(uint32 totalTiles, uint32 totalTilesBuilt) const
{
if (totalTiles)
return totalTilesBuilt * 100 / totalTiles;
return 0;
}
uint32 MapBuilder::currentPercentageDone() const
{
return percentageDone(m_totalTiles, m_totalTilesProcessed);
}
}