metaforce/hecl/include/hecl/ClientProcess.hpp

111 lines
3.6 KiB
C++

#pragma once
#include <condition_variable>
#include <cstddef>
#include <functional>
#include <list>
#include <memory>
#include <mutex>
#include <thread>
#include "hecl/Blender/Token.hpp"
#include "hecl/hecl.hpp"
#include "hecl/SystemChar.hpp"
#include <boo/ThreadLocalPtr.hpp>
namespace hecl::Database {
class IDataSpec;
}
namespace hecl {
class MultiProgressPrinter;
extern int CpuCountOverride;
void SetCpuCountOverride(int argc, const SystemChar** argv);
class ClientProcess {
std::mutex m_mutex;
std::condition_variable m_cv;
std::condition_variable m_initCv;
std::condition_variable m_waitCv;
const MultiProgressPrinter* m_progPrinter;
int m_completedCooks = 0;
int m_addedCooks = 0;
public:
struct Transaction {
ClientProcess& m_parent;
enum class Type { Buffer, Cook, Lambda } m_type;
bool m_complete = false;
virtual void run(blender::Token& btok) = 0;
Transaction(ClientProcess& parent, Type tp) : m_parent(parent), m_type(tp) {}
};
struct BufferTransaction final : Transaction {
ProjectPath m_path;
void* m_targetBuf;
size_t m_maxLen;
size_t m_offset;
void run(blender::Token& btok) override;
BufferTransaction(ClientProcess& parent, const ProjectPath& path, void* target, size_t maxLen, size_t offset)
: Transaction(parent, Type::Buffer), m_path(path), m_targetBuf(target), m_maxLen(maxLen), m_offset(offset) {}
};
struct CookTransaction final : Transaction {
ProjectPath m_path;
Database::IDataSpec* m_dataSpec;
bool m_returnResult = false;
bool m_force;
bool m_fast;
void run(blender::Token& btok) override;
CookTransaction(ClientProcess& parent, const ProjectPath& path, bool force, bool fast, Database::IDataSpec* spec)
: Transaction(parent, Type::Cook), m_path(path), m_dataSpec(spec), m_force(force), m_fast(fast) {}
};
struct LambdaTransaction final : Transaction {
std::function<void(blender::Token&)> m_func;
void run(blender::Token& btok) override;
LambdaTransaction(ClientProcess& parent, std::function<void(blender::Token&)>&& func)
: Transaction(parent, Type::Lambda), m_func(std::move(func)) {}
};
private:
std::list<std::shared_ptr<Transaction>> m_pendingQueue;
std::list<std::shared_ptr<Transaction>> m_completedQueue;
int m_inProgress = 0;
bool m_running = true;
struct Worker {
ClientProcess& m_proc;
int m_idx;
std::thread m_thr;
blender::Token m_blendTok;
bool m_didInit = false;
Worker(ClientProcess& proc, int idx);
void proc();
};
std::vector<Worker> m_workers;
static ThreadLocalPtr<ClientProcess::Worker> ThreadWorker;
public:
ClientProcess(const MultiProgressPrinter* progPrinter = nullptr);
~ClientProcess() { shutdown(); }
std::shared_ptr<const BufferTransaction> addBufferTransaction(const hecl::ProjectPath& path, void* target,
size_t maxLen, size_t offset);
std::shared_ptr<const CookTransaction> addCookTransaction(const hecl::ProjectPath& path, bool force, bool fast,
Database::IDataSpec* spec);
std::shared_ptr<const LambdaTransaction> addLambdaTransaction(std::function<void(blender::Token&)>&& func);
bool syncCook(const hecl::ProjectPath& path, Database::IDataSpec* spec, blender::Token& btok, bool force, bool fast);
void swapCompletedQueue(std::list<std::shared_ptr<Transaction>>& queue);
void waitUntilComplete();
void shutdown();
bool isBusy() const { return m_pendingQueue.size() || m_inProgress; }
static int GetThreadWorkerIdx() {
Worker* w = ThreadWorker.get();
if (w)
return w->m_idx;
return -1;
}
};
} // namespace hecl