Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve threading in ClassDB and EditorHelp #83695

Merged
merged 1 commit into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions core/object/class_db.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand All @@ -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<StringName> class_list;
ClassDB::get_class_list(&class_list);
for (const KeyValue<StringName, ClassInfo> &E : classes) {
class_list.push_back(E.key);
}
// Must be alphabetically sorted for hash to compute.
class_list.sort_custom<StringName::AlphCompare>();

Expand Down Expand Up @@ -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<Error> &p_values) {
OBJTYPE_RLOCK;
#ifdef DEBUG_METHODS_ENABLED
OBJTYPE_WLOCK;
ClassInfo *type = classes.getptr(p_class);

ERR_FAIL_NULL(type);
Expand All @@ -871,6 +873,7 @@ void ClassDB::set_method_error_return_values(const StringName &p_class, const St

Vector<Error> 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<Error>());
Expand Down Expand Up @@ -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 + "'.");
Expand Down
8 changes: 5 additions & 3 deletions editor/create_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, DocData::ClassDoc>::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."));
Expand All @@ -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) {
Expand Down
44 changes: 24 additions & 20 deletions editor/editor_help.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}

String EditorHelp::get_cache_full_path() {
return EditorPaths::get_singleton()->get_cache_dir().path_join("editor_doc_cache.res");
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);
}

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);
String EditorHelp::get_cache_full_path() {
return EditorPaths::get_singleton()->get_cache_dir().path_join("editor_doc_cache.res");
}

void EditorHelp::_load_doc_thread(void *p_udata) {
DEV_ASSERT(first_attempt);
DEV_ASSERT(doc_gen_first_attempt);

Ref<Resource> 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();
}
}
Expand All @@ -2401,7 +2403,7 @@ void EditorHelp::_gen_doc_thread(void *p_udata) {

Ref<Resource> 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<String, DocData::ClassDoc> &E : doc->class_list) {
classes.push_back(DocData::ClassDoc::to_dict(E.value));
Expand All @@ -2413,24 +2415,26 @@ 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) {
// In case not the first attempt.
_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);
}
Expand All @@ -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);
}
Expand Down
7 changes: 5 additions & 2 deletions editor/editor_help.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 4 additions & 1 deletion editor/editor_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -6761,7 +6765,6 @@ EditorNode::EditorNode() {
DisplayServer::get_singleton()->cursor_set_custom_image(Ref<Resource>());
}

EditorHelp::generate_doc();
SceneState::set_disable_placeholders(true);
ResourceLoader::clear_translation_remaps(); // Using no remaps if in editor.
ResourceLoader::clear_path_remaps();
Expand Down
6 changes: 4 additions & 2 deletions editor/scene_create_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,17 @@

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")));
node_type_3d->set_icon(get_editor_theme_icon(SNAME("Node3D")));
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;
}
}

Expand Down Expand Up @@ -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);
Expand Down
Loading