diff options
author | Subv <subv2112@gmail.com> | 2013-12-29 21:37:43 -0500 |
---|---|---|
committer | Subv <subv2112@gmail.com> | 2013-12-29 21:37:43 -0500 |
commit | 15d66d19b42759ccbb1900082c736a3953fcd3c9 (patch) | |
tree | c170a3c556363e22d164bea438aa1bae667816ac | |
parent | 473e4a7b7b72f5e316e0508d5232d4e96fa0168f (diff) |
Tools/MeshExtractor: Fixed the threading, threads should no longer behave in a weird way.
-rw-r--r-- | src/tools/mesh_extractor/ContinentBuilder.cpp | 143 | ||||
-rw-r--r-- | src/tools/mesh_extractor/ContinentBuilder.h | 63 |
2 files changed, 113 insertions, 93 deletions
diff --git a/src/tools/mesh_extractor/ContinentBuilder.cpp b/src/tools/mesh_extractor/ContinentBuilder.cpp index e2c5616db31..8321a7924a1 100644 --- a/src/tools/mesh_extractor/ContinentBuilder.cpp +++ b/src/tools/mesh_extractor/ContinentBuilder.cpp @@ -16,80 +16,13 @@ */ #include "ContinentBuilder.h" -#include "TileBuilder.h" #include "WDT.h" #include "Utils.h" #include "DetourNavMesh.h" #include "Cache.h" -#include "ace/Task.h" #include "Recast.h" #include "DetourCommon.h" -#include <ace/Atomic_Op.h> -#include <ace/Guard_T.h> -#include <ace/Synch.h> - -class BuilderThread : public ACE_Task_Base -{ -private: - ACE_Thread_Mutex lock; - int X, Y, MapId; - std::string Continent; - dtNavMeshParams Params; - ContinentBuilder* cBuilder; -public: - BuilderThread(ContinentBuilder* _cBuilder, dtNavMeshParams& params) : Params(params), cBuilder(_cBuilder), Free(true) {} - - void SetData(int x, int y, int map, const std::string& cont) - { - ACE_GUARD(ACE_Thread_Mutex, g, lock); - X = x; - Y = y; - MapId = map; - Continent = cont; - Free = false; - } - - int svc() - { - ACE_GUARD_RETURN(ACE_Thread_Mutex, g, lock, 0); - printf("[%02i,%02i] Building tile\n", X, Y); - TileBuilder builder(cBuilder, Continent, X, Y, MapId); - char buff[100]; - sprintf(buff, "mmaps/%03u%02i%02i.mmtile", MapId, Y, X); - FILE* f = fopen(buff, "r"); - if (f) // Check if file already exists. - { - printf("[%02i,%02i] Tile skipped, file already exists\n", X, Y); - fclose(f); - Free = true; - return 0; - } - uint8* nav = builder.BuildTiled(Params); - if (nav) - { - f = fopen(buff, "wb"); - if (!f) - { - printf("Could not create file %s. Check that you have write permissions to the destination folder and try again\n", buff); - return 0; - } - MmapTileHeader header; - Utils::InitializeMmapTileHeader(header); - header.size = builder.DataSize; - fwrite(&header, sizeof(MmapTileHeader), 1, f); - fwrite(nav, sizeof(unsigned char), builder.DataSize, f); - fclose(f); - } - dtFree(nav); - printf("[%02i,%02i] Tile Built!\n", X, Y); - Free = true; - return 0; - } - - ACE_Atomic_Op<ACE_Thread_Mutex, bool> Free; -}; - void ContinentBuilder::getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax) { // this is for elevation @@ -136,8 +69,6 @@ void ContinentBuilder::Build() dtNavMeshParams params; - std::vector<BuilderThread*> Threads; - if (TileMap->IsGlobalModel) { printf("Map %s ( %u ) is a WMO. Building with 1 thread.\n", Continent.c_str(), MapId); @@ -187,36 +118,62 @@ void ContinentBuilder::Build() fwrite(¶ms, sizeof(dtNavMeshParams), 1, mmap); fclose(mmap); - for (uint32 i = 0; i < NumberOfThreads; ++i) - Threads.push_back(new BuilderThread(this, params)); + std::vector<BuilderThread*> _threads; + BuilderThreadPool* pool = NumberOfThreads > 0 ? new BuilderThreadPool() : NULL; + printf("Map %s ( %u ) has %u tiles. Building them with %u threads\n", Continent.c_str(), MapId, uint32(TileMap->TileTable.size()), NumberOfThreads); + for (std::vector<TilePos>::iterator itr = TileMap->TileTable.begin(); itr != TileMap->TileTable.end(); ++itr) + pool->Enqueue(new TileBuildRequest(this, Continent, itr->X, itr->Y, MapId, params)); + + for (uint32 i = 0; i < NumberOfThreads; ++i) + _threads.push_back(new BuilderThread(this, pool->Queue())); + + // Free memory + for (std::vector<BuilderThread*>::iterator _th = _threads.begin(); _th != _threads.end(); ++_th) { - bool next = false; - while (!next) - { - for (std::vector<BuilderThread*>::iterator _th = Threads.begin(); _th != Threads.end(); ++_th) - { - if ((*_th)->Free.value()) - { - (*_th)->SetData(itr->X, itr->Y, MapId, Continent); - (*_th)->activate(); - next = true; - break; - } - } - // Wait for 20 seconds - ACE_OS::sleep(ACE_Time_Value (0, 20000)); - } + (*_th)->wait(); + delete *_th; } - } - // Free memory - for (std::vector<BuilderThread*>::iterator _th = Threads.begin(); _th != Threads.end(); ++_th) - { - (*_th)->wait(); - delete *_th; + delete pool; } Cache->Clear(); } + +int TileBuildRequest::call() +{ + printf("[%02i,%02i] Building tile\n", X, Y); + // Build the tile and return negative on error + TileBuilder tile(_builder, _continent, X, Y, _mapId); + char buff[100]; + sprintf(buff, "mmaps/%03u%02i%02i.mmtile", _mapId, Y, X); + FILE* f = fopen(buff, "r"); + if (f) // Check if file already exists. + { + printf("[%02i,%02i] Tile skipped, file already exists\n", X, Y); + fclose(f); + return 0; + } + uint8* nav = tile.BuildTiled(_params); + if (nav) + { + f = fopen(buff, "wb"); + if (!f) + { + printf("Could not create file %s. Check that you have write permissions to the destination folder and try again\n", buff); + dtFree(nav); + return -1; + } + MmapTileHeader header; + Utils::InitializeMmapTileHeader(header); + header.size = tile.DataSize; + fwrite(&header, sizeof(MmapTileHeader), 1, f); + fwrite(nav, sizeof(unsigned char), tile.DataSize, f); + fclose(f); + } + dtFree(nav); + printf("[%02i,%02i] Tile Built!\n", X, Y); + return 0; +} diff --git a/src/tools/mesh_extractor/ContinentBuilder.h b/src/tools/mesh_extractor/ContinentBuilder.h index 5349b8e1ba5..ce1eef9b642 100644 --- a/src/tools/mesh_extractor/ContinentBuilder.h +++ b/src/tools/mesh_extractor/ContinentBuilder.h @@ -17,9 +17,15 @@ #ifndef CONT_BUILDER_H #define CONT_BUILDER_H + #include <string> #include "WDT.h" #include "Define.h" +#include "TileBuilder.h" + +#include <ace/Task.h> +#include <ace/Activation_Queue.h> +#include <ace/Method_Request.h> class ContinentBuilder { @@ -44,4 +50,61 @@ private: int tileXMax; int tileYMax; }; + +class TileBuildRequest : public ACE_Method_Request +{ +public: + TileBuildRequest(ContinentBuilder* builder, std::string& continent, uint32 x, uint32 y, uint32 mapId, dtNavMeshParams& params) : _builder(builder), _continent(continent), X(x), Y(y), _mapId(mapId), _params(params) { } + + virtual int call(); + +private: + uint32 _mapId; + ContinentBuilder* _builder; + std::string& _continent; + uint32 X; + uint32 Y; + dtNavMeshParams& _params; +}; + +class BuilderThreadPool +{ +public: + BuilderThreadPool() : _queue(new ACE_Activation_Queue()) {} + ~BuilderThreadPool() { _queue->queue()->close(); delete _queue; } + + void Enqueue(TileBuildRequest* request) + { + _queue->enqueue(request); + } + + ACE_Activation_Queue* Queue() { return _queue; } + +private: + ACE_Activation_Queue* _queue; +}; + +class BuilderThread : public ACE_Task_Base +{ +private: + ContinentBuilder* _builder; + ACE_Activation_Queue* _queue; +public: + BuilderThread(ContinentBuilder* builder, ACE_Activation_Queue* queue) : _builder(builder), _queue(queue) { activate(); } + + int svc() + { + /// @ Set a timeout for dequeue attempts (only used when the queue is empty) as it will never get populated after thread starts + ACE_Time_Value timeout(5); + ACE_Method_Request* request = NULL; + while ((request = _queue->dequeue(&timeout)) != NULL) + { + request->call(); + delete request; + request = NULL; + } + return 0; + } +}; + #endif |