diff --git a/src/editor/asset_compiler.cpp b/src/editor/asset_compiler.cpp index 9eda8bb8e8..ccdc637e70 100644 --- a/src/editor/asset_compiler.cpp +++ b/src/editor/asset_compiler.cpp @@ -45,20 +45,6 @@ struct HashFunc }; -struct AssetCompilerTask : Thread -{ - AssetCompilerTask(AssetCompilerImpl& compiler, IAllocator& allocator) - : Thread(allocator) - , m_compiler(compiler) - {} - - int task() override; - - AssetCompilerImpl& m_compiler; - volatile bool m_finished = false; -}; - - void AssetCompiler::IPlugin::addSubresources(AssetCompiler& compiler, const Path& path) { const ResourceType type = compiler.getResourceType(path); @@ -86,10 +72,8 @@ struct AssetCompilerImpl : AssetCompiler { , m_load_hook(*this) , m_allocator(app.getAllocator(), "asset compiler") , m_plugins(m_allocator) - , m_task(*this, m_allocator) , m_to_compile(m_allocator) , m_compiled(m_allocator) - , m_semaphore(0, 0x7fFFffFF) , m_registered_extensions(m_allocator) , m_resources(m_allocator) , m_generations(m_allocator) @@ -105,7 +89,6 @@ struct AssetCompilerImpl : AssetCompiler { const char* base_path = fs.getBasePath(); m_watcher = FileSystemWatcher::create(base_path, m_allocator); m_watcher->getCallback().bind<&AssetCompilerImpl::onFileChanged>(this); - m_task.create("Asset compiler", true); Path path(base_path, ".lumix/resources"); if (!os::dirExists(path)) { if (!os::makePath(path.c_str())) logError("Could not create ", path); @@ -193,10 +176,6 @@ struct AssetCompilerImpl : AssetCompiler { } ASSERT(m_plugins.empty()); - m_task.m_finished = true; - m_to_compile.emplace(); - m_semaphore.signal(); - m_task.destroy(); ResourceManagerHub& rm = m_app.getEngine().getResourceManager(); rm.setLoadHook(nullptr); } @@ -234,6 +213,7 @@ struct AssetCompilerImpl : AssetCompiler { bool writeCompiledResource(const Path& path, Span data) override { PROFILE_FUNCTION(); + jobs::enter(&m_lz4_mutex); constexpr u32 COMPRESSION_SIZE_LIMIT = 4096; OutputMemoryStream compressed(m_allocator); i32 compressed_size = 0; @@ -250,6 +230,7 @@ struct AssetCompilerImpl : AssetCompiler { } compressed.resize(compressed_size); } + jobs::exit(&m_lz4_mutex); FileSystem& fs = m_app.getEngine().getFileSystem(); const Path out_path(".lumix/resources/", path.getHash().getHashValue(), ".res"); @@ -583,7 +564,6 @@ struct AssetCompilerImpl : AssetCompiler { } void pushToCompileQueue(const Path& path) { - MutexGuard lock(m_to_compile_mutex); auto iter = m_generations.find(path); if (!iter.isValid()) { iter = m_generations.insert(path, 0); @@ -599,7 +579,6 @@ struct AssetCompilerImpl : AssetCompiler { m_to_compile.push(job); ++m_compile_batch_count; ++m_batch_remaining_count; - m_semaphore.signal(); } CompileJob popCompiledResource() @@ -632,12 +611,7 @@ struct AssetCompilerImpl : AssetCompiler { if (ImGui::Begin("Resource compilation", nullptr, flags)) { ImGui::TextUnformatted("Compiling resources..."); ImGui::ProgressBar(((float)m_compile_batch_count - m_batch_remaining_count) / m_compile_batch_count); - Path path; - { - MutexGuard lock(m_to_compile_mutex); - path = m_res_in_progress; - } - ImGui::TextWrapped("%s", path.c_str()); + ImGui::TextWrapped("%s", m_res_in_progress.c_str()); } ImGui::End(); ImGui::PopStyleVar(); @@ -652,24 +626,44 @@ struct AssetCompilerImpl : AssetCompiler { return nullptr; } - void update() override - { + void runOneJob() { + if (m_to_compile.empty()) return; + + AssetCompilerImpl::CompileJob p = m_to_compile.back(); + m_to_compile.pop(); + auto iter = m_generations.find(p.path); + const bool is_most_recent = p.generation == iter.value(); + if (!is_most_recent) { + --m_batch_remaining_count; + return; + } + + m_res_in_progress = p.path.c_str(); + + jobs::runLambda([p, this]() mutable { + PROFILE_BLOCK("compile asset"); + profiler::pushString(p.path.c_str()); + p.compiled = compile(p.path); + if (!p.compiled) logError("Failed to compile resource ", p.path); + MutexGuard lock(m_compiled_mutex); + m_compiled.push(p); + }, nullptr); + } + + void update() override { for(;;) { + runOneJob(); CompileJob job = popCompiledResource(); if (job.path.isEmpty()) break; - // this can take some time, mutex is probably not the best option - - const u32 generation = [&](){ - MutexGuard lock(m_to_compile_mutex); - return m_generations[job.path]; - }(); + const u32 generation = m_generations[job.path]; if (job.generation != generation) continue; + // this can take some time, mutex is probably not the best option MutexGuard lock(m_compiled_mutex); // reload/continue loading resource and its subresources for (const ResourceItem& ri : m_resources) { - if (!endsWithInsensitive(ri.path, job.path)) continue;; + if (!endsWithInsensitive(ri.path, job.path)) continue; Resource* r = getResource(ri.path); if (r) { @@ -797,8 +791,6 @@ struct AssetCompilerImpl : AssetCompiler { } TagAllocator m_allocator; - Semaphore m_semaphore; - Mutex m_to_compile_mutex; Mutex m_compiled_mutex; Mutex m_changed_mutex; Mutex m_plugin_mutex; @@ -812,7 +804,6 @@ struct AssetCompilerImpl : AssetCompiler { StudioApp& m_app; LoadHook m_load_hook; HashMap m_plugins; - AssetCompilerTask m_task; UniquePtr m_watcher; HashMap m_resources; HashMap> m_registered_extensions; @@ -821,6 +812,7 @@ struct AssetCompilerImpl : AssetCompiler { bool m_init_finished = false; Array m_on_init_load; u8* m_lz4_state = nullptr; + jobs::Mutex m_lz4_mutex; u32 m_compile_batch_count = 0; u32 m_batch_remaining_count = 0; @@ -828,40 +820,6 @@ struct AssetCompilerImpl : AssetCompiler { }; -int AssetCompilerTask::task() -{ - while (!m_finished) { - m_compiler.m_semaphore.wait(); - AssetCompilerImpl::CompileJob p = [&]{ - MutexGuard lock(m_compiler.m_to_compile_mutex); - AssetCompilerImpl::CompileJob p = m_compiler.m_to_compile.back(); - if (p.path.isEmpty()) return p; - - auto iter = m_compiler.m_generations.find(p.path); - const bool is_most_recent = p.generation == iter.value(); - if (is_most_recent) { - m_compiler.m_res_in_progress = p.path.c_str(); - } - else { - p.path = Path(); - --m_compiler.m_batch_remaining_count; - } - m_compiler.m_to_compile.pop(); - return p; - }(); - if (!p.path.isEmpty()) { - PROFILE_BLOCK("compile asset"); - profiler::pushString(p.path.c_str()); - p.compiled = m_compiler.compile(p.path); - if (!p.compiled) logError("Failed to compile resource ", p.path); - MutexGuard lock(m_compiler.m_compiled_mutex); - m_compiler.m_compiled.push(p); - } - } - return 0; -} - - UniquePtr AssetCompiler::create(StudioApp& app) { return UniquePtr::create(app.getAllocator(), app); } diff --git a/src/renderer/editor/render_plugins.cpp b/src/renderer/editor/render_plugins.cpp index 8b9e2f8223..c862b2c463 100644 --- a/src/renderer/editor/render_plugins.cpp +++ b/src/renderer/editor/render_plugins.cpp @@ -2424,7 +2424,6 @@ struct ModelPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin { explicit ModelPlugin(StudioApp& app) : m_app(app) , m_tile(app.getAllocator()) - , m_fbx_importer(app) { app.getAssetCompiler().registerExtension("fbx", Model::TYPE); } @@ -2447,7 +2446,6 @@ struct ModelPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin { void init() { Engine& engine = m_app.getEngine(); m_renderer = static_cast(engine.getSystemManager().getSystem("renderer")); - m_fbx_importer.init(); } void addSubresources(AssetCompiler& compiler, const Path& _path) override { @@ -2522,14 +2520,15 @@ struct ModelPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin { cfg.anim_translation_error = meta.anim_translation_error; cfg.skeleton = meta.skeleton; cfg.root_motion_bone = BoneNameHash(meta.root_motion_bone.c_str()); - if (!m_fbx_importer.setSource(filepath, false, meta.force_skin)) return false; - if (m_fbx_importer.getBoneCount() == 0 && m_fbx_importer.getMeshes().empty() && m_fbx_importer.getAnimations().empty()) { - if (m_fbx_importer.getOFBXScene()) { - if (m_fbx_importer.getOFBXScene()->getMeshCount() > 0) { + FBXImporter importer(m_app); + if (!importer.setSource(filepath, false, meta.force_skin)) return false; + if (importer.getBoneCount() == 0 && importer.getMeshes().empty() && importer.getAnimations().empty()) { + if (importer.getOFBXScene()) { + if (importer.getOFBXScene()->getMeshCount() > 0) { logError("No meshes with materials found in ", src); } else { - if (m_fbx_importer.getBoneCount() == 0) { + if (importer.getBoneCount() == 0) { logError("No meshes or animations found in ", src); } } @@ -2539,16 +2538,16 @@ struct ModelPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin { bool any_written = false; if (meta.split) { cfg.origin = FBXImporter::ImportConfig::Origin::CENTER; - any_written = m_fbx_importer.writeSubmodels(filepath, cfg) || any_written; - any_written = m_fbx_importer.writePrefab(filepath, cfg) || any_written; + any_written = importer.writeSubmodels(filepath, cfg) || any_written; + any_written = importer.writePrefab(filepath, cfg) || any_written; } cfg.origin = FBXImporter::ImportConfig::Origin::SOURCE; - any_written = m_fbx_importer.writeModel(src, cfg) || any_written; - any_written = m_fbx_importer.writeMaterials(filepath, cfg) || any_written; + any_written = importer.writeModel(src, cfg) || any_written; + any_written = importer.writeMaterials(filepath, cfg) || any_written; if (!meta.ignore_animations) { - any_written = m_fbx_importer.writeAnimations(filepath, cfg) || any_written; + any_written = importer.writeAnimations(filepath, cfg) || any_written; } - any_written = m_fbx_importer.writePhysics(filepath, cfg) || any_written; + any_written = importer.writePhysics(filepath, cfg) || any_written; return any_written; } @@ -3124,7 +3123,6 @@ struct ModelPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin { StudioApp& m_app; Renderer* m_renderer = nullptr; TexturePlugin* m_texture_plugin; - FBXImporter m_fbx_importer; jobs::Signal m_subres_signal; gpu::ProgramHandle m_downscale_program = gpu::INVALID_PROGRAM; }; @@ -5076,6 +5074,7 @@ struct StudioAppPlugin : StudioApp::IPlugin , m_terrain_plugin(app) , m_instanced_model_plugin(app) , m_model_plugin(app) + , m_fbx_importer(app) , m_procedural_geom_plugin(app) {} @@ -5096,6 +5095,7 @@ struct StudioAppPlugin : StudioApp::IPlugin void init() override { PROFILE_FUNCTION(); + m_fbx_importer.init(); m_renderdoc_capture_action.init("Capture RenderDoc", "Capture with RenderDoc", "capture_renderdoc", "", Action::GLOBAL); m_renderdoc_capture_action.func.bind<&StudioAppPlugin::captureRenderDoc>(this); @@ -5379,6 +5379,7 @@ struct StudioAppPlugin : StudioApp::IPlugin } StudioApp& m_app; + FBXImporter m_fbx_importer; // only for preloading impostor shadow shader // TODO do this in a better way Action m_renderdoc_capture_action; UniquePtr m_particle_editor; EditorUIRenderPlugin m_editor_ui_render_plugin;