diff options
Diffstat (limited to 'core/io/resource_loader.cpp')
-rw-r--r-- | core/io/resource_loader.cpp | 58 |
1 files changed, 35 insertions, 23 deletions
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 0c7764392a..ff563a35b2 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -36,6 +36,7 @@ #include "core/object/script_language.h" #include "core/os/condition_variable.h" #include "core/os/os.h" +#include "core/os/safe_binary_mutex.h" #include "core/string/print_string.h" #include "core/string/translation.h" #include "core/variant/variant_parser.h" @@ -187,6 +188,8 @@ void ResourceFormatLoader::_bind_methods() { BIND_ENUM_CONSTANT(CACHE_MODE_IGNORE); BIND_ENUM_CONSTANT(CACHE_MODE_REUSE); BIND_ENUM_CONSTANT(CACHE_MODE_REPLACE); + BIND_ENUM_CONSTANT(CACHE_MODE_IGNORE_DEEP); + BIND_ENUM_CONSTANT(CACHE_MODE_REPLACE_DEEP); GDVIRTUAL_BIND(_get_recognized_extensions); GDVIRTUAL_BIND(_recognize_path, "path", "type"); @@ -244,11 +247,11 @@ Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_origin thread_load_mutex.lock(); HashMap<String, ThreadLoadTask>::Iterator E = thread_load_tasks.find(load_paths_stack->get(load_paths_stack->size() - 1)); if (E) { - E->value.sub_tasks.insert(p_path); + E->value.sub_tasks.insert(p_original_path); } thread_load_mutex.unlock(); } - load_paths_stack->push_back(p_path); + load_paths_stack->push_back(p_original_path); // Try all loaders and pick the first match for the type hint bool found = false; @@ -338,10 +341,20 @@ void ResourceLoader::_thread_load_function(void *p_userdata) { load_task.cond_var = nullptr; } + bool ignoring = load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE || load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE_DEEP; + bool replacing = load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE || load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE_DEEP; if (load_task.resource.is_valid()) { - if (load_task.cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { - load_task.resource->set_path(load_task.local_path, load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); - } else if (!load_task.local_path.is_resource_file()) { + if (!ignoring) { + if (replacing) { + Ref<Resource> old_res = ResourceCache::get_ref(load_task.local_path); + if (old_res.is_valid() && old_res != load_task.resource) { + // If resource is already loaded, only replace its data, to avoid existing invalidating instances. + old_res->copy_from(load_task.resource); + load_task.resource = old_res; + } + } + load_task.resource->set_path(load_task.local_path, replacing); + } else { load_task.resource->set_path_cache(load_task.local_path); } @@ -361,7 +374,7 @@ void ResourceLoader::_thread_load_function(void *p_userdata) { if (_loaded_callback) { _loaded_callback(load_task.resource, load_task.local_path); } - } else if (load_task.cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { + } else if (!ignoring) { Ref<Resource> existing = ResourceCache::get_ref(load_task.local_path); if (existing.is_valid()) { load_task.resource = existing; @@ -520,20 +533,20 @@ Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path, float ResourceLoader::_dependency_get_progress(const String &p_path) { if (thread_load_tasks.has(p_path)) { ThreadLoadTask &load_task = thread_load_tasks[p_path]; + float current_progress = 0.0; int dep_count = load_task.sub_tasks.size(); if (dep_count > 0) { - float dep_progress = 0; for (const String &E : load_task.sub_tasks) { - dep_progress += _dependency_get_progress(E); + current_progress += _dependency_get_progress(E); } - dep_progress /= float(dep_count); - dep_progress *= 0.5; - dep_progress += load_task.progress * 0.5; - return dep_progress; + current_progress /= float(dep_count); + current_progress *= 0.5; + current_progress += load_task.progress * 0.5; } else { - return load_task.progress; + current_progress = load_task.progress; } - + load_task.max_reported_progress = MAX(load_task.max_reported_progress, current_progress); + return load_task.max_reported_progress; } else { return 1.0; //assume finished loading it so it no longer exists } @@ -641,16 +654,14 @@ Ref<Resource> ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro if (load_task.task_id != 0) { // Loading thread is in the worker pool. - load_task.awaited = true; thread_load_mutex.unlock(); Error err = WorkerThreadPool::get_singleton()->wait_for_task_completion(load_task.task_id); if (err == ERR_BUSY) { - // The WorkerThreadPool has scheduled tasks in a way that the current load depends on - // another one in a lower stack frame. Restart such load here. When the stack is eventually - // unrolled, the original load will have been notified to go on. -#ifdef DEV_ENABLED - print_verbose("ResourceLoader: Load task happened to wait on another one deep in the call stack. Attempting to avoid deadlock by re-issuing the load now."); -#endif + // The WorkerThreadPool has reported that the current task wants to await on an older one. + // That't not allowed for safety, to avoid deadlocks. Fortunately, though, in the context of + // resource loading that means that the task to wait for can be restarted here to break the + // cycle, with as much recursion into this process as needed. + // When the stack is eventually unrolled, the original load will have been notified to go on. // CACHE_MODE_IGNORE is needed because, otherwise, the new request would just see there's // an ongoing load for that resource and wait for it again. This value forces a new load. Ref<ResourceLoader::LoadToken> token = _load_start(load_task.local_path, load_task.type_hint, LOAD_THREAD_DISTRIBUTE, ResourceFormatLoader::CACHE_MODE_IGNORE); @@ -663,6 +674,7 @@ Ref<Resource> ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro } else { DEV_ASSERT(err == OK); thread_load_mutex.lock(); + load_task.awaited = true; } } else { // Loading thread is main or user thread. @@ -1103,7 +1115,7 @@ void ResourceLoader::set_load_callback(ResourceLoadedCallback p_callback) { ResourceLoadedCallback ResourceLoader::_loaded_callback = nullptr; -Ref<ResourceFormatLoader> ResourceLoader::_find_custom_resource_format_loader(String path) { +Ref<ResourceFormatLoader> ResourceLoader::_find_custom_resource_format_loader(const String &path) { for (int i = 0; i < loader_count; ++i) { if (loader[i]->get_script_instance() && loader[i]->get_script_instance()->get_script()->get_path() == path) { return loader[i]; @@ -1112,7 +1124,7 @@ Ref<ResourceFormatLoader> ResourceLoader::_find_custom_resource_format_loader(St return Ref<ResourceFormatLoader>(); } -bool ResourceLoader::add_custom_resource_format_loader(String script_path) { +bool ResourceLoader::add_custom_resource_format_loader(const String &script_path) { if (_find_custom_resource_format_loader(script_path).is_valid()) { return false; } |