feat: updated godot version

This commit is contained in:
Sara Gerretsen 2026-04-04 19:38:56 +02:00
parent 0c508b0831
commit 42b028dbb5
4694 changed files with 236470 additions and 401376 deletions

View file

@ -30,15 +30,11 @@
#include "resource_loader.h"
#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/core_bind.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/io/resource_importer.h"
#include "core/object/callable_mp.h"
#include "core/object/class_db.h"
#include "core/object/message_queue.h"
#include "core/object/script_language.h"
#include "core/os/condition_variable.h"
#include "core/os/os.h"
@ -222,6 +218,26 @@ void ResourceFormatLoader::_bind_methods() {
GDVIRTUAL_BIND(_load, "path", "original_path", "use_sub_threads", "cache_mode");
}
///////////////////////////////////
// These are used before and after a wait for a WorkerThreadPool task
// because that can lead to another load started in the same thread,
// something we must treat as a different stack for the purposes
// of tracking nesting.
#define PREPARE_FOR_WTP_WAIT \
int load_nesting_backup = ResourceLoader::load_nesting; \
Vector<String> load_paths_stack_backup = ResourceLoader::load_paths_stack; \
ResourceLoader::load_nesting = 0; \
ResourceLoader::load_paths_stack.clear();
#define RESTORE_AFTER_WTP_WAIT \
DEV_ASSERT(ResourceLoader::load_nesting == 0); \
DEV_ASSERT(ResourceLoader::load_paths_stack.is_empty()); \
ResourceLoader::load_nesting = load_nesting_backup; \
ResourceLoader::load_paths_stack = load_paths_stack_backup; \
load_paths_stack_backup.clear();
// This should be robust enough to be called redundantly without issues.
void ResourceLoader::LoadToken::clear() {
WorkerThreadPool::TaskID task_to_await = 0;
@ -260,11 +276,9 @@ void ResourceLoader::LoadToken::clear() {
// If task is unused, await it here, locally, now the token data is consistent.
if (task_to_await) {
int load_nesting_backup = load_nesting;
load_nesting = 0;
PREPARE_FOR_WTP_WAIT
WorkerThreadPool::get_singleton()->wait_for_task_completion(task_to_await);
DEV_ASSERT(load_nesting == 0);
load_nesting = load_nesting_backup;
RESTORE_AFTER_WTP_WAIT
}
}
@ -272,9 +286,20 @@ ResourceLoader::LoadToken::~LoadToken() {
clear();
}
Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_original_path, const String &p_type_hint, CacheMode p_cache_mode, Error *r_error, bool p_use_sub_threads, float *r_progress) {
Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_original_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error, bool p_use_sub_threads, float *r_progress) {
const String &original_path = p_original_path.is_empty() ? p_path : p_original_path;
load_nesting++;
if (load_paths_stack.size()) {
MutexLock thread_load_lock(thread_load_mutex);
const String &parent_task_path = load_paths_stack.get(load_paths_stack.size() - 1);
HashMap<String, ThreadLoadTask>::Iterator E = thread_load_tasks.find(parent_task_path);
// Avoid double-tracking, for progress reporting, resources that boil down to a remapped path containing the real payload (e.g., imported resources).
bool is_remapped_load = original_path == parent_task_path;
if (E && !is_remapped_load) {
E->value.sub_tasks.insert(original_path);
}
}
load_paths_stack.push_back(original_path);
print_verbose(vformat("Loading resource: %s", p_path));
@ -292,6 +317,7 @@ Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_origin
}
}
load_paths_stack.resize(load_paths_stack.size() - 1);
res_ref_overrides.erase(load_nesting);
load_nesting--;
@ -351,6 +377,7 @@ void ResourceLoader::_run_load_task(void *p_userdata) {
// Thread-safe either if it's the current thread or a brand new one.
CallQueue *own_mq_override = nullptr;
if (load_nesting == 0) {
DEV_ASSERT(load_paths_stack.is_empty());
if (!Thread::is_main_thread()) {
// Let the caller thread use its own, for added flexibility. Provide one otherwise.
if (MessageQueue::get_singleton() == MessageQueue::get_main_singleton()) {
@ -388,8 +415,8 @@ void ResourceLoader::_run_load_task(void *p_userdata) {
}
load_task.need_wait = false;
bool ignoring = load_task.cache_mode == CACHE_MODE_IGNORE || load_task.cache_mode == CACHE_MODE_IGNORE_DEEP;
bool replacing = load_task.cache_mode == CACHE_MODE_REPLACE || load_task.cache_mode == CACHE_MODE_REPLACE_DEEP;
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;
bool unlock_pending = true;
if (load_task.resource.is_valid()) {
// From now on, no critical section needed as no one will write to the task anymore.
@ -469,6 +496,7 @@ void ResourceLoader::_run_load_task(void *p_userdata) {
MessageQueue::set_thread_singleton_override(nullptr);
memdelete(own_mq_override);
}
DEV_ASSERT(load_paths_stack.is_empty());
}
curr_load_task = curr_load_task_backup;
@ -485,7 +513,7 @@ String ResourceLoader::_validate_local_path(const String &p_path) {
}
}
Error ResourceLoader::load_threaded_request(const String &p_path, const String &p_type_hint, bool p_use_sub_threads, CacheMode p_cache_mode) {
Error ResourceLoader::load_threaded_request(const String &p_path, const String &p_type_hint, bool p_use_sub_threads, ResourceFormatLoader::CacheMode p_cache_mode) {
Ref<ResourceLoader::LoadToken> token = _load_start(p_path, p_type_hint, p_use_sub_threads ? LOAD_THREAD_DISTRIBUTE : LOAD_THREAD_SPAWN_SINGLE, p_cache_mode, true);
return token.is_valid() ? OK : FAILED;
}
@ -510,7 +538,7 @@ void ResourceLoader::_load_threaded_request_setup_user_token(LoadToken *p_token,
print_lt("REQUEST: user load tokens: " + itos(user_load_tokens.size()));
}
Ref<Resource> ResourceLoader::load(const String &p_path, const String &p_type_hint, CacheMode p_cache_mode, Error *r_error) {
Ref<Resource> ResourceLoader::load(const String &p_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error) {
if (r_error) {
*r_error = OK;
}
@ -535,11 +563,11 @@ Ref<Resource> ResourceLoader::load(const String &p_path, const String &p_type_hi
return res;
}
Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path, const String &p_type_hint, LoadThreadMode p_thread_mode, CacheMode p_cache_mode, bool p_for_user) {
Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path, const String &p_type_hint, LoadThreadMode p_thread_mode, ResourceFormatLoader::CacheMode p_cache_mode, bool p_for_user) {
String local_path = _validate_local_path(p_path);
ERR_FAIL_COND_V(local_path.is_empty(), Ref<ResourceLoader::LoadToken>());
bool ignoring_cache = p_cache_mode == CACHE_MODE_IGNORE || p_cache_mode == CACHE_MODE_IGNORE_DEEP;
bool ignoring_cache = p_cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE || p_cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE_DEEP;
Ref<LoadToken> load_token;
bool must_not_register = false;
@ -585,7 +613,7 @@ Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path,
load_task.type_hint = p_type_hint;
load_task.cache_mode = p_cache_mode;
load_task.use_sub_threads = p_thread_mode == LOAD_THREAD_DISTRIBUTE;
if (p_cache_mode == CACHE_MODE_REUSE) {
if (p_cache_mode == ResourceFormatLoader::CACHE_MODE_REUSE) {
Ref<Resource> existing = ResourceCache::get_ref(local_path);
if (existing.is_valid()) {
//referencing is fine
@ -598,12 +626,6 @@ Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path,
}
}
// Task hierarchy
if (curr_load_task) {
load_task.parent_task = curr_load_task;
curr_load_task->sub_tasks.insert(load_task.local_path);
}
// If we want to ignore cache, but there's another task loading it, we can't add this one to the map.
must_not_register = ignoring_cache && thread_load_tasks.has(local_path);
if (must_not_register) {
@ -793,22 +815,6 @@ void ResourceLoader::set_is_import_thread(bool p_import_thread) {
import_thread = p_import_thread;
}
void ResourceLoader::notify_load_error(const String &p_err) {
if (err_notify) {
MessageQueue::get_main_singleton()->push_callable(callable_mp_static(err_notify).bind(p_err));
}
}
void ResourceLoader::notify_dependency_error(const String &p_path, const String &p_dependency, const String &p_type) {
if (dep_err_notify) {
if (Thread::get_caller_id() == Thread::get_main_id()) {
dep_err_notify(p_path, p_dependency, p_type);
} else {
MessageQueue::get_main_singleton()->push_callable(callable_mp_static(dep_err_notify).bind(p_path, p_dependency, p_type));
}
}
}
Ref<Resource> ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Error *r_error, MutexLock<SafeBinaryMutex<BINARY_MUTEX_TAG>> &p_thread_load_lock) {
if (r_error) {
*r_error = OK;
@ -845,11 +851,9 @@ Ref<Resource> ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro
// Loading thread is in the worker pool.
p_thread_load_lock.temp_unlock();
int load_nesting_backup = load_nesting;
load_nesting = 0;
PREPARE_FOR_WTP_WAIT
Error wait_err = WorkerThreadPool::get_singleton()->wait_for_task_completion(load_task.task_id);
DEV_ASSERT(load_nesting == 0);
load_nesting = load_nesting_backup;
RESTORE_AFTER_WTP_WAIT
DEV_ASSERT(!wait_err || wait_err == ERR_BUSY);
if (wait_err == ERR_BUSY) {
@ -900,21 +904,21 @@ Ref<Resource> ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro
load_task_ptr = &load_task;
}
p_thread_load_lock.temp_unlock();
Ref<Resource> resource = load_task_ptr->resource;
if (r_error) {
*r_error = load_task_ptr->error;
}
if (resource.is_valid()) {
if (load_task_ptr->parent_task) {
if (curr_load_task) {
// A task awaiting another => Let the awaiter accumulate the resource changed connections.
DEV_ASSERT(load_task_ptr->parent_task != load_task_ptr);
DEV_ASSERT(curr_load_task != load_task_ptr);
for (const ThreadLoadTask::ResourceChangedConnection &rcc : load_task_ptr->resource_changed_connections) {
load_task_ptr->parent_task->resource_changed_connections.push_back(rcc);
curr_load_task->resource_changed_connections.push_back(rcc);
}
} else {
p_thread_load_lock.temp_unlock();
// A leaf task being awaited => Propagate the resource changed connections.
if (Thread::is_main_thread()) {
// On the main thread it's safe to migrate the connections to the standard signal mechanism.
@ -938,11 +942,11 @@ Ref<Resource> ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro
}
}
}
p_thread_load_lock.temp_relock();
}
}
p_thread_load_lock.temp_relock();
return resource;
}
@ -1564,6 +1568,7 @@ bool ResourceLoader::timestamp_on_load = false;
thread_local bool ResourceLoader::import_thread = false;
thread_local int ResourceLoader::load_nesting = 0;
thread_local Vector<String> ResourceLoader::load_paths_stack;
thread_local HashMap<int, HashMap<String, Ref<Resource>>> ResourceLoader::res_ref_overrides;
thread_local ResourceLoader::ThreadLoadTask *ResourceLoader::curr_load_task = nullptr;