mirror of
https://github.com/godotengine/godot.git
synced 2025-12-08 06:09:55 +00:00
Merge pull request #113114 from RandomShaper/fix_load_progress_cycles
ResourceLoader: Fix potential infinite recursion in progress reporting
This commit is contained in:
commit
a1848013e5
2 changed files with 20 additions and 4 deletions
|
|
@ -666,6 +666,14 @@ 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];
|
||||
if (load_task.in_progress_check) {
|
||||
// Given the fact that any resource loaded when an outer stack frame is
|
||||
// loading another one is considered a dependency of it, for progress
|
||||
// tracking purposes, a cycle can happen if even if the original resource
|
||||
// graphs involved have none. For instance, preload() can cause this.
|
||||
return load_task.max_reported_progress;
|
||||
}
|
||||
load_task.in_progress_check = true;
|
||||
float current_progress = 0.0;
|
||||
int dep_count = load_task.sub_tasks.size();
|
||||
if (dep_count > 0) {
|
||||
|
|
@ -679,6 +687,7 @@ float ResourceLoader::_dependency_get_progress(const String &p_path) {
|
|||
current_progress = load_task.progress;
|
||||
}
|
||||
load_task.max_reported_progress = MAX(load_task.max_reported_progress, current_progress);
|
||||
load_task.in_progress_check = false;
|
||||
return load_task.max_reported_progress;
|
||||
} else {
|
||||
return 1.0; //assume finished loading it so it no longer exists
|
||||
|
|
|
|||
|
|
@ -176,10 +176,8 @@ private:
|
|||
struct ThreadLoadTask {
|
||||
WorkerThreadPool::TaskID task_id = 0; // Used if run on a worker thread from the pool.
|
||||
Thread::ID thread_id = 0; // Used if running on an user thread (e.g., simple non-threaded load).
|
||||
bool awaited = false; // If it's in the pool, this helps not awaiting from more than one dependent thread.
|
||||
ConditionVariable *cond_var = nullptr; // In not in the worker pool or already awaiting, this is used as a secondary awaiting mechanism.
|
||||
uint32_t awaiters_count = 0;
|
||||
bool need_wait = true;
|
||||
LoadToken *load_token = nullptr;
|
||||
String local_path;
|
||||
String type_hint;
|
||||
|
|
@ -190,17 +188,26 @@ private:
|
|||
ResourceFormatLoader::CacheMode cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE;
|
||||
Error error = OK;
|
||||
Ref<Resource> resource;
|
||||
bool use_sub_threads = false;
|
||||
HashSet<String> sub_tasks;
|
||||
|
||||
bool awaited : 1; // If it's in the pool, this helps not awaiting from more than one dependent thread.
|
||||
bool need_wait : 1;
|
||||
bool in_progress_check : 1; // Measure against recursion cycles in progress reporting. Cycles are not expected, but can happen due to how it's currently implemented.
|
||||
bool use_sub_threads : 1;
|
||||
|
||||
struct ResourceChangedConnection {
|
||||
Resource *source = nullptr;
|
||||
Callable callable;
|
||||
uint32_t flags = 0;
|
||||
};
|
||||
LocalVector<ResourceChangedConnection> resource_changed_connections;
|
||||
};
|
||||
|
||||
ThreadLoadTask() :
|
||||
awaited(false),
|
||||
need_wait(true),
|
||||
in_progress_check(false),
|
||||
use_sub_threads(false) {}
|
||||
};
|
||||
static void _run_load_task(void *p_userdata);
|
||||
|
||||
static thread_local bool import_thread;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue