From 9b03fb36f967f81a306d87601a79dd4063fb9421 Mon Sep 17 00:00:00 2001 From: Yuri Sizov Date: Fri, 20 Oct 2023 22:14:04 +0200 Subject: [PATCH] Improve threading in ClassDB and EditorHelp --- core/object/class_db.cpp | 11 ++++++--- editor/create_dialog.cpp | 8 ++++--- editor/editor_help.cpp | 44 ++++++++++++++++++---------------- editor/editor_help.h | 7 ++++-- editor/editor_node.cpp | 5 +++- editor/scene_create_dialog.cpp | 6 +++-- 6 files changed, 50 insertions(+), 31 deletions(-) diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index c594f4a9b49..8c54db3c2cf 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -165,8 +165,8 @@ ClassDB::APIType ClassDB::get_api_type(const StringName &p_class) { } uint32_t ClassDB::get_api_hash(APIType p_api) { - OBJTYPE_RLOCK; #ifdef DEBUG_METHODS_ENABLED + OBJTYPE_WLOCK; if (api_hashes_cache.has(p_api)) { return api_hashes_cache[p_api]; @@ -175,7 +175,9 @@ uint32_t ClassDB::get_api_hash(APIType p_api) { uint64_t hash = hash_murmur3_one_64(HashMapHasherDefault::hash(VERSION_FULL_CONFIG)); List class_list; - ClassDB::get_class_list(&class_list); + for (const KeyValue &E : classes) { + class_list.push_back(E.key); + } // Must be alphabetically sorted for hash to compute. class_list.sort_custom(); @@ -859,8 +861,8 @@ void ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_ } void ClassDB::set_method_error_return_values(const StringName &p_class, const StringName &p_method, const Vector &p_values) { - OBJTYPE_RLOCK; #ifdef DEBUG_METHODS_ENABLED + OBJTYPE_WLOCK; ClassInfo *type = classes.getptr(p_class); ERR_FAIL_NULL(type); @@ -871,6 +873,7 @@ void ClassDB::set_method_error_return_values(const StringName &p_class, const St Vector ClassDB::get_method_error_return_values(const StringName &p_class, const StringName &p_method) { #ifdef DEBUG_METHODS_ENABLED + OBJTYPE_RLOCK; ClassInfo *type = classes.getptr(p_class); ERR_FAIL_NULL_V(type, Vector()); @@ -1415,6 +1418,8 @@ void ClassDB::_bind_compatibility(ClassInfo *type, MethodBind *p_method) { } void ClassDB::_bind_method_custom(const StringName &p_class, MethodBind *p_method, bool p_compatibility) { + OBJTYPE_WLOCK; + ClassInfo *type = classes.getptr(p_class); if (!type) { ERR_FAIL_MSG("Couldn't bind custom method '" + p_method->get_name() + "' for instance '" + p_class + "'."); diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 0e025b44309..e37035f5ebc 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -309,8 +309,10 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String r_item->set_custom_color(0, search_options->get_theme_color(SNAME("disabled_font_color"), EditorStringName(Editor))); } - bool is_deprecated = EditorHelp::get_doc_data()->class_list[p_type].is_deprecated; - bool is_experimental = EditorHelp::get_doc_data()->class_list[p_type].is_experimental; + HashMap::Iterator class_doc = EditorHelp::get_doc_data()->class_list.find(p_type); + + bool is_deprecated = (class_doc && class_doc->value.is_deprecated); + bool is_experimental = (class_doc && class_doc->value.is_experimental); if (is_deprecated) { r_item->add_button(0, get_editor_theme_icon("StatusError"), 0, false, TTR("This class is marked as deprecated.")); @@ -330,7 +332,7 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String r_item->set_collapsed(should_collapse); } - const String &description = DTR(EditorHelp::get_doc_data()->class_list[p_type].brief_description); + const String &description = DTR(class_doc ? class_doc->value.brief_description : ""); r_item->set_tooltip_text(0, description); if (p_type_category == TypeCategory::OTHER_TYPE && !script_type) { diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index d6eadf3ab4f..0ab6e20b015 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -2360,36 +2360,38 @@ void EditorHelp::_add_text(const String &p_bbcode) { _add_text_to_rt(p_bbcode, class_desc, this, edited_class); } -Thread EditorHelp::thread; +String EditorHelp::doc_version_hash; +bool EditorHelp::doc_gen_first_attempt = true; +bool EditorHelp::doc_gen_use_threads = true; +Thread EditorHelp::gen_thread; void EditorHelp::_wait_for_thread() { - if (thread.is_started()) { - thread.wait_to_finish(); + if (gen_thread.is_started()) { + gen_thread.wait_to_finish(); } } +void EditorHelp::_compute_doc_version_hash() { + uint32_t version_hash = Engine::get_singleton()->get_version_info().hash(); + doc_version_hash = vformat("%d/%d/%d/%s", version_hash, ClassDB::get_api_hash(ClassDB::API_CORE), ClassDB::get_api_hash(ClassDB::API_EDITOR), _doc_data_hash); +} + String EditorHelp::get_cache_full_path() { return EditorPaths::get_singleton()->get_cache_dir().path_join("editor_doc_cache.res"); } -static bool first_attempt = true; - -static String _compute_doc_version_hash() { - uint32_t version_hash = Engine::get_singleton()->get_version_info().hash(); - return vformat("%d/%d/%d/%s", version_hash, ClassDB::get_api_hash(ClassDB::API_CORE), ClassDB::get_api_hash(ClassDB::API_EDITOR), _doc_data_hash); -} - void EditorHelp::_load_doc_thread(void *p_udata) { - DEV_ASSERT(first_attempt); + DEV_ASSERT(doc_gen_first_attempt); + Ref cache_res = ResourceLoader::load(get_cache_full_path()); - if (cache_res.is_valid() && cache_res->get_meta("version_hash", "") == _compute_doc_version_hash()) { + if (cache_res.is_valid() && cache_res->get_meta("version_hash", "") == doc_version_hash) { Array classes = cache_res->get_meta("classes", Array()); for (int i = 0; i < classes.size(); i++) { doc->add_doc(DocData::ClassDoc::from_dict(classes[i])); } } else { // We have to go back to the main thread to start from scratch. - first_attempt = false; + doc_gen_first_attempt = false; callable_mp_static(&EditorHelp::generate_doc).bind(true).call_deferred(); } } @@ -2401,7 +2403,7 @@ void EditorHelp::_gen_doc_thread(void *p_udata) { Ref cache_res; cache_res.instantiate(); - cache_res->set_meta("version_hash", _compute_doc_version_hash()); + cache_res->set_meta("version_hash", doc_version_hash); Array classes; for (const KeyValue &E : doc->class_list) { classes.push_back(DocData::ClassDoc::to_dict(E.value)); @@ -2413,8 +2415,6 @@ void EditorHelp::_gen_doc_thread(void *p_udata) { } } -static bool doc_gen_use_threads = true; - void EditorHelp::generate_doc(bool p_use_cache) { OS::get_singleton()->benchmark_begin_measure("EditorHelp::generate_doc"); if (doc_gen_use_threads) { @@ -2422,15 +2422,19 @@ void EditorHelp::generate_doc(bool p_use_cache) { _wait_for_thread(); } - DEV_ASSERT(first_attempt == (doc == nullptr)); + DEV_ASSERT(doc_gen_first_attempt == (doc == nullptr)); if (!doc) { doc = memnew(DocTools); } - if (p_use_cache && first_attempt && FileAccess::exists(get_cache_full_path())) { + if (doc_version_hash.is_empty()) { + _compute_doc_version_hash(); + } + + if (p_use_cache && doc_gen_first_attempt && FileAccess::exists(get_cache_full_path())) { if (doc_gen_use_threads) { - thread.start(_load_doc_thread, nullptr); + gen_thread.start(_load_doc_thread, nullptr); } else { _load_doc_thread(nullptr); } @@ -2441,7 +2445,7 @@ void EditorHelp::generate_doc(bool p_use_cache) { doc->generate(true); if (doc_gen_use_threads) { - thread.start(_gen_doc_thread, nullptr); + gen_thread.start(_gen_doc_thread, nullptr); } else { _gen_doc_thread(nullptr); } diff --git a/editor/editor_help.h b/editor/editor_help.h index 0ca3942e0be..1f813f930c6 100644 --- a/editor/editor_help.h +++ b/editor/editor_help.h @@ -187,12 +187,15 @@ class EditorHelp : public VBoxContainer { String _fix_constant(const String &p_constant) const; void _toggle_scripts_pressed(); - static Thread thread; + static String doc_version_hash; + static bool doc_gen_first_attempt; + static bool doc_gen_use_threads; + static Thread gen_thread; static void _wait_for_thread(); static void _load_doc_thread(void *p_udata); static void _gen_doc_thread(void *p_udata); - static void _generate_doc_first_step(); + static void _compute_doc_version_hash(); protected: virtual void _update_theme_item_cache() override; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 30872f02889..dc10df85056 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -575,6 +575,10 @@ void EditorNode::update_preview_themes(int p_mode) { void EditorNode::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_POSTINITIALIZE: { + EditorHelp::generate_doc(); + } break; + case NOTIFICATION_PROCESS: { if (opening_prev && !confirmation->is_visible()) { opening_prev = false; @@ -6761,7 +6765,6 @@ EditorNode::EditorNode() { DisplayServer::get_singleton()->cursor_set_custom_image(Ref()); } - EditorHelp::generate_doc(); SceneState::set_disable_placeholders(true); ResourceLoader::clear_translation_remaps(); // Using no remaps if in editor. ResourceLoader::clear_path_remaps(); diff --git a/editor/scene_create_dialog.cpp b/editor/scene_create_dialog.cpp index d6cb36013f3..60ad7e59683 100644 --- a/editor/scene_create_dialog.cpp +++ b/editor/scene_create_dialog.cpp @@ -47,7 +47,6 @@ void SceneCreateDialog::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { select_node_button->set_icon(get_editor_theme_icon(SNAME("ClassList"))); node_type_2d->set_icon(get_editor_theme_icon(SNAME("Node2D"))); @@ -55,6 +54,10 @@ void SceneCreateDialog::_notification(int p_what) { node_type_gui->set_icon(get_editor_theme_icon(SNAME("Control"))); node_type_other->add_theme_icon_override(SNAME("icon"), get_editor_theme_icon(SNAME("Node"))); } break; + + case NOTIFICATION_READY: { + select_node_dialog->select_base(); + } break; } } @@ -180,7 +183,6 @@ SceneCreateDialog::SceneCreateDialog() { select_node_dialog = memnew(CreateDialog); add_child(select_node_dialog); select_node_dialog->set_base_type("Node"); - select_node_dialog->select_base(); select_node_dialog->connect("create", callable_mp(this, &SceneCreateDialog::on_type_picked)); VBoxContainer *main_vb = memnew(VBoxContainer);