world converter threading

This commit is contained in:
MihailRis 2024-04-15 19:44:21 +03:00
parent ab110dcdf5
commit cc58ea29bc
10 changed files with 122 additions and 63 deletions

View File

@ -208,7 +208,7 @@ const ResPaths* AssetsLoader::getPaths() const {
return paths; return paths;
} }
class LoaderWorker : public util::Worker<std::shared_ptr<aloader_entry>, assetload::postfunc> { class LoaderWorker : public util::Worker<aloader_entry, assetload::postfunc> {
AssetsLoader* loader; AssetsLoader* loader;
public: public:
LoaderWorker(AssetsLoader* loader) : loader(loader) { LoaderWorker(AssetsLoader* loader) : loader(loader) {
@ -222,7 +222,7 @@ public:
std::shared_ptr<Task> AssetsLoader::startTask(runnable onDone) { std::shared_ptr<Task> AssetsLoader::startTask(runnable onDone) {
auto pool = std::make_shared< auto pool = std::make_shared<
util::ThreadPool<std::shared_ptr<aloader_entry>, assetload::postfunc> util::ThreadPool<aloader_entry, assetload::postfunc>
>( >(
"assets-loader-pool", "assets-loader-pool",
[=](){return std::make_shared<LoaderWorker>(this);}, [=](){return std::make_shared<LoaderWorker>(this);},

View File

@ -11,16 +11,29 @@
#include "../content/ContentLUT.h" #include "../content/ContentLUT.h"
#include "../objects/Player.h" #include "../objects/Player.h"
#include "../debug/Logger.h" #include "../debug/Logger.h"
#include "../util/ThreadPool.h"
namespace fs = std::filesystem; namespace fs = std::filesystem;
static debug::Logger logger("world-converter"); static debug::Logger logger("world-converter");
class ConverterWorker : public util::Worker<convert_task, int> {
std::shared_ptr<WorldConverter> converter;
public:
ConverterWorker(std::shared_ptr<WorldConverter> converter)
: converter(converter) {}
int operator()(const std::shared_ptr<convert_task>& task) override {
converter->convert(*task);
return 0;
}
};
WorldConverter::WorldConverter( WorldConverter::WorldConverter(
fs::path folder, fs::path folder,
const Content* content, const Content* content,
std::shared_ptr<ContentLUT> lut std::shared_ptr<ContentLUT> lut
) : wfile(std::make_unique<WorldFiles>(folder, DebugSettings {})), ) : wfile(std::make_unique<WorldFiles>(folder)),
lut(lut), lut(lut),
content(content) content(content)
{ {
@ -38,7 +51,40 @@ WorldConverter::WorldConverter(
WorldConverter::~WorldConverter() { WorldConverter::~WorldConverter() {
} }
void WorldConverter::convertRegion(fs::path file) { std::shared_ptr<Task> WorldConverter::startTask(
fs::path folder,
const Content* content,
std::shared_ptr<ContentLUT> lut,
runnable onDone,
bool multithreading
) {
auto converter = std::make_shared<WorldConverter>(folder, content, lut);
if (!multithreading) {
converter->setOnComplete([=]() {
converter->write();
onDone();
});
return converter;
}
auto pool = std::make_shared<util::ThreadPool<convert_task, int>>(
"converter-pool",
[=](){return std::make_shared<ConverterWorker>(converter);},
[=](int& _) {}
);
while (!converter->tasks.empty()) {
const convert_task& task = converter->tasks.front();
auto ptr = std::make_shared<convert_task>(task);
pool->enqueueJob(ptr);
converter->tasks.pop();
}
pool->setOnComplete([=]() {
converter->write();
onDone();
});
return pool;
}
void WorldConverter::convertRegion(fs::path file) const {
int x, z; int x, z;
std::string name = file.stem().string(); std::string name = file.stem().string();
if (!WorldRegions::parseRegionFilename(name, x, z)) { if (!WorldRegions::parseRegionFilename(name, x, z)) {
@ -54,13 +100,27 @@ void WorldConverter::convertRegion(fs::path file) {
}); });
} }
void WorldConverter::convertPlayer(fs::path file) { void WorldConverter::convertPlayer(fs::path file) const {
logger.info() << "converting player " << file.u8string(); logger.info() << "converting player " << file.u8string();
auto map = files::read_json(file); auto map = files::read_json(file);
Player::convert(map.get(), lut.get()); Player::convert(map.get(), lut.get());
files::write_json(file, map.get()); files::write_json(file, map.get());
} }
void WorldConverter::convert(convert_task task) const {
if (!fs::is_regular_file(task.file))
return;
switch (task.type) {
case convert_task_type::region:
convertRegion(task.file);
break;
case convert_task_type::player:
convertPlayer(task.file);
break;
}
}
void WorldConverter::convertNext() { void WorldConverter::convertNext() {
if (tasks.empty()) { if (tasks.empty()) {
throw std::runtime_error("no more regions to convert"); throw std::runtime_error("no more regions to convert");
@ -69,18 +129,28 @@ void WorldConverter::convertNext() {
tasks.pop(); tasks.pop();
tasksDone++; tasksDone++;
if (!fs::is_regular_file(task.file)) convert(task);
return; }
switch (task.type) {
case convert_task_type::region: void WorldConverter::setOnComplete(runnable callback) {
convertRegion(task.file); this->onComplete = callback;
break; }
case convert_task_type::player:
convertPlayer(task.file); void WorldConverter::update() {
break; convertNext();
if (onComplete && tasks.empty()) {
onComplete();
} }
} }
void WorldConverter::terminate() {
tasks = {};
}
bool WorldConverter::isActive() const {
return !tasks.empty();
}
void WorldConverter::write() { void WorldConverter::write() {
logger.info() << "writing world"; logger.info() << "writing world";
wfile->write(nullptr, content); wfile->write(nullptr, content);
@ -92,8 +162,8 @@ void WorldConverter::waitForEnd() {
} }
} }
uint WorldConverter::getWorkRemaining() const { uint WorldConverter::getWorkTotal() const {
return tasks.size(); return tasks.size() + tasksDone;
} }
uint WorldConverter::getWorkDone() const { uint WorldConverter::getWorkDone() const {

View File

@ -32,41 +32,35 @@ class WorldConverter : public Task {
runnable onComplete; runnable onComplete;
uint tasksDone = 0; uint tasksDone = 0;
void convertPlayer(fs::path file); void convertPlayer(fs::path file) const;
void convertRegion(fs::path file); void convertRegion(fs::path file) const;
public: public:
WorldConverter( WorldConverter(
fs::path folder, const Content* content, fs::path folder,
const Content* content,
std::shared_ptr<ContentLUT> lut std::shared_ptr<ContentLUT> lut
); );
~WorldConverter(); ~WorldConverter();
void convert(convert_task task) const;
void convertNext(); void convertNext();
void setOnComplete(runnable callback);
void setOnComplete(runnable callback) {
this->onComplete = callback;
}
void update() override {
convertNext();
if (onComplete && tasks.empty()) {
onComplete();
}
}
void terminate() override {
tasks = {};
}
bool isActive() const override {
return !tasks.empty();
}
void waitForEnd() override;
void write(); void write();
uint getWorkRemaining() const override; void update() override;
void terminate() override;
bool isActive() const override;
void waitForEnd() override;
uint getWorkTotal() const override;
uint getWorkDone() const override; uint getWorkDone() const override;
static std::shared_ptr<Task> startTask(
fs::path folder,
const Content* content,
std::shared_ptr<ContentLUT> lut,
runnable onDone,
bool multithreading
);
}; };
#endif // FILES_WORLD_CONVERTER_H_ #endif // FILES_WORLD_CONVERTER_H_

View File

@ -207,7 +207,7 @@ ubyte* WorldRegions::getData(
std::shared_ptr<regfile> WorldRegions::useRegFile(glm::ivec3 coord) { std::shared_ptr<regfile> WorldRegions::useRegFile(glm::ivec3 coord) {
auto* file = openRegFiles[coord].get(); auto* file = openRegFiles[coord].get();
file->inUse = true; file->inUse = true;
return std::shared_ptr<regfile>(openRegFiles[coord].get(), [this](regfile* ptr) { return std::shared_ptr<regfile>(file, [this](regfile* ptr) {
ptr->inUse = false; ptr->inUse = false;
regFilesCv.notify_one(); regFilesCv.notify_one();
}); });

View File

@ -116,7 +116,7 @@ void show_process_panel(Engine* engine, std::shared_ptr<Task> task, std::wstring
auto label = std::make_shared<Label>(L"0%"); auto label = std::make_shared<Label>(L"0%");
panel->add(label); panel->add(label);
uint initialWork = task->getWorkRemaining(); uint initialWork = task->getWorkTotal();
panel->listenInterval(0.01f, [=]() { panel->listenInterval(0.01f, [=]() {
task->update(); task->update();
@ -134,25 +134,21 @@ void show_process_panel(Engine* engine, std::shared_ptr<Task> task, std::wstring
menu->setPage("process", false); menu->setPage("process", false);
} }
std::shared_ptr<WorldConverter> create_converter( std::shared_ptr<Task> create_converter(
Engine* engine, Engine* engine,
fs::path folder, fs::path folder,
const Content* content, const Content* content,
std::shared_ptr<ContentLUT> lut, std::shared_ptr<ContentLUT> lut,
runnable postRunnable) runnable postRunnable)
{ {
auto converter = std::make_shared<WorldConverter>(folder, content, lut); return WorldConverter::startTask(folder, content, lut, [=](){
converter->setOnComplete([=](){
converter->write();
auto menu = engine->getGUI()->getMenu(); auto menu = engine->getGUI()->getMenu();
menu->reset(); menu->reset();
menu->setPage("main", false); menu->setPage("main", false);
engine->getGUI()->postRunnable([=]() { engine->getGUI()->postRunnable([=]() {
postRunnable(); postRunnable();
}); });
}); }, true);
return converter;
} }
void show_convert_request( void show_convert_request(

View File

@ -34,7 +34,7 @@ static void create_controls_panel(Engine* engine) {
} }
auto scrollPanel = std::dynamic_pointer_cast<Panel>(guiutil::create( auto scrollPanel = std::dynamic_pointer_cast<Panel>(guiutil::create(
"<panel size='400,200' padding='2' interval='1' max-length='400' color='#0000004C'>" "<panel size='380,200' padding='2' interval='1' max-length='400' color='#0000004C'>"
"</panel>" "</panel>"
)); ));
for (auto& entry : Events::bindings){ for (auto& entry : Events::bindings){
@ -55,7 +55,6 @@ static void create_controls_panel(Engine* engine) {
} }
void menus::create_settings_panel(Engine* engine) { void menus::create_settings_panel(Engine* engine) {
//create_audio_settings_panel(engine);
create_controls_panel(engine); create_controls_panel(engine);
auto menu = engine->getGUI()->getMenu(); auto menu = engine->getGUI()->getMenu();

View File

@ -14,7 +14,7 @@ static debug::Logger logger("chunks-render");
const uint RENDERER_CAPACITY = 9 * 6 * 6 * 3000; const uint RENDERER_CAPACITY = 9 * 6 * 6 * 3000;
class RendererWorker : public util::Worker<std::shared_ptr<Chunk>, RendererResult> { class RendererWorker : public util::Worker<Chunk, RendererResult> {
Level* level; Level* level;
BlocksRenderer renderer; BlocksRenderer renderer;
public: public:

View File

@ -29,7 +29,7 @@ class ChunksRenderer {
std::unordered_map<glm::ivec2, std::shared_ptr<Mesh>> meshes; std::unordered_map<glm::ivec2, std::shared_ptr<Mesh>> meshes;
std::unordered_map<glm::ivec2, bool> inwork; std::unordered_map<glm::ivec2, bool> inwork;
util::ThreadPool<std::shared_ptr<Chunk>, RendererResult> threadPool; util::ThreadPool<Chunk, RendererResult> threadPool;
public: public:
ChunksRenderer( ChunksRenderer(
Level* level, Level* level,

View File

@ -10,7 +10,7 @@ public:
virtual ~Task() {} virtual ~Task() {}
virtual bool isActive() const = 0; virtual bool isActive() const = 0;
virtual uint getWorkRemaining() const = 0; virtual uint getWorkTotal() const = 0;
virtual uint getWorkDone() const = 0; virtual uint getWorkDone() const = 0;
virtual void update() = 0; virtual void update() = 0;
virtual void waitForEnd() = 0; virtual void waitForEnd() = 0;

View File

@ -17,7 +17,7 @@ namespace util {
template<class J, class T> template<class J, class T>
struct ThreadPoolResult { struct ThreadPoolResult {
J job; std::shared_ptr<J> job;
std::condition_variable& variable; std::condition_variable& variable;
int workerIndex; int workerIndex;
bool& locked; bool& locked;
@ -29,13 +29,13 @@ class Worker {
public: public:
Worker() {} Worker() {}
virtual ~Worker() {} virtual ~Worker() {}
virtual R operator()(const T&) = 0; virtual R operator()(const std::shared_ptr<T>&) = 0;
}; };
template<class T, class R> template<class T, class R>
class ThreadPool : public Task { class ThreadPool : public Task {
debug::Logger logger; debug::Logger logger;
std::queue<T> jobs; std::queue<std::shared_ptr<T>> jobs;
std::queue<ThreadPoolResult<T, R>> results; std::queue<ThreadPoolResult<T, R>> results;
std::mutex resultsMutex; std::mutex resultsMutex;
std::vector<std::thread> threads; std::vector<std::thread> threads;
@ -43,7 +43,7 @@ class ThreadPool : public Task {
std::mutex jobsMutex; std::mutex jobsMutex;
std::vector<std::unique_lock<std::mutex>> workersBlocked; std::vector<std::unique_lock<std::mutex>> workersBlocked;
consumer<R&> resultConsumer; consumer<R&> resultConsumer;
consumer<T&> onJobFailed = nullptr; consumer<std::shared_ptr<T>&> onJobFailed = nullptr;
runnable onComplete = nullptr; runnable onComplete = nullptr;
std::atomic<int> busyWorkers = 0; std::atomic<int> busyWorkers = 0;
std::atomic<uint> jobsDone = 0; std::atomic<uint> jobsDone = 0;
@ -57,7 +57,7 @@ class ThreadPool : public Task {
std::mutex mutex; std::mutex mutex;
bool locked = false; bool locked = false;
while (working) { while (working) {
T job; std::shared_ptr<T> job;
{ {
std::unique_lock<std::mutex> lock(jobsMutex); std::unique_lock<std::mutex> lock(jobsMutex);
jobsMutexCondition.wait(lock, [this] { jobsMutexCondition.wait(lock, [this] {
@ -199,7 +199,7 @@ public:
} }
} }
void enqueueJob(T job) { void enqueueJob(std::shared_ptr<T> job) {
{ {
std::lock_guard<std::mutex> lock(jobsMutex); std::lock_guard<std::mutex> lock(jobsMutex);
jobs.push(job); jobs.push(job);
@ -228,8 +228,8 @@ public:
this->onComplete = callback; this->onComplete = callback;
} }
uint getWorkRemaining() const override { uint getWorkTotal() const override {
return jobs.size(); return jobs.size()+jobsDone+busyWorkers;
} }
uint getWorkDone() const override { uint getWorkDone() const override {