aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2024-07-06 12:56:59 +0200
committerShauren <shauren.trinity@gmail.com>2024-07-06 12:56:59 +0200
commit11a252e601522d840c5c2ceb3331495c51a2e5d3 (patch)
treee33c6a36874562c4ef986d54cc14ff1472eb851d
parenta0f13391a0404d859cf4f8b8dee0c801f2640473 (diff)
Tools/vmap_assembler: Multithread building vmaps
-rw-r--r--src/common/Threading/ThreadPool.h5
-rw-r--r--src/tools/vmap4_assembler/TileAssembler.cpp107
-rw-r--r--src/tools/vmap4_assembler/TileAssembler.h10
-rw-r--r--src/tools/vmap4_assembler/VMapAssembler.cpp12
4 files changed, 89 insertions, 45 deletions
diff --git a/src/common/Threading/ThreadPool.h b/src/common/Threading/ThreadPool.h
index 1606bf98d1e..c99bdf1af4d 100644
--- a/src/common/Threading/ThreadPool.h
+++ b/src/common/Threading/ThreadPool.h
@@ -40,6 +40,11 @@ public:
_impl.join();
}
+ void Stop()
+ {
+ _impl.stop();
+ }
+
private:
boost::asio::thread_pool _impl;
};
diff --git a/src/tools/vmap4_assembler/TileAssembler.cpp b/src/tools/vmap4_assembler/TileAssembler.cpp
index e0a3962cf2b..6be3e1b70b6 100644
--- a/src/tools/vmap4_assembler/TileAssembler.cpp
+++ b/src/tools/vmap4_assembler/TileAssembler.cpp
@@ -17,11 +17,13 @@
#include "TileAssembler.h"
#include "BoundingIntervalHierarchy.h"
+#include "Duration.h"
#include "IteratorPair.h"
#include "MapTree.h"
#include "Memory.h"
#include "StringConvert.h"
#include "StringFormat.h"
+#include "ThreadPool.h"
#include "VMapDefinitions.h"
#include <boost/filesystem/directory.hpp>
#include <boost/filesystem/operations.hpp>
@@ -43,8 +45,8 @@ namespace VMAP
//=================================================================
- TileAssembler::TileAssembler(std::string pSrcDirName, std::string pDestDirName)
- : iDestDir(std::move(pDestDirName)), iSrcDir(std::move(pSrcDirName))
+ TileAssembler::TileAssembler(std::string srcDirName, std::string destDirName, uint32 threads)
+ : iSrcDir(std::move(srcDirName)), iDestDir(std::move(destDirName)), iThreads(threads)
{
}
@@ -69,64 +71,95 @@ namespace VMAP
// else already exists - this is fine, continue
}
- std::deque<boost::filesystem::path> mapSpawnFiles;
+ // export Map data
+ Trinity::ThreadPool threadPool(iThreads);
+ bool aborted = false;
+ std::once_flag abortedFlag;
+ auto abortThreads = [&threadPool, &aborted, &abortedFlag]
+ {
+ std::call_once(abortedFlag, [&] { threadPool.Stop(); aborted = true; });
+ };
+
+ // Every worker thread gets its dedicated output container to avoid having to synchronize access
+ std::atomic<std::size_t> workerIndexGen;
+ std::vector<std::set<std::string>> spawnedModelFilesByThread(iThreads);
+
+ std::atomic<std::size_t> mapsToProcess;
+
for (boost::filesystem::directory_entry const& directoryEntry : dirBin)
{
if (!boost::filesystem::is_regular_file(directoryEntry))
continue;
- mapSpawnFiles.push_back(directoryEntry.path());
- }
+ ++mapsToProcess;
+ threadPool.PostWork([this, file = directoryEntry.path(), &abortThreads, &workerIndexGen, &spawnedModelFilesByThread, &mapsToProcess]
+ {
+ thread_local std::size_t workerIndex = workerIndexGen++;
+ --mapsToProcess;
- // export Map data
- while (!mapSpawnFiles.empty())
- {
- boost::filesystem::path file = std::move(mapSpawnFiles.front());
- mapSpawnFiles.pop_front();
+ auto dirf = Trinity::make_unique_ptr_with_deleter(fopen(file.string().c_str(), "rb"), &::fclose);
+ if (!dirf)
+ {
+ printf("Could not read dir_bin file!\n");
+ return abortThreads();
+ }
- auto dirf = Trinity::make_unique_ptr_with_deleter(fopen(file.string().c_str(), "rb"), &::fclose);
- if (!dirf)
- {
- printf("Could not read dir_bin file!\n");
- return false;
- }
+ Optional<uint32> mapId = Trinity::StringTo<uint32>(file.filename().string());
+ if (!mapId)
+ {
+ printf("Invalid Map ID %s\n", file.filename().string().c_str());
+ return abortThreads();
+ }
- Optional<uint32> mapId = Trinity::StringTo<uint32>(file.filename().string());
- if (!mapId)
- {
- printf("Invalid Map ID %s\n", file.filename().string().c_str());
- return false;
- }
+ printf("spawning Map %u\n", *mapId);
- printf("spawning Map %u\n", *mapId);
+ MapSpawns data;
+ data.MapId = *mapId;
+ if (!readMapSpawns(dirf.get(), &data))
+ return abortThreads();
- MapSpawns data;
- data.MapId = *mapId;
- if (!readMapSpawns(dirf.get(), &data))
- return false;
+ if (!convertMap(data))
+ return abortThreads();
- if (!convertMap(data))
- return false;
+ spawnedModelFilesByThread[workerIndex].merge(data.SpawnedModelFiles);
+ });
}
+ while (mapsToProcess && !aborted)
+ std::this_thread::sleep_for(1s);
+
+ if (aborted)
+ return false;
+
+ for (std::set<std::string>& modelsForThread : spawnedModelFilesByThread)
+ spawnedModelFiles.merge(modelsForThread);
+
// add an object models, listed in temp_gameobject_models file
exportGameobjectModels();
// export objects
printf("\nConverting Model Files\n");
for (std::string const& spawnedModelFile : spawnedModelFiles)
{
- printf("Converting %s\n", spawnedModelFile.c_str());
- if (!convertRawFile(spawnedModelFile))
+ threadPool.PostWork([&]
{
- printf("error converting %s\n", spawnedModelFile.c_str());
- break;
- }
+ printf("Converting %s\n", spawnedModelFile.c_str());
+ if (!convertRawFile(spawnedModelFile))
+ {
+ printf("error converting %s\n", spawnedModelFile.c_str());
+ abortThreads();
+ }
+ });
}
+ threadPool.Join();
+
+ if (aborted)
+ return false;
+
return true;
}
- bool TileAssembler::convertMap(MapSpawns& data)
+ bool TileAssembler::convertMap(MapSpawns& data) const
{
float constexpr invTileSize = 1.0f / 533.33333f;
@@ -142,7 +175,6 @@ namespace VMAP
continue;
mapSpawns.push_back(&spawn);
- spawnedModelFiles.insert(spawn.name);
std::map<uint32, std::set<uint32>>& tileEntries = (spawn.flags & MOD_PARENT_SPAWN) ? data.ParentTileEntries : data.TileEntries;
@@ -285,12 +317,13 @@ namespace VMAP
}
data->UniqueEntries.emplace(spawn.ID, spawn);
+ data->SpawnedModelFiles.insert(spawn.name);
}
return true;
}
- bool TileAssembler::calculateTransformedBound(ModelSpawn &spawn)
+ bool TileAssembler::calculateTransformedBound(ModelSpawn &spawn) const
{
std::string modelFilename(iSrcDir);
modelFilename.push_back('/');
diff --git a/src/tools/vmap4_assembler/TileAssembler.h b/src/tools/vmap4_assembler/TileAssembler.h
index f803793a5b5..3586a9daec6 100644
--- a/src/tools/vmap4_assembler/TileAssembler.h
+++ b/src/tools/vmap4_assembler/TileAssembler.h
@@ -56,6 +56,7 @@ namespace VMAP
{
uint32 MapId = 0;
std::map<uint32, ModelSpawn> UniqueEntries;
+ std::set<std::string> SpawnedModelFiles;
std::map<uint32 /*packedTileId*/, std::set<uint32 /*Id*/>> TileEntries;
std::map<uint32 /*packedTileId*/, std::set<uint32 /*Id*/>> ParentTileEntries;
};
@@ -92,17 +93,18 @@ namespace VMAP
class TileAssembler
{
private:
- std::string iDestDir;
std::string iSrcDir;
+ std::string iDestDir;
+ uint32 iThreads;
std::set<std::string> spawnedModelFiles;
public:
- TileAssembler(std::string pSrcDirName, std::string pDestDirName);
+ TileAssembler(std::string srcDirName, std::string destDirName, uint32 threads);
bool convertWorld2();
- bool convertMap(MapSpawns& data);
+ bool convertMap(MapSpawns& data) const;
static bool readMapSpawns(FILE* dirf, MapSpawns* data);
- bool calculateTransformedBound(ModelSpawn &spawn);
+ bool calculateTransformedBound(ModelSpawn &spawn) const;
void exportGameobjectModels();
bool convertRawFile(const std::string& pModelFilename);
diff --git a/src/tools/vmap4_assembler/VMapAssembler.cpp b/src/tools/vmap4_assembler/VMapAssembler.cpp
index b492b207879..9a4886b2919 100644
--- a/src/tools/vmap4_assembler/VMapAssembler.cpp
+++ b/src/tools/vmap4_assembler/VMapAssembler.cpp
@@ -24,6 +24,7 @@
#include <boost/program_options.hpp>
#include <iostream>
#include <string>
+#include <thread>
namespace po = boost::program_options;
@@ -34,9 +35,10 @@ namespace po = boost::program_options;
* @param [in] argv raw command line arguments
* @param [out] src raw data dir
* @param [out] dest vmap dest dir
+ * @param [out] threads number of threads to use
* @return Non-empty optional if program should exit immediately (holds exit code in that case)
*/
-Optional<int> HandleArgs(int argc, char* argv[], std::string* src, std::string* dest);
+Optional<int> HandleArgs(int argc, char* argv[], std::string* src, std::string* dest, uint32* threads);
int main(int argc, char* argv[])
{
@@ -45,14 +47,15 @@ int main(int argc, char* argv[])
Trinity::Locale::Init();
std::string src, dest;
- if (Optional<int> exitCode = HandleArgs(argc, argv, &src, &dest))
+ uint32 threads = 0;
+ if (Optional<int> exitCode = HandleArgs(argc, argv, &src, &dest, &threads))
return *exitCode;
Trinity::Banner::Show("VMAP assembler", [](char const* text) { std::cout << text << std::endl; }, nullptr);
std::cout << "using " << src << " as source directory and writing output to " << dest << std::endl;
- VMAP::TileAssembler ta(std::move(src), std::move(dest));
+ VMAP::TileAssembler ta(std::move(src), std::move(dest), threads);
if (!ta.convertWorld2())
{
@@ -64,10 +67,11 @@ int main(int argc, char* argv[])
return 0;
}
-Optional<int> HandleArgs(int argc, char* argv[], std::string* src, std::string* dest)
+Optional<int> HandleArgs(int argc, char* argv[], std::string* src, std::string* dest, uint32* threads)
{
po::options_description visible("Usage: vmap4assembler [OPTION]... [SRC] [DEST]\n\nWhere OPTION can be any of");
visible.add_options()
+ ("threads", po::value<uint32>(threads)->default_value(std::thread::hardware_concurrency()), "number of threads to use")
("help,h", "print usage message")
("version,v", "print version build info");