mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-19 19:22:49 +00:00
feat(ugc): processor=toolbox-blender in the UGC server
The processor setting and toolbox_* settings (Blender, LU-Toolbox- Standalone, add-ons folder, brick and work folders, device, threads, timeout). Models asking for toolbox-blender are made by the Blender worker when it can run, else natively, logged at start, when it changes and per make. /status has the worker's state; --make-model takes toolbox-blender too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -181,9 +181,40 @@ namespace {
|
||||
settings.icon.denoiseSamples = std::clamp(Setting<int32_t>("denoise_samples", 4), 1, 256);
|
||||
settings.icon.bakedAo = settings.ao.enabled ? std::clamp(settings.ao.strength, 0.0f, 1.0f) : 0.0f;
|
||||
settings.maxBricks = Setting<uint32_t>("max_model_bricks", 0);
|
||||
// What makes the models: native, or toolbox-blender (LU Toolbox in Blender, when it can run: ReadToolboxConfig)
|
||||
const auto processorName = Game::config->GetValue("processor");
|
||||
if (UgcProcessOptions::Contains(UgcProcessOptions::PROCESSOR, processorName)) settings.processor = processorName;
|
||||
return settings;
|
||||
}
|
||||
|
||||
// A path setting: relative ones are next to the server binaries; empty is `fallback` (empty: none)
|
||||
std::filesystem::path PathSetting(const std::string& key, const std::string& fallback = "") {
|
||||
const auto value = Game::config->GetValue(key).empty() ? fallback : Game::config->GetValue(key);
|
||||
if (value.empty()) return {};
|
||||
std::filesystem::path path(value);
|
||||
return path.is_relative() ? BinaryPathFinder::GetBinaryDir() / path : path;
|
||||
}
|
||||
|
||||
std::filesystem::path ResPath();
|
||||
|
||||
// LU Toolbox in a headless Blender (processor=toolbox-blender, docs/UgcServer.md "LU Toolbox in Blender"): the
|
||||
// external programs and folders it needs
|
||||
UgcToolbox::Config ReadToolboxConfig() {
|
||||
UgcToolbox::Config config;
|
||||
config.blender = PathSetting("toolbox_blender");
|
||||
config.standalone = PathSetting("toolbox_standalone_dir");
|
||||
config.scripts = PathSetting("toolbox_scripts_dir");
|
||||
config.worker = BinaryPathFinder::GetBinaryDir() / "ugc-toolbox" / "dlu_toolbox_worker.py";
|
||||
config.brickdb = PathSetting("toolbox_brickdb_dir", "toolbox-brickdb");
|
||||
config.work = PathSetting("toolbox_work_dir", "toolbox-work");
|
||||
config.res = ResPath();
|
||||
if (!Game::config->GetValue("toolbox_device").empty()) config.device = Game::config->GetValue("toolbox_device");
|
||||
config.threads = std::clamp(Setting<uint32_t>("toolbox_threads", 4), 1u, 256u);
|
||||
config.timeoutSeconds = std::clamp(Setting<uint32_t>("toolbox_timeout_seconds", 1800), 10u, 86400u);
|
||||
config.nice = std::clamp(Setting<int32_t>("worker_nice", 0), 0, 19);
|
||||
return config;
|
||||
}
|
||||
|
||||
// The processing options the settings pick, and what is used instead when this build or machine can't
|
||||
// (main thread: the GPU is set up here the first time)
|
||||
void LogProcessingOptions(const UgcJobs::Settings& settings) {
|
||||
@@ -195,6 +226,21 @@ namespace {
|
||||
if (!UgcRender::Available(settings.icon.denoise)) LOG("denoise=%s can't be used (the server was built without DLU_OIDN): off instead", std::string(UgcRender::Name(settings.icon.denoise)).c_str());
|
||||
}
|
||||
|
||||
// Whether LU Toolbox in Blender can be used, logged at start and when it changes (and the processor setting's
|
||||
// fallback): every make that asks for it and can't have it logs why too
|
||||
void LogToolbox(const UgcJobs::Settings& settings, const std::string& problem) {
|
||||
static std::optional<std::string> logged;
|
||||
if (logged && *logged == problem + settings.processor) return;
|
||||
logged = problem + settings.processor;
|
||||
if (problem.empty()) {
|
||||
LOG("toolbox-blender can be used%s", settings.processor == UgcProcessOptions::TOOLBOX_BLENDER ? " and makes the models (processor=toolbox-blender)" : "");
|
||||
} else if (settings.processor == UgcProcessOptions::TOOLBOX_BLENDER) {
|
||||
LOG("processor=toolbox-blender can't be used (%s): models are made natively", problem.c_str());
|
||||
} else {
|
||||
LOG("toolbox-blender can't be used (%s)", problem.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
UgcProcessor::Limits ReadLimits() {
|
||||
UgcProcessor::Limits limits;
|
||||
const auto cores = std::max<unsigned>(std::thread::hardware_concurrency(), 1);
|
||||
@@ -575,7 +621,7 @@ namespace {
|
||||
auto settings = ReadSettings();
|
||||
UgcProcessOptions::Choice choice;
|
||||
if (!UgcProcessOptions::Parse(options, choice)) {
|
||||
std::cerr << "Unknown processing options \"" << options << "\" (ray backend embree, hiprt or embree-gpu; denoise off or oidn)\n";
|
||||
std::cerr << "Unknown processing options \"" << options << "\" (ray backend embree, hiprt or embree-gpu; denoise off or oidn; processor native or toolbox-blender)\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
UgcJobs::ApplyOptions(settings, choice);
|
||||
@@ -593,7 +639,19 @@ namespace {
|
||||
std::cerr << "Can't read " << input << "\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
outcome = UgcJobs::ProcessModel(*data, library, settings);
|
||||
// LU Toolbox in Blender when asked for and it can run (Blender is started for this model and stopped after)
|
||||
UgcToolbox::Worker toolbox;
|
||||
toolbox.Configure(ReadToolboxConfig());
|
||||
std::string why;
|
||||
if (UgcToolbox::Resolve(settings.processor, UgcToolbox::Problem(toolbox.GetConfig()), why) == UgcProcessOptions::TOOLBOX_BLENDER) {
|
||||
// A file name has no object id: its name hashed names Blender's files
|
||||
outcome = UgcJobs::ProcessModelToolbox(*data, library, settings, toolbox, UgcModularKey::StorageId(input));
|
||||
toolbox.Stop();
|
||||
// Blender's CPU time is charged to this thread (JobCpuSeconds below)
|
||||
} else {
|
||||
if (!why.empty()) std::cerr << "toolbox-blender can't be used (" << why << "): made natively\n";
|
||||
outcome = UgcJobs::ProcessModel(*data, library, settings);
|
||||
}
|
||||
} else {
|
||||
CDClientDatabase::Connect((BinaryPathFinder::GetBinaryDir() / "resServer/CDServer.sqlite").string());
|
||||
UgcJobs::ModularInput modular;
|
||||
@@ -633,7 +691,7 @@ int main(int argc, char** argv) {
|
||||
Game::config = new dConfig("ugcconfig.ini");
|
||||
|
||||
// UgcServer --make-model <file.lxfml> <folder> [options] or --make-modular "1:4713+1:4714+1:4715" <folder> [options];
|
||||
// options: processing options over the settings (UgcProcessOptions), e.g. embree fast
|
||||
// options: processing options over the settings (UgcProcessOptions), e.g. embree oidn, or toolbox-blender
|
||||
if (argc >= 4 && (std::string(argv[1]) == "--make-model" || std::string(argv[1]) == "--make-modular")) {
|
||||
std::string options;
|
||||
for (int i = 4; i < argc; i++) options += std::string(options.empty() ? "" : " ") + argv[i];
|
||||
@@ -704,7 +762,9 @@ int main(int argc, char** argv) {
|
||||
processorConfig.threads = threads > 0 ? threads : std::max<size_t>(std::thread::hardware_concurrency() / 2, 1);
|
||||
UgcProcessor processor(processorConfig, storage, library, ReadSettings());
|
||||
processor.Configure(ReadSettings(), ReadLimits());
|
||||
processor.ConfigureToolbox(ReadToolboxConfig());
|
||||
LogProcessingOptions(ReadSettings());
|
||||
LogToolbox(ReadSettings(), processor.ToolboxProblem());
|
||||
g_Processor = &processor;
|
||||
// Sent with the traffic reports to the dashboard (Diagnostics)
|
||||
TrafficStats::Local().SetGauge("workers_busy", [&processor] { return static_cast<double>(processor.Busy()); });
|
||||
@@ -772,7 +832,10 @@ int main(int argc, char** argv) {
|
||||
// Settings the dashboard changed arrive as a config reload; pick them up
|
||||
if (now - lastConfigure >= std::chrono::seconds(5)) {
|
||||
lastConfigure = now;
|
||||
processor.Configure(ReadSettings(), ReadLimits());
|
||||
const auto settings = ReadSettings();
|
||||
processor.Configure(settings, ReadLimits());
|
||||
processor.ConfigureToolbox(ReadToolboxConfig());
|
||||
LogToolbox(settings, processor.ToolboxProblem());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user