Skip to content

Commit 9efef81

Browse files
committed
Merge branch 'navmeshtool_worldspaces' into 'master'
Somewhat reduce navmeshtool peak memory usage See merge request OpenMW/openmw!5076
2 parents 48ee222 + dff8fa1 commit 9efef81

File tree

6 files changed

+300
-142
lines changed

6 files changed

+300
-142
lines changed

apps/navmeshtool/main.cpp

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <components/resource/imagemanager.hpp>
2525
#include <components/resource/niffilemanager.hpp>
2626
#include <components/resource/scenemanager.hpp>
27+
#include <components/sceneutil/workqueue.hpp>
2728
#include <components/settings/values.hpp>
2829
#include <components/toutf8/toutf8.hpp>
2930
#include <components/version/version.hpp>
@@ -39,9 +40,9 @@
3940
#include <filesystem>
4041
#include <iostream>
4142
#include <map>
43+
#include <regex>
4244
#include <string>
4345
#include <thread>
44-
#include <type_traits>
4546
#include <utility>
4647
#include <vector>
4748

@@ -119,6 +120,10 @@ namespace NavMeshTool
119120
addOption("write-binary-log", bpo::value<bool>()->implicit_value(true)->default_value(false),
120121
"write progress in binary messages to be consumed by the launcher");
121122

123+
addOption("worldspace-filter", bpo::value<std::string>()->default_value(".*"),
124+
"Regular expression to filter in specified worldspaces in modified ECMAScript grammar (see "
125+
"https://en.cppreference.com/w/cpp/regex/ecmascript.html)");
126+
122127
Files::ConfigurationManager::addCommonOptions(result);
123128

124129
return result;
@@ -180,6 +185,8 @@ namespace NavMeshTool
180185
const bool removeUnusedTiles = variables["remove-unused-tiles"].as<bool>();
181186
const bool writeBinaryLog = variables["write-binary-log"].as<bool>();
182187

188+
const std::regex worldspaceFilter(variables["worldspace-filter"].as<std::string>());
189+
183190
#ifdef WIN32
184191
if (writeBinaryLog)
185192
_setmode(_fileno(stderr), _O_BINARY);
@@ -229,11 +236,42 @@ namespace NavMeshTool
229236
navigatorSettings.mRecast.mSwimHeightScale
230237
= EsmLoader::getGameSetting(esmData.mGameSettings, "fSwimHeightScale").getFloat();
231238

232-
WorldspaceData cellsData = gatherWorldspaceData(
233-
navigatorSettings, readers, vfs, bulletShapeManager, esmData, processInteriorCells, writeBinaryLog);
239+
const std::unordered_map<ESM::RefId, std::vector<std::size_t>> worldspaceCells
240+
= collectWorldspaceCells(esmData, processInteriorCells, worldspaceFilter);
241+
242+
Status status = Status::Ok;
243+
bool needVacuum = false;
244+
std::size_t count = 0;
245+
246+
SceneUtil::WorkQueue workQueue(threadsNumber);
247+
248+
Log(Debug::Info) << "Using " << threadsNumber << " parallel workers...";
249+
250+
for (const auto& [worldspace, cells] : worldspaceCells)
251+
{
252+
const WorldspaceData worldspaceData = gatherWorldspaceData(
253+
navigatorSettings, readers, vfs, bulletShapeManager, esmData, writeBinaryLog, worldspace, cells);
254+
255+
const Result result = generateAllNavMeshTiles(
256+
agentBounds, navigatorSettings, removeUnusedTiles, writeBinaryLog, worldspaceData, db, workQueue);
234257

235-
const Status status = generateAllNavMeshTiles(agentBounds, navigatorSettings, threadsNumber,
236-
removeUnusedTiles, writeBinaryLog, cellsData, std::move(db));
258+
++count;
259+
260+
Log(Debug::Info) << "Processed worldspace (" << count << "/" << worldspaceCells.size() << ") "
261+
<< worldspace;
262+
263+
status = result.mStatus;
264+
needVacuum = needVacuum || result.mNeedVacuum;
265+
266+
if (status != Status::Ok)
267+
break;
268+
}
269+
270+
if (status == Status::Ok && needVacuum)
271+
{
272+
Log(Debug::Info) << "Vacuuming the database...";
273+
db.vacuum();
274+
}
237275

238276
switch (status)
239277
{

apps/navmeshtool/navmesh.cpp

Lines changed: 25 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
#include <cstddef>
2727
#include <random>
2828
#include <string_view>
29-
#include <utility>
3029
#include <vector>
3130

3231
namespace NavMeshTool
@@ -78,8 +77,8 @@ namespace NavMeshTool
7877
public:
7978
std::atomic_size_t mExpected{ 0 };
8079

81-
explicit NavMeshTileConsumer(NavMeshDb&& db, bool removeUnusedTiles, bool writeBinaryLog)
82-
: mDb(std::move(db))
80+
explicit NavMeshTileConsumer(NavMeshDb& db, bool removeUnusedTiles, bool writeBinaryLog)
81+
: mDb(db)
8382
, mRemoveUnusedTiles(removeUnusedTiles)
8483
, mWriteBinaryLog(writeBinaryLog)
8584
, mTransaction(mDb.startTransaction(Sqlite3::TransactionMode::Immediate))
@@ -211,12 +210,6 @@ namespace NavMeshTool
211210
mTransaction.commit();
212211
}
213212

214-
void vacuum()
215-
{
216-
const std::lock_guard lock(mMutex);
217-
mDb.vacuum();
218-
}
219-
220213
void removeTilesOutsideRange(ESM::RefId worldspace, const TilesPositionsRange& range)
221214
{
222215
const std::lock_guard lock(mMutex);
@@ -233,7 +226,7 @@ namespace NavMeshTool
233226
std::size_t mDeleted = 0;
234227
Status mStatus = Status::Ok;
235228
mutable std::mutex mMutex;
236-
NavMeshDb mDb;
229+
NavMeshDb& mDb;
237230
const bool mRemoveUnusedTiles;
238231
const bool mWriteBinaryLog;
239232
Transaction mTransaction;
@@ -254,45 +247,39 @@ namespace NavMeshTool
254247
};
255248
}
256249

257-
Status generateAllNavMeshTiles(const AgentBounds& agentBounds, const Settings& settings, std::size_t threadsNumber,
258-
bool removeUnusedTiles, bool writeBinaryLog, WorldspaceData& data, NavMeshDb&& db)
250+
Result generateAllNavMeshTiles(const AgentBounds& agentBounds, const Settings& settings, bool removeUnusedTiles,
251+
bool writeBinaryLog, const WorldspaceData& data, NavMeshDb& db, SceneUtil::WorkQueue& workQueue)
259252
{
260-
Log(Debug::Info) << "Generating navmesh tiles by " << threadsNumber << " parallel workers...";
253+
Log(Debug::Info) << "Generating navmesh tiles for " << data.mWorldspace << " worldspace...";
261254

262-
SceneUtil::WorkQueue workQueue(threadsNumber);
263-
auto navMeshTileConsumer
264-
= std::make_shared<NavMeshTileConsumer>(std::move(db), removeUnusedTiles, writeBinaryLog);
265-
std::size_t tiles = 0;
266-
std::mt19937_64 random;
255+
auto navMeshTileConsumer = std::make_shared<NavMeshTileConsumer>(db, removeUnusedTiles, writeBinaryLog);
267256

268-
for (const std::unique_ptr<WorldspaceNavMeshInput>& input : data.mNavMeshInputs)
269-
{
270-
const auto range = DetourNavigator::makeTilesPositionsRange(Misc::Convert::toOsgXY(input->mAabb.m_min),
271-
Misc::Convert::toOsgXY(input->mAabb.m_max), settings.mRecast);
272-
273-
if (removeUnusedTiles)
274-
navMeshTileConsumer->removeTilesOutsideRange(input->mWorldspace, range);
257+
const auto range = DetourNavigator::makeTilesPositionsRange(
258+
Misc::Convert::toOsgXY(data.mAabb.m_min), Misc::Convert::toOsgXY(data.mAabb.m_max), settings.mRecast);
275259

276-
std::vector<TilePosition> worldspaceTiles;
260+
if (removeUnusedTiles)
261+
navMeshTileConsumer->removeTilesOutsideRange(data.mWorldspace, range);
277262

278-
DetourNavigator::getTilesPositions(
279-
range, [&](const TilePosition& tilePosition) { worldspaceTiles.push_back(tilePosition); });
263+
std::vector<TilePosition> worldspaceTiles = data.mTiles;
280264

281-
tiles += worldspaceTiles.size();
265+
{
266+
const std::size_t tiles = worldspaceTiles.size();
282267

283268
if (writeBinaryLog)
284269
serializeToStderr(ExpectedTiles{ static_cast<std::uint64_t>(tiles) });
285270

286271
navMeshTileConsumer->mExpected = tiles;
272+
}
287273

274+
{
275+
std::mt19937_64 random;
288276
std::shuffle(worldspaceTiles.begin(), worldspaceTiles.end(), random);
289-
290-
for (const TilePosition& tilePosition : worldspaceTiles)
291-
workQueue.addWorkItem(new GenerateNavMeshTile(input->mWorldspace, tilePosition,
292-
RecastMeshProvider(input->mTileCachedRecastMeshManager), agentBounds, settings,
293-
navMeshTileConsumer));
294277
}
295278

279+
for (const TilePosition& tilePosition : worldspaceTiles)
280+
workQueue.addWorkItem(new GenerateNavMeshTile(data.mWorldspace, tilePosition,
281+
RecastMeshProvider(*data.mTileCachedRecastMeshManager), agentBounds, settings, navMeshTileConsumer));
282+
296283
const Status status = navMeshTileConsumer->wait();
297284
if (status == Status::Ok)
298285
navMeshTileConsumer->commit();
@@ -304,12 +291,9 @@ namespace NavMeshTool
304291
Log(Debug::Info) << "Generated navmesh for " << navMeshTileConsumer->getProvided() << " tiles, " << inserted
305292
<< " are inserted, " << updated << " updated and " << deleted << " deleted";
306293

307-
if (inserted + updated + deleted > 0)
308-
{
309-
Log(Debug::Info) << "Vacuuming the database...";
310-
navMeshTileConsumer->vacuum();
311-
}
312-
313-
return status;
294+
return Result{
295+
.mStatus = status,
296+
.mNeedVacuum = inserted + updated + deleted > 0,
297+
};
314298
}
315299
}

apps/navmeshtool/navmesh.hpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
#ifndef OPENMW_NAVMESHTOOL_NAVMESH_H
22
#define OPENMW_NAVMESHTOOL_NAVMESH_H
33

4-
#include <cstddef>
5-
64
namespace DetourNavigator
75
{
86
class NavMeshDb;
97
struct Settings;
108
struct AgentBounds;
119
}
1210

11+
namespace SceneUtil
12+
{
13+
class WorkQueue;
14+
}
15+
1316
namespace NavMeshTool
1417
{
1518
struct WorldspaceData;
@@ -21,9 +24,15 @@ namespace NavMeshTool
2124
NotEnoughSpace,
2225
};
2326

24-
Status generateAllNavMeshTiles(const DetourNavigator::AgentBounds& agentBounds,
25-
const DetourNavigator::Settings& settings, std::size_t threadsNumber, bool removeUnusedTiles,
26-
bool writeBinaryLog, WorldspaceData& cellsData, DetourNavigator::NavMeshDb&& db);
27+
struct Result
28+
{
29+
Status mStatus;
30+
bool mNeedVacuum;
31+
};
32+
33+
Result generateAllNavMeshTiles(const DetourNavigator::AgentBounds& agentBounds,
34+
const DetourNavigator::Settings& settings, bool removeUnusedTiles, bool writeBinaryLog,
35+
const WorldspaceData& data, DetourNavigator::NavMeshDb& db, SceneUtil::WorkQueue& workQueue);
2736
}
2837

2938
#endif

0 commit comments

Comments
 (0)