fixed race condition when writing prefabs during fbx import

This commit is contained in:
Mikulas Florek 2023-09-23 18:55:44 +02:00
parent c284ce9769
commit 24d1cb1887
4 changed files with 52 additions and 3 deletions

View file

@ -379,7 +379,7 @@ bool init(u8 workers_count, IAllocator& allocator)
int count = maximum(1, int(workers_count));
for (int i = 0; i < count; ++i) {
WorkerTask* task = LUMIX_NEW(getAllocator(), WorkerTask)(*g_system, i < 64 ? u64(1) << i : 0);
WorkerTask* task = LUMIX_NEW(getAllocator(), WorkerTask)(*g_system, i);
if (task->create("Worker", false)) {
task->m_is_enabled = true;
g_system->m_workers.push(task);
@ -499,4 +499,45 @@ void wait(Signal* handle) {
waitEx(handle, false);
}
u32 getWorkerIndex() {
return getWorker()->m_worker_index;
}
void moveJobToWorker(u8 worker_index) {
g_system->m_sync.enter();
FiberDecl* this_fiber = getWorker()->m_current_fiber;
WorkerTask* worker = g_system->m_workers[worker_index % g_system->m_workers.size()];
worker->m_work_queue.push(this_fiber, &g_system->m_job_queue_sync);
wake();
FiberDecl* new_fiber = g_system->m_free_fibers.back();
g_system->m_free_fibers.pop();
if (!Fiber::isValid(new_fiber->fiber)) {
new_fiber->fiber = Fiber::create(64 * 1024, manage, new_fiber);
}
getWorker()->m_current_fiber = new_fiber;
this_fiber->current_job.worker_index = worker_index;
Fiber::switchTo(&this_fiber->fiber, new_fiber->fiber);
getWorker()->m_current_fiber = this_fiber;
ASSERT(getWorker()->m_worker_index == worker_index);
g_system->m_sync.exit();
}
void yield() {
g_system->m_sync.enter();
FiberDecl* this_fiber = getWorker()->m_current_fiber;
g_system->m_work_queue.push(this_fiber, &g_system->m_job_queue_sync);
wake();
FiberDecl* new_fiber = g_system->m_free_fibers.back();
g_system->m_free_fibers.pop();
if (!Fiber::isValid(new_fiber->fiber)) {
new_fiber->fiber = Fiber::create(64 * 1024, manage, new_fiber);
}
this_fiber->current_job.worker_index = ANY_WORKER;
getWorker()->m_current_fiber = new_fiber;
Fiber::switchTo(&this_fiber->fiber, new_fiber->fiber);
g_system->m_sync.exit();
}
} // namespace Lumix::jobs

View file

@ -19,6 +19,10 @@ LUMIX_ENGINE_API void shutdown();
LUMIX_ENGINE_API u8 getWorkersCount();
LUMIX_ENGINE_API void enableBackupWorker(bool enable);
// yield current job and push it to worker queue
LUMIX_ENGINE_API void moveJobToWorker(u8 worker_index);
// yield current job, push it to global queue
LUMIX_ENGINE_API void yield();
LUMIX_ENGINE_API void enter(Mutex* mutex);
LUMIX_ENGINE_API void exit(Mutex* mutex);

View file

@ -2586,7 +2586,6 @@ bool FBXImporter::writePhysicsPrefab(const Path& src, const ImportConfig& cfg) {
bool FBXImporter::writePrefab(const Path& src, const ImportConfig& cfg)
{
// TODO this is not threadsafe, since it can load/unload assets, access lua state, ...
Engine& engine = m_app.getEngine();
World& world = engine.createWorld(false);
@ -2625,7 +2624,6 @@ bool FBXImporter::writePrefab(const Path& src, const ImportConfig& cfg)
world.serialize(blob, WorldSerializeFlags::NONE);
engine.destroyWorld(world);
if (!file.write(blob.data(), blob.size())) {
logError("Could not write ", tmp);
file.close();

View file

@ -66,6 +66,7 @@
using namespace Lumix;
static AtomicI32 xx = 0;
static Animation::Flags operator | (Animation::Flags a, Animation::Flags b) {
return Animation::Flags(u32(a) | u32(b));
@ -2687,7 +2688,10 @@ struct ModelPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin {
if (meta.split) {
cfg.origin = FBXImporter::ImportConfig::Origin::CENTER_EACH_MESH;
any_written = importer.writeSubmodels(filepath, cfg) || any_written;
// writePrefab is not threadsafe, run on "main thread"
jobs::moveJobToWorker(0);
any_written = importer.writePrefab(filepath, cfg) || any_written;
jobs::yield();
}
cfg.origin = meta.origin;
any_written = importer.writeModel(src, cfg) || any_written;
@ -2697,7 +2701,9 @@ struct ModelPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin {
}
any_written = importer.writePhysics(filepath, cfg) || any_written;
if (meta.create_prefab_with_physics) {
jobs::moveJobToWorker(0);
importer.writePhysicsPrefab(filepath, cfg);
jobs::yield();
}
return any_written;
}