Merge pull request #93695 from RandomShaper/res_load_main_th
`ResourceLoader`: Support polling and get-before-complete on the main thread
This commit is contained in:
commit
e052a53bb6
@ -40,6 +40,7 @@
|
|||||||
#include "core/string/print_string.h"
|
#include "core/string/print_string.h"
|
||||||
#include "core/string/translation.h"
|
#include "core/string/translation.h"
|
||||||
#include "core/variant/variant_parser.h"
|
#include "core/variant/variant_parser.h"
|
||||||
|
#include "servers/rendering_server.h"
|
||||||
|
|
||||||
#ifdef DEBUG_LOAD_THREADED
|
#ifdef DEBUG_LOAD_THREADED
|
||||||
#define print_lt(m_text) print_line(m_text)
|
#define print_lt(m_text) print_line(m_text)
|
||||||
@ -585,6 +586,16 @@ ResourceLoader::ThreadLoadStatus ResourceLoader::load_threaded_get_status(const
|
|||||||
*r_progress = _dependency_get_progress(local_path);
|
*r_progress = _dependency_get_progress(local_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Support userland polling in a loop on the main thread.
|
||||||
|
if (Thread::is_main_thread() && status == THREAD_LOAD_IN_PROGRESS) {
|
||||||
|
uint64_t frame = Engine::get_singleton()->get_process_frames();
|
||||||
|
if (frame == load_task.last_progress_check_main_thread_frame) {
|
||||||
|
_ensure_load_progress();
|
||||||
|
} else {
|
||||||
|
load_task.last_progress_check_main_thread_frame = frame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -613,6 +624,21 @@ Ref<Resource> ResourceLoader::load_threaded_get(const String &p_path, Error *r_e
|
|||||||
}
|
}
|
||||||
return Ref<Resource>();
|
return Ref<Resource>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Support userland requesting on the main thread before the load is reported to be complete.
|
||||||
|
if (Thread::is_main_thread() && !load_token->local_path.is_empty()) {
|
||||||
|
const ThreadLoadTask &load_task = thread_load_tasks[load_token->local_path];
|
||||||
|
while (load_task.status == THREAD_LOAD_IN_PROGRESS) {
|
||||||
|
if (!_ensure_load_progress()) {
|
||||||
|
// This local poll loop is not needed.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
thread_load_lock.~MutexLock();
|
||||||
|
OS::get_singleton()->delay_usec(1000);
|
||||||
|
new (&thread_load_lock) MutexLock(thread_load_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res = _load_complete_inner(*load_token, r_error, thread_load_lock);
|
res = _load_complete_inner(*load_token, r_error, thread_load_lock);
|
||||||
if (load_token->unreference()) {
|
if (load_token->unreference()) {
|
||||||
memdelete(load_token);
|
memdelete(load_token);
|
||||||
@ -731,6 +757,17 @@ Ref<Resource> ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ResourceLoader::_ensure_load_progress() {
|
||||||
|
// Some servers may need a new engine iteration to allow the load to progress.
|
||||||
|
// Since the only known one is the rendering server (in single thread mode), let's keep it simple and just sync it.
|
||||||
|
// This may be refactored in the future to support other servers and have less coupling.
|
||||||
|
if (OS::get_singleton()->get_render_thread_mode() == OS::RENDER_SEPARATE_THREAD) {
|
||||||
|
return false; // Not needed.
|
||||||
|
}
|
||||||
|
RenderingServer::get_singleton()->sync();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Ref<Resource> ResourceLoader::ensure_resource_ref_override_for_outer_load(const String &p_path, const String &p_res_type) {
|
Ref<Resource> ResourceLoader::ensure_resource_ref_override_for_outer_load(const String &p_path, const String &p_res_type) {
|
||||||
ERR_FAIL_COND_V(load_nesting == 0, Ref<Resource>()); // It makes no sense to use this from nesting level 0.
|
ERR_FAIL_COND_V(load_nesting == 0, Ref<Resource>()); // It makes no sense to use this from nesting level 0.
|
||||||
const String &local_path = _validate_local_path(p_path);
|
const String &local_path = _validate_local_path(p_path);
|
||||||
|
@ -174,6 +174,7 @@ private:
|
|||||||
String type_hint;
|
String type_hint;
|
||||||
float progress = 0.0f;
|
float progress = 0.0f;
|
||||||
float max_reported_progress = 0.0f;
|
float max_reported_progress = 0.0f;
|
||||||
|
uint64_t last_progress_check_main_thread_frame = UINT64_MAX;
|
||||||
ThreadLoadStatus status = THREAD_LOAD_IN_PROGRESS;
|
ThreadLoadStatus status = THREAD_LOAD_IN_PROGRESS;
|
||||||
ResourceFormatLoader::CacheMode cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE;
|
ResourceFormatLoader::CacheMode cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE;
|
||||||
Error error = OK;
|
Error error = OK;
|
||||||
@ -197,6 +198,8 @@ private:
|
|||||||
|
|
||||||
static float _dependency_get_progress(const String &p_path);
|
static float _dependency_get_progress(const String &p_path);
|
||||||
|
|
||||||
|
static bool _ensure_load_progress();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static Error load_threaded_request(const String &p_path, const String &p_type_hint = "", bool p_use_sub_threads = false, ResourceFormatLoader::CacheMode p_cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE);
|
static Error load_threaded_request(const String &p_path, const String &p_type_hint = "", bool p_use_sub_threads = false, ResourceFormatLoader::CacheMode p_cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE);
|
||||||
static ThreadLoadStatus load_threaded_get_status(const String &p_path, float *r_progress = nullptr);
|
static ThreadLoadStatus load_threaded_get_status(const String &p_path, float *r_progress = nullptr);
|
||||||
|
@ -87,7 +87,7 @@
|
|||||||
<param index="0" name="path" type="String" />
|
<param index="0" name="path" type="String" />
|
||||||
<description>
|
<description>
|
||||||
Returns the resource loaded by [method load_threaded_request].
|
Returns the resource loaded by [method load_threaded_request].
|
||||||
If this is called before the loading thread is done (i.e. [method load_threaded_get_status] is not [constant THREAD_LOAD_LOADED]), the calling thread will be blocked until the resource has finished loading.
|
If this is called before the loading thread is done (i.e. [method load_threaded_get_status] is not [constant THREAD_LOAD_LOADED]), the calling thread will be blocked until the resource has finished loading. However, it's recommended to use [method load_threaded_get_status] to known when the load has actually completed.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="load_threaded_get_status">
|
<method name="load_threaded_get_status">
|
||||||
@ -97,6 +97,7 @@
|
|||||||
<description>
|
<description>
|
||||||
Returns the status of a threaded loading operation started with [method load_threaded_request] for the resource at [param path]. See [enum ThreadLoadStatus] for possible return values.
|
Returns the status of a threaded loading operation started with [method load_threaded_request] for the resource at [param path]. See [enum ThreadLoadStatus] for possible return values.
|
||||||
An array variable can optionally be passed via [param progress], and will return a one-element array containing the percentage of completion of the threaded loading.
|
An array variable can optionally be passed via [param progress], and will return a one-element array containing the percentage of completion of the threaded loading.
|
||||||
|
[b]Note:[/b] The recommended way of using this method is to call it during different frames (e.g., in [method Node._process], instead of a loop).
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="load_threaded_request">
|
<method name="load_threaded_request">
|
||||||
|
Loading…
Reference in New Issue
Block a user