Removed interactive loader, added proper thread loading.

This commit is contained in:
Juan Linietsky 2020-02-28 08:27:04 -03:00
parent 5beccaf86f
commit 475e4ea67b
57 changed files with 872 additions and 592 deletions

View File

@ -64,8 +64,21 @@ static const unsigned int MONTH_DAYS_TABLE[2][12] = {
_ResourceLoader *_ResourceLoader::singleton = NULL; _ResourceLoader *_ResourceLoader::singleton = NULL;
Ref<ResourceInteractiveLoader> _ResourceLoader::load_interactive(const String &p_path, const String &p_type_hint) { Error _ResourceLoader::load_threaded_request(const String &p_path, const String &p_type_hint, bool p_use_sub_threads) {
return ResourceLoader::load_interactive(p_path, p_type_hint);
return ResourceLoader::load_threaded_request(p_path, p_type_hint, p_use_sub_threads);
}
_ResourceLoader::ThreadLoadStatus _ResourceLoader::load_threaded_get_status(const String &p_path, Array r_progress) {
float progress = 0;
ResourceLoader::ThreadLoadStatus tls = ResourceLoader::load_threaded_get_status(p_path, &progress);
r_progress.resize(1);
r_progress[0] = progress;
return (ThreadLoadStatus)tls;
}
RES _ResourceLoader::load_threaded_get(const String &p_path) {
Error error;
RES res = ResourceLoader::load_threaded_get(p_path, &error);
return res;
} }
RES _ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache) { RES _ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache) {
@ -120,13 +133,21 @@ bool _ResourceLoader::exists(const String &p_path, const String &p_type_hint) {
void _ResourceLoader::_bind_methods() { void _ResourceLoader::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_interactive", "path", "type_hint"), &_ResourceLoader::load_interactive, DEFVAL("")); ClassDB::bind_method(D_METHOD("load_threaded_request", "path", "type_hint", "use_sub_threads"), &_ResourceLoader::load_threaded_request, DEFVAL(""), DEFVAL(false));
ClassDB::bind_method(D_METHOD("load_threaded_get_status", "path", "r_progress"), &_ResourceLoader::load_threaded_get_status, DEFVAL(Array()));
ClassDB::bind_method(D_METHOD("load_threaded_get", "path"), &_ResourceLoader::load_threaded_get);
ClassDB::bind_method(D_METHOD("load", "path", "type_hint", "no_cache"), &_ResourceLoader::load, DEFVAL(""), DEFVAL(false)); ClassDB::bind_method(D_METHOD("load", "path", "type_hint", "no_cache"), &_ResourceLoader::load, DEFVAL(""), DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_recognized_extensions_for_type", "type"), &_ResourceLoader::get_recognized_extensions_for_type); ClassDB::bind_method(D_METHOD("get_recognized_extensions_for_type", "type"), &_ResourceLoader::get_recognized_extensions_for_type);
ClassDB::bind_method(D_METHOD("set_abort_on_missing_resources", "abort"), &_ResourceLoader::set_abort_on_missing_resources); ClassDB::bind_method(D_METHOD("set_abort_on_missing_resources", "abort"), &_ResourceLoader::set_abort_on_missing_resources);
ClassDB::bind_method(D_METHOD("get_dependencies", "path"), &_ResourceLoader::get_dependencies); ClassDB::bind_method(D_METHOD("get_dependencies", "path"), &_ResourceLoader::get_dependencies);
ClassDB::bind_method(D_METHOD("has_cached", "path"), &_ResourceLoader::has_cached); ClassDB::bind_method(D_METHOD("has_cached", "path"), &_ResourceLoader::has_cached);
ClassDB::bind_method(D_METHOD("exists", "path", "type_hint"), &_ResourceLoader::exists, DEFVAL("")); ClassDB::bind_method(D_METHOD("exists", "path", "type_hint"), &_ResourceLoader::exists, DEFVAL(""));
BIND_ENUM_CONSTANT(THREAD_LOAD_INVALID_RESOURCE);
BIND_ENUM_CONSTANT(THREAD_LOAD_IN_PROGRESS);
BIND_ENUM_CONSTANT(THREAD_LOAD_FAILED);
BIND_ENUM_CONSTANT(THREAD_LOAD_LOADED);
} }
_ResourceLoader::_ResourceLoader() { _ResourceLoader::_ResourceLoader() {

View File

@ -49,8 +49,19 @@ protected:
static _ResourceLoader *singleton; static _ResourceLoader *singleton;
public: public:
enum ThreadLoadStatus {
THREAD_LOAD_INVALID_RESOURCE,
THREAD_LOAD_IN_PROGRESS,
THREAD_LOAD_FAILED,
THREAD_LOAD_LOADED
};
static _ResourceLoader *get_singleton() { return singleton; } static _ResourceLoader *get_singleton() { return singleton; }
Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_type_hint = "");
Error load_threaded_request(const String &p_path, const String &p_type_hint = "", bool p_use_sub_threads = false);
ThreadLoadStatus load_threaded_get_status(const String &p_path, Array r_progress = Array());
RES load_threaded_get(const String &p_path);
RES load(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false); RES load(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false);
Vector<String> get_recognized_extensions_for_type(const String &p_type); Vector<String> get_recognized_extensions_for_type(const String &p_type);
void set_abort_on_missing_resources(bool p_abort); void set_abort_on_missing_resources(bool p_abort);
@ -61,6 +72,8 @@ public:
_ResourceLoader(); _ResourceLoader();
}; };
VARIANT_ENUM_CAST(_ResourceLoader::ThreadLoadStatus);
class _ResourceSaver : public Object { class _ResourceSaver : public Object {
GDCLASS(_ResourceSaver, Object); GDCLASS(_ResourceSaver, Object);

View File

@ -99,7 +99,7 @@ Crypto::Crypto() {
/// Resource loader/saver /// Resource loader/saver
RES ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
String el = p_path.get_extension().to_lower(); String el = p_path.get_extension().to_lower();
if (el == "crt") { if (el == "crt") {

View File

@ -87,7 +87,7 @@ class ResourceFormatLoaderCrypto : public ResourceFormatLoader {
GDCLASS(ResourceFormatLoaderCrypto, ResourceFormatLoader); GDCLASS(ResourceFormatLoaderCrypto, ResourceFormatLoader);
public: public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -129,7 +129,7 @@ void ImageLoader::cleanup() {
///////////////// /////////////////
RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ); FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (!f) { if (!f) {

View File

@ -73,7 +73,7 @@ public:
class ResourceFormatLoaderImage : public ResourceFormatLoader { class ResourceFormatLoaderImage : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -93,7 +93,7 @@ enum {
}; };
void ResourceInteractiveLoaderBinary::_advance_padding(uint32_t p_len) { void ResourceLoaderBinary::_advance_padding(uint32_t p_len) {
uint32_t extra = 4 - (p_len % 4); uint32_t extra = 4 - (p_len % 4);
if (extra < 4) { if (extra < 4) {
@ -102,7 +102,7 @@ void ResourceInteractiveLoaderBinary::_advance_padding(uint32_t p_len) {
} }
} }
StringName ResourceInteractiveLoaderBinary::_get_string() { StringName ResourceLoaderBinary::_get_string() {
uint32_t id = f->get_32(); uint32_t id = f->get_32();
if (id & 0x80000000) { if (id & 0x80000000) {
@ -121,7 +121,7 @@ StringName ResourceInteractiveLoaderBinary::_get_string() {
return string_map[id]; return string_map[id];
} }
Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
uint32_t type = f->get_32(); uint32_t type = f->get_32();
print_bl("find property of type: " + itos(type)); print_bl("find property of type: " + itos(type));
@ -377,20 +377,26 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) {
r_v = Variant(); r_v = Variant();
} else { } else {
String exttype = external_resources[erindex].type; if (external_resources[erindex].cache.is_null()) {
String path = external_resources[erindex].path; //cache not here yet, wait for it?
if (use_sub_threads) {
Error err;
external_resources.write[erindex].cache = ResourceLoader::load_threaded_get(external_resources[erindex].path, &err);
if (path.find("://") == -1 && path.is_rel_path()) { if (err != OK || external_resources[erindex].cache.is_null()) {
// path is relative to file being loaded, so convert to a resource path if (!ResourceLoader::get_abort_on_missing_resources()) {
path = ProjectSettings::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path));
ResourceLoader::notify_dependency_error(local_path, external_resources[erindex].path, external_resources[erindex].type);
} else {
error = ERR_FILE_MISSING_DEPENDENCIES;
ERR_FAIL_V_MSG(error, "Can't load dependency: " + external_resources[erindex].path + ".");
}
}
}
} }
RES res = ResourceLoader::load(path, exttype); r_v = external_resources[erindex].cache;
if (res.is_null()) {
WARN_PRINT(String("Couldn't load resource: " + path).utf8().get_data());
}
r_v = res;
} }
} break; } break;
@ -638,160 +644,168 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) {
return OK; //never reach anyway return OK; //never reach anyway
} }
void ResourceInteractiveLoaderBinary::set_local_path(const String &p_local_path) { void ResourceLoaderBinary::set_local_path(const String &p_local_path) {
res_path = p_local_path; res_path = p_local_path;
} }
Ref<Resource> ResourceInteractiveLoaderBinary::get_resource() { Ref<Resource> ResourceLoaderBinary::get_resource() {
return resource; return resource;
} }
Error ResourceInteractiveLoaderBinary::poll() { Error ResourceLoaderBinary::load() {
if (error != OK) if (error != OK)
return error; return error;
int s = stage; int stage = 0;
if (s < external_resources.size()) { for (int i = 0; i < external_resources.size(); i++) {
String path = external_resources[s].path; String path = external_resources[i].path;
if (remaps.has(path)) { if (remaps.has(path)) {
path = remaps[path]; path = remaps[path];
} }
RES res = ResourceLoader::load(path, external_resources[s].type);
if (res.is_null()) {
if (!ResourceLoader::get_abort_on_missing_resources()) { if (path.find("://") == -1 && path.is_rel_path()) {
// path is relative to file being loaded, so convert to a resource path
path = ProjectSettings::get_singleton()->localize_path(path.get_base_dir().plus_file(external_resources[i].path));
}
ResourceLoader::notify_dependency_error(local_path, path, external_resources[s].type); external_resources.write[i].path = path; //remap happens here, not on load because on load it can actually be used for filesystem dock resource remap
} else {
error = ERR_FILE_MISSING_DEPENDENCIES; if (!use_sub_threads) {
ERR_FAIL_V_MSG(error, "Can't load dependency: " + path + "."); external_resources.write[i].cache = ResourceLoader::load(path, external_resources[i].type);
if (external_resources[i].cache.is_null()) {
if (!ResourceLoader::get_abort_on_missing_resources()) {
ResourceLoader::notify_dependency_error(local_path, path, external_resources[i].type);
} else {
error = ERR_FILE_MISSING_DEPENDENCIES;
ERR_FAIL_V_MSG(error, "Can't load dependency: " + path + ".");
}
} }
} else { } else {
resource_cache.push_back(res); Error err = ResourceLoader::load_threaded_request(path, external_resources[i].type, use_sub_threads, local_path);
if (err != OK) {
if (!ResourceLoader::get_abort_on_missing_resources()) {
ResourceLoader::notify_dependency_error(local_path, path, external_resources[i].type);
} else {
error = ERR_FILE_MISSING_DEPENDENCIES;
ERR_FAIL_V_MSG(error, "Can't load dependency: " + path + ".");
}
}
} }
stage++; stage++;
return error;
} }
s -= external_resources.size(); for (int i = 0; i < internal_resources.size(); i++) {
if (s >= internal_resources.size()) { bool main = i == (internal_resources.size() - 1);
error = ERR_BUG; //maybe it is loaded already
ERR_FAIL_COND_V(s >= internal_resources.size(), error); String path;
} int subindex = 0;
bool main = s == (internal_resources.size() - 1); if (!main) {
//maybe it is loaded already path = internal_resources[i].path;
String path; if (path.begins_with("local://")) {
int subindex = 0; path = path.replace_first("local://", "");
subindex = path.to_int();
path = res_path + "::" + path;
}
if (!main) { if (ResourceCache::has(path)) {
//already loaded, don't do anything
stage++;
error = OK;
continue;
}
} else {
path = internal_resources[s].path; if (!ResourceCache::has(res_path))
if (path.begins_with("local://")) { path = res_path;
path = path.replace_first("local://", "");
subindex = path.to_int();
path = res_path + "::" + path;
} }
if (ResourceCache::has(path)) { uint64_t offset = internal_resources[i].offset;
//already loaded, don't do anything
stage++;
error = OK;
return error;
}
} else {
if (!ResourceCache::has(res_path)) f->seek(offset);
path = res_path;
}
uint64_t offset = internal_resources[s].offset; String t = get_unicode_string();
f->seek(offset); Object *obj = ClassDB::instance(t);
if (!obj) {
String t = get_unicode_string();
Object *obj = ClassDB::instance(t);
if (!obj) {
error = ERR_FILE_CORRUPT;
ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource of unrecognized type in file: " + t + ".");
}
Resource *r = Object::cast_to<Resource>(obj);
if (!r) {
String obj_class = obj->get_class();
error = ERR_FILE_CORRUPT;
memdelete(obj); //bye
ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource type in resource field not a resource, type is: " + obj_class + ".");
}
RES res = RES(r);
r->set_path(path);
r->set_subindex(subindex);
int pc = f->get_32();
//set properties
for (int i = 0; i < pc; i++) {
StringName name = _get_string();
if (name == StringName()) {
error = ERR_FILE_CORRUPT; error = ERR_FILE_CORRUPT;
ERR_FAIL_V(ERR_FILE_CORRUPT); ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource of unrecognized type in file: " + t + ".");
} }
Variant value; Resource *r = Object::cast_to<Resource>(obj);
if (!r) {
String obj_class = obj->get_class();
error = ERR_FILE_CORRUPT;
memdelete(obj); //bye
ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource type in resource field not a resource, type is: " + obj_class + ".");
}
error = parse_variant(value); RES res = RES(r);
if (error)
return error;
res->set(name, value); r->set_path(path);
} r->set_subindex(subindex);
int pc = f->get_32();
//set properties
for (int j = 0; j < pc; j++) {
StringName name = _get_string();
if (name == StringName()) {
error = ERR_FILE_CORRUPT;
ERR_FAIL_V(ERR_FILE_CORRUPT);
}
Variant value;
error = parse_variant(value);
if (error)
return error;
res->set(name, value);
}
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
res->set_edited(false); res->set_edited(false);
#endif #endif
stage++; stage++;
resource_cache.push_back(res); if (progress) {
*progress = (i + 1) / float(internal_resources.size());
}
if (main) { resource_cache.push_back(res);
f->close(); if (main) {
resource = res;
resource->set_as_translation_remapped(translation_remapped);
error = ERR_FILE_EOF;
} else { f->close();
error = OK; resource = res;
resource->set_as_translation_remapped(translation_remapped);
error = OK;
return OK;
}
} }
return OK; return ERR_FILE_EOF;
}
int ResourceInteractiveLoaderBinary::get_stage() const {
return stage;
}
int ResourceInteractiveLoaderBinary::get_stage_count() const {
return external_resources.size() + internal_resources.size();
} }
void ResourceInteractiveLoaderBinary::set_translation_remapped(bool p_remapped) { void ResourceLoaderBinary::set_translation_remapped(bool p_remapped) {
translation_remapped = p_remapped; translation_remapped = p_remapped;
} }
@ -814,7 +828,7 @@ static String get_ustring(FileAccess *f) {
return s; return s;
} }
String ResourceInteractiveLoaderBinary::get_unicode_string() { String ResourceLoaderBinary::get_unicode_string() {
int len = f->get_32(); int len = f->get_32();
if (len > str_buf.size()) { if (len > str_buf.size()) {
@ -828,7 +842,7 @@ String ResourceInteractiveLoaderBinary::get_unicode_string() {
return s; return s;
} }
void ResourceInteractiveLoaderBinary::get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types) { void ResourceLoaderBinary::get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types) {
open(p_f); open(p_f);
if (error) if (error)
@ -846,7 +860,7 @@ void ResourceInteractiveLoaderBinary::get_dependencies(FileAccess *p_f, List<Str
} }
} }
void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) { void ResourceLoaderBinary::open(FileAccess *p_f) {
error = OK; error = OK;
@ -947,7 +961,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) {
} }
} }
String ResourceInteractiveLoaderBinary::recognize(FileAccess *p_f) { String ResourceLoaderBinary::recognize(FileAccess *p_f) {
error = OK; error = OK;
@ -992,20 +1006,22 @@ String ResourceInteractiveLoaderBinary::recognize(FileAccess *p_f) {
return type; return type;
} }
ResourceInteractiveLoaderBinary::ResourceInteractiveLoaderBinary() : ResourceLoaderBinary::ResourceLoaderBinary() :
translation_remapped(false), translation_remapped(false),
f(NULL), f(NULL),
error(OK), error(OK) {
stage(0) {
progress = nullptr;
use_sub_threads = false;
} }
ResourceInteractiveLoaderBinary::~ResourceInteractiveLoaderBinary() { ResourceLoaderBinary::~ResourceLoaderBinary() {
if (f) if (f)
memdelete(f); memdelete(f);
} }
Ref<ResourceInteractiveLoader> ResourceFormatLoaderBinary::load_interactive(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoaderBinary::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
if (r_error) if (r_error)
*r_error = ERR_FILE_CANT_OPEN; *r_error = ERR_FILE_CANT_OPEN;
@ -1013,16 +1029,27 @@ Ref<ResourceInteractiveLoader> ResourceFormatLoaderBinary::load_interactive(cons
Error err; Error err;
FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
ERR_FAIL_COND_V_MSG(err != OK, Ref<ResourceInteractiveLoader>(), "Cannot open file '" + p_path + "'."); ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot open file '" + p_path + "'.");
Ref<ResourceInteractiveLoaderBinary> ria = memnew(ResourceInteractiveLoaderBinary); ResourceLoaderBinary loader;
loader.use_sub_threads = p_use_sub_threads;
loader.progress = r_progress;
String path = p_original_path != "" ? p_original_path : p_path; String path = p_original_path != "" ? p_original_path : p_path;
ria->local_path = ProjectSettings::get_singleton()->localize_path(path); loader.local_path = ProjectSettings::get_singleton()->localize_path(path);
ria->res_path = ria->local_path; loader.res_path = loader.local_path;
//ria->set_local_path( Globals::get_singleton()->localize_path(p_path) ); //loader.set_local_path( Globals::get_singleton()->localize_path(p_path) );
ria->open(f); loader.open(f);
return ria; err = loader.load();
if (r_error) {
*r_error = err;
}
if (err) {
return RES();
}
return loader.resource;
} }
void ResourceFormatLoaderBinary::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const { void ResourceFormatLoaderBinary::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const {
@ -1064,11 +1091,11 @@ void ResourceFormatLoaderBinary::get_dependencies(const String &p_path, List<Str
FileAccess *f = FileAccess::open(p_path, FileAccess::READ); FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_MSG(!f, "Cannot open file '" + p_path + "'."); ERR_FAIL_COND_MSG(!f, "Cannot open file '" + p_path + "'.");
Ref<ResourceInteractiveLoaderBinary> ria = memnew(ResourceInteractiveLoaderBinary); ResourceLoaderBinary loader;
ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
ria->res_path = ria->local_path; loader.res_path = loader.local_path;
//ria->set_local_path( Globals::get_singleton()->localize_path(p_path) ); //loader.set_local_path( Globals::get_singleton()->localize_path(p_path) );
ria->get_dependencies(f, p_dependencies, p_add_types); loader.get_dependencies(f, p_dependencies, p_add_types);
} }
Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, const Map<String, String> &p_map) { Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, const Map<String, String> &p_map) {
@ -1153,21 +1180,17 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
ERR_FAIL_COND_V_MSG(err != OK, ERR_FILE_CANT_OPEN, "Cannot open file '" + p_path + "'."); ERR_FAIL_COND_V_MSG(err != OK, ERR_FILE_CANT_OPEN, "Cannot open file '" + p_path + "'.");
Ref<ResourceInteractiveLoaderBinary> ria = memnew(ResourceInteractiveLoaderBinary); ResourceLoaderBinary loader;
ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
ria->res_path = ria->local_path; loader.res_path = loader.local_path;
ria->remaps = p_map; loader.remaps = p_map;
//ria->set_local_path( Globals::get_singleton()->localize_path(p_path) ); //loader.set_local_path( Globals::get_singleton()->localize_path(p_path) );
ria->open(f); loader.open(f);
err = ria->poll(); err = loader.load();
while (err == OK) {
err = ria->poll();
}
ERR_FAIL_COND_V(err != ERR_FILE_EOF, ERR_FILE_CORRUPT); ERR_FAIL_COND_V(err != ERR_FILE_EOF, ERR_FILE_CORRUPT);
RES res = ria->get_resource(); RES res = loader.get_resource();
ERR_FAIL_COND_V(!res.is_valid(), ERR_FILE_CORRUPT); ERR_FAIL_COND_V(!res.is_valid(), ERR_FILE_CORRUPT);
return ResourceFormatSaverBinary::singleton->save(p_path, res); return ResourceFormatSaverBinary::singleton->save(p_path, res);
@ -1283,11 +1306,11 @@ String ResourceFormatLoaderBinary::get_resource_type(const String &p_path) const
return ""; //could not rwead return ""; //could not rwead
} }
Ref<ResourceInteractiveLoaderBinary> ria = memnew(ResourceInteractiveLoaderBinary); ResourceLoaderBinary loader;
ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
ria->res_path = ria->local_path; loader.res_path = loader.local_path;
//ria->set_local_path( Globals::get_singleton()->localize_path(p_path) ); //loader.set_local_path( Globals::get_singleton()->localize_path(p_path) );
String r = ria->recognize(f); String r = loader.recognize(f);
return ClassDB::get_compatibility_remapped_class(r); return ClassDB::get_compatibility_remapped_class(r);
} }

View File

@ -35,7 +35,7 @@
#include "core/io/resource_saver.h" #include "core/io/resource_saver.h"
#include "core/os/file_access.h" #include "core/os/file_access.h"
class ResourceInteractiveLoaderBinary : public ResourceInteractiveLoader { class ResourceLoaderBinary {
bool translation_remapped; bool translation_remapped;
String local_path; String local_path;
@ -58,8 +58,11 @@ class ResourceInteractiveLoaderBinary : public ResourceInteractiveLoader {
struct ExtResource { struct ExtResource {
String path; String path;
String type; String type;
RES cache;
}; };
bool use_sub_threads;
float *progress;
Vector<ExtResource> external_resources; Vector<ExtResource> external_resources;
struct IntResource { struct IntResource {
@ -75,32 +78,30 @@ class ResourceInteractiveLoaderBinary : public ResourceInteractiveLoader {
Map<String, String> remaps; Map<String, String> remaps;
Error error; Error error;
int stage;
friend class ResourceFormatLoaderBinary; friend class ResourceFormatLoaderBinary;
Error parse_variant(Variant &r_v); Error parse_variant(Variant &r_v);
Map<String, RES> dependency_cache;
public: public:
virtual void set_local_path(const String &p_local_path); void set_local_path(const String &p_local_path);
virtual Ref<Resource> get_resource(); Ref<Resource> get_resource();
virtual Error poll(); Error load();
virtual int get_stage() const; void set_translation_remapped(bool p_remapped);
virtual int get_stage_count() const;
virtual void set_translation_remapped(bool p_remapped);
void set_remaps(const Map<String, String> &p_remaps) { remaps = p_remaps; } void set_remaps(const Map<String, String> &p_remaps) { remaps = p_remaps; }
void open(FileAccess *p_f); void open(FileAccess *p_f);
String recognize(FileAccess *p_f); String recognize(FileAccess *p_f);
void get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types); void get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types);
ResourceInteractiveLoaderBinary(); ResourceLoaderBinary();
~ResourceInteractiveLoaderBinary(); ~ResourceLoaderBinary();
}; };
class ResourceFormatLoaderBinary : public ResourceFormatLoader { class ResourceFormatLoaderBinary : public ResourceFormatLoader {
public: public:
virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;

View File

@ -117,7 +117,7 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy
return OK; return OK;
} }
RES ResourceFormatImporter::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatImporter::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
PathAndType pat; PathAndType pat;
Error err = _get_path_and_type(p_path, pat); Error err = _get_path_and_type(p_path, pat);
@ -130,7 +130,7 @@ RES ResourceFormatImporter::load(const String &p_path, const String &p_original_
return RES(); return RES();
} }
RES res = ResourceLoader::_load(pat.path, p_path, pat.type, false, r_error); RES res = ResourceLoader::_load(pat.path, p_path, pat.type, false, r_error, p_use_sub_threads, r_progress);
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
if (res.is_valid()) { if (res.is_valid()) {

View File

@ -58,7 +58,7 @@ class ResourceFormatImporter : public ResourceFormatLoader {
public: public:
static ResourceFormatImporter *get_singleton() { return singleton; } static ResourceFormatImporter *get_singleton() { return singleton; }
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const; virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const;

View File

@ -39,26 +39,16 @@
#include "core/translation.h" #include "core/translation.h"
#include "core/variant_parser.h" #include "core/variant_parser.h"
#ifdef DEBUG_LOAD_THREADED
#define print_lt(m_text) print_line(m_text)
#else
#define print_lt(m_text)
#endif
Ref<ResourceFormatLoader> ResourceLoader::loader[ResourceLoader::MAX_LOADERS]; Ref<ResourceFormatLoader> ResourceLoader::loader[ResourceLoader::MAX_LOADERS];
int ResourceLoader::loader_count = 0; int ResourceLoader::loader_count = 0;
Error ResourceInteractiveLoader::wait() {
Error err = poll();
while (err == OK) {
err = poll();
}
return err;
}
ResourceInteractiveLoader::~ResourceInteractiveLoader() {
if (path_loading != String()) {
ResourceLoader::_remove_from_loading_map_and_thread(path_loading, path_loading_thread);
}
}
bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_for_type) const { bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_for_type) const {
String extension = p_path.get_extension(); String extension = p_path.get_extension();
@ -111,45 +101,6 @@ void ResourceLoader::get_recognized_extensions_for_type(const String &p_type, Li
} }
} }
void ResourceInteractiveLoader::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_resource"), &ResourceInteractiveLoader::get_resource);
ClassDB::bind_method(D_METHOD("poll"), &ResourceInteractiveLoader::poll);
ClassDB::bind_method(D_METHOD("wait"), &ResourceInteractiveLoader::wait);
ClassDB::bind_method(D_METHOD("get_stage"), &ResourceInteractiveLoader::get_stage);
ClassDB::bind_method(D_METHOD("get_stage_count"), &ResourceInteractiveLoader::get_stage_count);
}
class ResourceInteractiveLoaderDefault : public ResourceInteractiveLoader {
GDCLASS(ResourceInteractiveLoaderDefault, ResourceInteractiveLoader);
public:
Ref<Resource> resource;
virtual void set_local_path(const String &p_local_path) { /*scene->set_filename(p_local_path);*/
}
virtual Ref<Resource> get_resource() { return resource; }
virtual Error poll() { return ERR_FILE_EOF; }
virtual int get_stage() const { return 1; }
virtual int get_stage_count() const { return 1; }
virtual void set_translation_remapped(bool p_remapped) { resource->set_as_translation_remapped(p_remapped); }
ResourceInteractiveLoaderDefault() {}
};
Ref<ResourceInteractiveLoader> ResourceFormatLoader::load_interactive(const String &p_path, const String &p_original_path, Error *r_error) {
//either this
Ref<Resource> res = load(p_path, p_original_path, r_error);
if (res.is_null())
return Ref<ResourceInteractiveLoader>();
Ref<ResourceInteractiveLoaderDefault> ril = Ref<ResourceInteractiveLoaderDefault>(memnew(ResourceInteractiveLoaderDefault));
ril->resource = res;
return ril;
}
bool ResourceFormatLoader::exists(const String &p_path) const { bool ResourceFormatLoader::exists(const String &p_path) const {
return FileAccess::exists(p_path); //by default just check file return FileAccess::exists(p_path); //by default just check file
} }
@ -168,10 +119,10 @@ void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions)
} }
} }
RES ResourceFormatLoader::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
if (get_script_instance() && get_script_instance()->has_method("load")) { if (get_script_instance() && get_script_instance()->has_method("load")) {
Variant res = get_script_instance()->call("load", p_path, p_original_path); Variant res = get_script_instance()->call("load", p_path, p_original_path, p_use_sub_threads);
if (res.get_type() == Variant::INT) { if (res.get_type() == Variant::INT) {
@ -184,29 +135,11 @@ RES ResourceFormatLoader::load(const String &p_path, const String &p_original_pa
*r_error = OK; *r_error = OK;
return res; return res;
} }
return res;
} }
//or this must be implemented ERR_FAIL_V_MSG(RES(), "Failed to load resource '" + p_path + "', ResourceFormatLoader::load was not implemented for this resource type.");
Ref<ResourceInteractiveLoader> ril = load_interactive(p_path, p_original_path, r_error);
if (!ril.is_valid())
return RES();
ril->set_local_path(p_original_path);
while (true) {
Error err = ril->poll();
if (err == ERR_FILE_EOF) {
if (r_error)
*r_error = OK;
return ril->get_resource();
}
if (r_error)
*r_error = err;
ERR_FAIL_COND_V_MSG(err != OK, RES(), "Failed to load resource '" + p_path + "'.");
}
} }
void ResourceFormatLoader::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) { void ResourceFormatLoader::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
@ -256,7 +189,7 @@ void ResourceFormatLoader::_bind_methods() {
/////////////////////////////////// ///////////////////////////////////
RES ResourceLoader::_load(const String &p_path, const String &p_original_path, const String &p_type_hint, bool p_no_cache, Error *r_error) { RES ResourceLoader::_load(const String &p_path, const String &p_original_path, const String &p_type_hint, bool p_no_cache, Error *r_error, bool p_use_sub_threads, float *r_progress) {
bool found = false; bool found = false;
@ -267,7 +200,7 @@ RES ResourceLoader::_load(const String &p_path, const String &p_original_path, c
continue; continue;
} }
found = true; found = true;
RES res = loader[i]->load(p_path, p_original_path != String() ? p_original_path : p_path, r_error); RES res = loader[i]->load(p_path, p_original_path != String() ? p_original_path : p_path, r_error, p_use_sub_threads, r_progress);
if (res.is_null()) { if (res.is_null()) {
continue; continue;
} }
@ -285,43 +218,302 @@ RES ResourceLoader::_load(const String &p_path, const String &p_original_path, c
ERR_FAIL_V_MSG(RES(), "No loader found for resource: " + p_path + "."); ERR_FAIL_V_MSG(RES(), "No loader found for resource: " + p_path + ".");
} }
bool ResourceLoader::_add_to_loading_map(const String &p_path) { void ResourceLoader::_thread_load_function(void *p_userdata) {
bool success; ThreadLoadTask &load_task = *(ThreadLoadTask *)p_userdata;
MutexLock lock(loading_map_mutex); load_task.loader_id = Thread::get_caller_id();
LoadingMapKey key; if (load_task.semaphore) {
key.path = p_path; //this is an actual thread, so wait for Ok fom semaphore
key.thread = Thread::get_caller_id(); thread_load_semaphore->wait(); //wait until its ok to start loading
}
load_task.resource = _load(load_task.remapped_path, load_task.remapped_path != load_task.local_path ? load_task.local_path : String(), load_task.type_hint, false, &load_task.error, load_task.use_sub_threads, &load_task.progress);
if (loading_map.has(key)) { load_task.progress = 1.0; //it was fully loaded at this point, so force progress to 1.0
success = false;
thread_load_mutex->lock();
if (load_task.error != OK) {
load_task.status = THREAD_LOAD_FAILED;
} else { } else {
loading_map[key] = true; load_task.status = THREAD_LOAD_LOADED;
success = true; }
if (load_task.semaphore) {
if (load_task.start_next && thread_waiting_count > 0) {
thread_waiting_count--;
//thread loading count remains constant, this ends but another one begins
thread_load_semaphore->post();
} else {
thread_loading_count--; //no threads waiting, just reduce loading count
}
print_lt("END: load count: " + itos(thread_loading_count) + " / wait count: " + itos(thread_waiting_count) + " / suspended count: " + itos(thread_suspended_count) + " / active: " + itos(thread_loading_count - thread_suspended_count));
for (int i = 0; i < load_task.poll_requests; i++) {
load_task.semaphore->post();
}
memdelete(load_task.semaphore);
load_task.semaphore = nullptr;
} }
return success; if (load_task.resource.is_valid()) {
load_task.resource->set_path(load_task.local_path);
if (load_task.xl_remapped)
load_task.resource->set_as_translation_remapped(true);
#ifdef TOOLS_ENABLED
load_task.resource->set_edited(false);
if (timestamp_on_load) {
uint64_t mt = FileAccess::get_modified_time(load_task.remapped_path);
//printf("mt %s: %lli\n",remapped_path.utf8().get_data(),mt);
load_task.resource->set_last_modified_time(mt);
}
#endif
if (_loaded_callback) {
_loaded_callback(load_task.resource, load_task.local_path);
}
}
thread_load_mutex->unlock();
}
Error ResourceLoader::load_threaded_request(const String &p_path, const String &p_type_hint, bool p_use_sub_threads, const String &p_source_resource) {
String local_path;
if (p_path.is_rel_path())
local_path = "res://" + p_path;
else
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
thread_load_mutex->lock();
if (p_source_resource != String()) {
//must be loading from this resource
if (!thread_load_tasks.has(p_source_resource)) {
thread_load_mutex->unlock();
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "There is no thread loading source resource '" + p_source_resource + "'.");
}
//must be loading from this thread
if (thread_load_tasks[p_source_resource].loader_id != Thread::get_caller_id()) {
thread_load_mutex->unlock();
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Threading loading resource'" + local_path + " failed: Source specified: '" + p_source_resource + "' but was not called by it.");
}
//must not be already added as s sub tasks
if (thread_load_tasks[p_source_resource].sub_tasks.has(local_path)) {
thread_load_mutex->unlock();
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Thread loading source resource '" + p_source_resource + "' already is loading '" + local_path + "'.");
}
}
if (thread_load_tasks.has(local_path)) {
thread_load_tasks[local_path].requests++;
if (p_source_resource != String()) {
thread_load_tasks[p_source_resource].sub_tasks.insert(local_path);
}
thread_load_mutex->unlock();
return OK;
}
{
//create load task
ThreadLoadTask load_task;
load_task.requests = 1;
load_task.remapped_path = _path_remap(local_path, &load_task.xl_remapped);
load_task.local_path = local_path;
load_task.type_hint = p_type_hint;
load_task.use_sub_threads = p_use_sub_threads;
{ //must check if resource is already loaded before attempting to load it in a thread
if (load_task.loader_id == Thread::get_caller_id()) {
thread_load_mutex->unlock();
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Attempted to load a resource already being loaded from this thread, cyclic reference?");
}
//lock first if possible
if (ResourceCache::lock) {
ResourceCache::lock->read_lock();
}
//get ptr
Resource **rptr = ResourceCache::resources.getptr(local_path);
if (rptr) {
RES res(*rptr);
//it is possible this resource was just freed in a thread. If so, this referencing will not work and resource is considered not cached
if (res.is_valid()) {
//referencing is fine
load_task.resource = res;
load_task.status = THREAD_LOAD_LOADED;
load_task.progress = 1.0;
}
}
if (ResourceCache::lock) {
ResourceCache::lock->read_unlock();
}
}
if (p_source_resource != String()) {
thread_load_tasks[p_source_resource].sub_tasks.insert(local_path);
}
thread_load_tasks[local_path] = load_task;
}
ThreadLoadTask &load_task = thread_load_tasks[local_path];
if (load_task.resource.is_null()) { //needs to be loaded in thread
load_task.semaphore = memnew(Semaphore);
if (thread_loading_count < thread_load_max) {
thread_loading_count++;
thread_load_semaphore->post(); //we have free threads, so allow one
} else {
thread_waiting_count++;
}
print_lt("REQUEST: load count: " + itos(thread_loading_count) + " / wait count: " + itos(thread_waiting_count) + " / suspended count: " + itos(thread_suspended_count) + " / active: " + itos(thread_loading_count - thread_suspended_count));
load_task.thread = Thread::create(_thread_load_function, &thread_load_tasks[local_path]);
load_task.loader_id = load_task.thread->get_id();
}
thread_load_mutex->unlock();
return OK;
} }
void ResourceLoader::_remove_from_loading_map(const String &p_path) { float ResourceLoader::_dependency_get_progress(const String &p_path) {
MutexLock lock(loading_map_mutex);
LoadingMapKey key; if (thread_load_tasks.has(p_path)) {
key.path = p_path; ThreadLoadTask &load_task = thread_load_tasks[p_path];
key.thread = Thread::get_caller_id(); int dep_count = load_task.sub_tasks.size();
if (dep_count > 0) {
float dep_progress = 0;
for (Set<String>::Element *E = load_task.sub_tasks.front(); E; E = E->next()) {
dep_progress += _dependency_get_progress(E->get());
}
dep_progress /= float(dep_count);
dep_progress *= 0.5;
dep_progress += load_task.progress * 0.5;
return dep_progress;
} else {
return load_task.progress;
}
loading_map.erase(key); } else {
return 1.0; //assume finished loading it so it no longer exists
}
} }
void ResourceLoader::_remove_from_loading_map_and_thread(const String &p_path, Thread::ID p_thread) { ResourceLoader::ThreadLoadStatus ResourceLoader::load_threaded_get_status(const String &p_path, float *r_progress) {
MutexLock lock(loading_map_mutex);
LoadingMapKey key; String local_path;
key.path = p_path; if (p_path.is_rel_path())
key.thread = p_thread; local_path = "res://" + p_path;
else
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
loading_map.erase(key); thread_load_mutex->lock();
if (!thread_load_tasks.has(local_path)) {
thread_load_mutex->unlock();
return THREAD_LOAD_INVALID_RESOURCE;
}
ThreadLoadTask &load_task = thread_load_tasks[local_path];
ThreadLoadStatus status;
status = load_task.status;
if (r_progress) {
*r_progress = _dependency_get_progress(local_path);
}
thread_load_mutex->unlock();
return status;
}
RES ResourceLoader::load_threaded_get(const String &p_path, Error *r_error) {
String local_path;
if (p_path.is_rel_path())
local_path = "res://" + p_path;
else
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
thread_load_mutex->lock();
if (!thread_load_tasks.has(local_path)) {
thread_load_mutex->unlock();
if (r_error) {
*r_error = ERR_INVALID_PARAMETER;
}
return RES();
}
ThreadLoadTask &load_task = thread_load_tasks[local_path];
//semaphore still exists, meaning its still loading, request poll
Semaphore *semaphore = load_task.semaphore;
if (semaphore) {
load_task.poll_requests++;
{
// As we got a semaphore, this means we are going to have to wait
// until the sub-resource is done loading
//
// As this thread will become 'blocked' we should "echange" its
// active status with a waiting one, to ensure load continues.
//
// This ensures loading is never blocked and that is also within
// the maximum number of active threads.
if (thread_waiting_count > 0) {
thread_waiting_count--;
thread_loading_count++;
thread_load_semaphore->post();
load_task.start_next = false; //do not start next since we are doing it here
}
thread_suspended_count++;
print_lt("GET: load count: " + itos(thread_loading_count) + " / wait count: " + itos(thread_waiting_count) + " / suspended count: " + itos(thread_suspended_count) + " / active: " + itos(thread_loading_count - thread_suspended_count));
}
thread_load_mutex->unlock();
semaphore->wait();
thread_load_mutex->lock();
thread_suspended_count--;
if (!thread_load_tasks.has(local_path)) { //may have been erased during unlock and this was always an invalid call
thread_load_mutex->unlock();
if (r_error) {
*r_error = ERR_INVALID_PARAMETER;
}
return RES();
}
}
RES resource = load_task.resource;
if (r_error) {
*r_error = load_task.error;
}
load_task.requests--;
if (load_task.requests == 0) {
if (load_task.thread) { //thread may not have been used
Thread::wait_to_finish(load_task.thread);
memdelete(load_task.thread);
}
thread_load_tasks.erase(local_path);
}
thread_load_mutex->unlock();
return resource;
} }
RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache, Error *r_error) { RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache, Error *r_error) {
@ -337,83 +529,101 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
if (!p_no_cache) { if (!p_no_cache) {
{ thread_load_mutex->lock();
bool success = _add_to_loading_map(local_path);
ERR_FAIL_COND_V_MSG(!success, RES(), "Resource: '" + local_path + "' is already being loaded. Cyclic reference?"); //Is it already being loaded? poll until done
if (thread_load_tasks.has(local_path)) {
Error err = load_threaded_request(p_path, p_type_hint);
if (err != OK) {
if (r_error) {
*r_error = err;
}
return RES();
}
thread_load_mutex->unlock();
return load_threaded_get(p_path, r_error);
} }
//lock first if possible //Is it cached?
if (ResourceCache::lock) { if (ResourceCache::lock) {
ResourceCache::lock->read_lock(); ResourceCache::lock->read_lock();
} }
//get ptr
Resource **rptr = ResourceCache::resources.getptr(local_path); Resource **rptr = ResourceCache::resources.getptr(local_path);
if (rptr) { if (rptr) {
RES res(*rptr); RES res(*rptr);
//it is possible this resource was just freed in a thread. If so, this referencing will not work and resource is considered not cached //it is possible this resource was just freed in a thread. If so, this referencing will not work and resource is considered not cached
if (res.is_valid()) { if (res.is_valid()) {
//referencing is fine
if (r_error)
*r_error = OK;
if (ResourceCache::lock) { if (ResourceCache::lock) {
ResourceCache::lock->read_unlock(); ResourceCache::lock->read_unlock();
} }
_remove_from_loading_map(local_path); thread_load_mutex->unlock();
return res;
if (r_error) {
*r_error = OK;
}
return res; //use cached
} }
} }
if (ResourceCache::lock) { if (ResourceCache::lock) {
ResourceCache::lock->read_unlock(); ResourceCache::lock->read_unlock();
} }
}
bool xl_remapped = false; //load using task (but this thread)
String path = _path_remap(local_path, &xl_remapped); ThreadLoadTask load_task;
if (path == "") { load_task.requests = 1;
if (!p_no_cache) { load_task.local_path = local_path;
_remove_from_loading_map(local_path); load_task.remapped_path = _path_remap(local_path, &load_task.xl_remapped);
load_task.type_hint = p_type_hint;
load_task.loader_id = Thread::get_caller_id();
thread_load_tasks[local_path] = load_task;
thread_load_mutex->unlock();
_thread_load_function(&thread_load_tasks[local_path]);
return load_threaded_get(p_path, r_error);
} else {
bool xl_remapped = false;
String path = _path_remap(local_path, &xl_remapped);
if (path == "") {
ERR_FAIL_V_MSG(RES(), "Remapping '" + local_path + "' failed.");
} }
ERR_FAIL_V_MSG(RES(), "Remapping '" + local_path + "' failed.");
}
print_verbose("Loading resource: " + path); print_verbose("Loading resource: " + path);
RES res = _load(path, local_path, p_type_hint, p_no_cache, r_error); float p;
RES res = _load(path, local_path, p_type_hint, p_no_cache, r_error, false, &p);
if (res.is_null()) { if (res.is_null()) {
if (!p_no_cache) { print_verbose("Failed loading resource: " + path);
_remove_from_loading_map(local_path); return RES();
} }
print_verbose("Failed loading resource: " + path);
return RES();
}
if (!p_no_cache)
res->set_path(local_path);
if (xl_remapped) if (xl_remapped)
res->set_as_translation_remapped(true); res->set_as_translation_remapped(true);
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
res->set_edited(false); res->set_edited(false);
if (timestamp_on_load) { if (timestamp_on_load) {
uint64_t mt = FileAccess::get_modified_time(path); uint64_t mt = FileAccess::get_modified_time(path);
//printf("mt %s: %lli\n",remapped_path.utf8().get_data(),mt); //printf("mt %s: %lli\n",remapped_path.utf8().get_data(),mt);
res->set_last_modified_time(mt); res->set_last_modified_time(mt);
} }
#endif #endif
if (!p_no_cache) { return res;
_remove_from_loading_map(local_path);
} }
if (_loaded_callback) {
_loaded_callback(res, p_path);
}
return res;
} }
bool ResourceLoader::exists(const String &p_path, const String &p_type_hint) { bool ResourceLoader::exists(const String &p_path, const String &p_type_hint) {
@ -446,76 +656,6 @@ bool ResourceLoader::exists(const String &p_path, const String &p_type_hint) {
return false; return false;
} }
Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_path, const String &p_type_hint, bool p_no_cache, Error *r_error) {
if (r_error)
*r_error = ERR_CANT_OPEN;
String local_path;
if (p_path.is_rel_path())
local_path = "res://" + p_path;
else
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
if (!p_no_cache) {
bool success = _add_to_loading_map(local_path);
ERR_FAIL_COND_V_MSG(!success, RES(), "Resource: '" + local_path + "' is already being loaded. Cyclic reference?");
if (ResourceCache::has(local_path)) {
print_verbose("Loading resource: " + local_path + " (cached)");
Ref<Resource> res_cached = ResourceCache::get(local_path);
Ref<ResourceInteractiveLoaderDefault> ril = Ref<ResourceInteractiveLoaderDefault>(memnew(ResourceInteractiveLoaderDefault));
ril->resource = res_cached;
ril->path_loading = local_path;
ril->path_loading_thread = Thread::get_caller_id();
return ril;
}
}
bool xl_remapped = false;
String path = _path_remap(local_path, &xl_remapped);
if (path == "") {
if (!p_no_cache) {
_remove_from_loading_map(local_path);
}
ERR_FAIL_V_MSG(RES(), "Remapping '" + local_path + "' failed.");
}
print_verbose("Loading resource: " + path);
bool found = false;
for (int i = 0; i < loader_count; i++) {
if (!loader[i]->recognize_path(path, p_type_hint))
continue;
found = true;
Ref<ResourceInteractiveLoader> ril = loader[i]->load_interactive(path, local_path, r_error);
if (ril.is_null())
continue;
if (!p_no_cache) {
ril->set_local_path(local_path);
ril->path_loading = local_path;
ril->path_loading_thread = Thread::get_caller_id();
}
if (xl_remapped)
ril->set_translation_remapped(true);
return ril;
}
if (!p_no_cache) {
_remove_from_loading_map(local_path);
}
ERR_FAIL_COND_V_MSG(found, Ref<ResourceInteractiveLoader>(), "Failed loading resource: " + path + ".");
ERR_FAIL_V_MSG(Ref<ResourceInteractiveLoader>(), "No loader found for resource: " + path + ".");
}
void ResourceLoader::add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front) { void ResourceLoader::add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front) {
ERR_FAIL_COND(p_format_loader.is_null()); ERR_FAIL_COND(p_format_loader.is_null());
@ -984,20 +1124,19 @@ void ResourceLoader::remove_custom_loaders() {
} }
} }
Mutex ResourceLoader::loading_map_mutex;
HashMap<ResourceLoader::LoadingMapKey, int, ResourceLoader::LoadingMapKeyHasher> ResourceLoader::loading_map;
void ResourceLoader::initialize() { void ResourceLoader::initialize() {
thread_load_mutex = memnew(Mutex);
thread_load_max = OS::get_singleton()->get_processor_count();
thread_loading_count = 0;
thread_waiting_count = 0;
thread_suspended_count = 0;
thread_load_semaphore = memnew(Semaphore);
} }
void ResourceLoader::finalize() { void ResourceLoader::finalize() {
#ifndef NO_THREADS
const LoadingMapKey *K = NULL; memdelete(thread_load_mutex);
while ((K = loading_map.next(K))) { memdelete(thread_load_semaphore);
ERR_PRINT("Exited while resource is being loaded: " + K->path);
}
loading_map.clear();
#endif
} }
ResourceLoadErrorNotify ResourceLoader::err_notify = NULL; ResourceLoadErrorNotify ResourceLoader::err_notify = NULL;
@ -1009,6 +1148,15 @@ void *ResourceLoader::dep_err_notify_ud = NULL;
bool ResourceLoader::abort_on_missing_resource = true; bool ResourceLoader::abort_on_missing_resource = true;
bool ResourceLoader::timestamp_on_load = false; bool ResourceLoader::timestamp_on_load = false;
Mutex *ResourceLoader::thread_load_mutex = nullptr;
HashMap<String, ResourceLoader::ThreadLoadTask> ResourceLoader::thread_load_tasks;
Semaphore *ResourceLoader::thread_load_semaphore = nullptr;
int ResourceLoader::thread_loading_count = 0;
int ResourceLoader::thread_waiting_count = 0;
int ResourceLoader::thread_suspended_count = 0;
int ResourceLoader::thread_load_max = 0;
SelfList<Resource>::List ResourceLoader::remapped_list; SelfList<Resource>::List ResourceLoader::remapped_list;
HashMap<String, Vector<String> > ResourceLoader::translation_remaps; HashMap<String, Vector<String> > ResourceLoader::translation_remaps;
HashMap<String, String> ResourceLoader::path_remaps; HashMap<String, String> ResourceLoader::path_remaps;

View File

@ -31,32 +31,10 @@
#ifndef RESOURCE_LOADER_H #ifndef RESOURCE_LOADER_H
#define RESOURCE_LOADER_H #define RESOURCE_LOADER_H
#include "core/os/semaphore.h"
#include "core/os/thread.h" #include "core/os/thread.h"
#include "core/resource.h" #include "core/resource.h"
class ResourceInteractiveLoader : public Reference {
GDCLASS(ResourceInteractiveLoader, Reference);
friend class ResourceLoader;
String path_loading;
Thread::ID path_loading_thread;
protected:
static void _bind_methods();
public:
virtual void set_local_path(const String &p_local_path) = 0;
virtual Ref<Resource> get_resource() = 0;
virtual Error poll() = 0;
virtual int get_stage() const = 0;
virtual int get_stage_count() const = 0;
virtual void set_translation_remapped(bool p_remapped) = 0;
virtual Error wait();
ResourceInteractiveLoader() {}
~ResourceInteractiveLoader();
};
class ResourceFormatLoader : public Reference { class ResourceFormatLoader : public Reference {
GDCLASS(ResourceFormatLoader, Reference); GDCLASS(ResourceFormatLoader, Reference);
@ -65,8 +43,7 @@ protected:
static void _bind_methods(); static void _bind_methods();
public: public:
virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL);
virtual bool exists(const String &p_path) const; virtual bool exists(const String &p_path) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
@ -95,6 +72,15 @@ class ResourceLoader {
MAX_LOADERS = 64 MAX_LOADERS = 64
}; };
public:
enum ThreadLoadStatus {
THREAD_LOAD_INVALID_RESOURCE,
THREAD_LOAD_IN_PROGRESS,
THREAD_LOAD_FAILED,
THREAD_LOAD_LOADED
};
private:
static Ref<ResourceFormatLoader> loader[MAX_LOADERS]; static Ref<ResourceFormatLoader> loader[MAX_LOADERS];
static int loader_count; static int loader_count;
static bool timestamp_on_load; static bool timestamp_on_load;
@ -115,34 +101,47 @@ class ResourceLoader {
friend class ResourceFormatImporter; friend class ResourceFormatImporter;
friend class ResourceInteractiveLoader; friend class ResourceInteractiveLoader;
//internal load function //internal load function
static RES _load(const String &p_path, const String &p_original_path, const String &p_type_hint, bool p_no_cache, Error *r_error); static RES _load(const String &p_path, const String &p_original_path, const String &p_type_hint, bool p_no_cache, Error *r_error, bool p_use_sub_threads, float *r_progress);
static ResourceLoadedCallback _loaded_callback; static ResourceLoadedCallback _loaded_callback;
static Ref<ResourceFormatLoader> _find_custom_resource_format_loader(String path); static Ref<ResourceFormatLoader> _find_custom_resource_format_loader(String path);
static Mutex loading_map_mutex;
//used to track paths being loaded in a thread, avoids cyclic recursion struct ThreadLoadTask {
struct LoadingMapKey { Thread *thread = nullptr;
String path; Thread::ID loader_id = 0;
Thread::ID thread; Semaphore *semaphore = nullptr;
bool operator==(const LoadingMapKey &p_key) const { String local_path;
return (thread == p_key.thread && path == p_key.path); String remapped_path;
} String type_hint;
}; float progress = 0.0;
struct LoadingMapKeyHasher { ThreadLoadStatus status = THREAD_LOAD_IN_PROGRESS;
Error error;
static _FORCE_INLINE_ uint32_t hash(const LoadingMapKey &p_key) { return p_key.path.hash() + HashMapHasherDefault::hash(p_key.thread); } RES resource;
bool xl_remapped = false;
bool use_sub_threads = false;
bool start_next = true;
int requests = 0;
int poll_requests = 0;
Set<String> sub_tasks;
}; };
static HashMap<LoadingMapKey, int, LoadingMapKeyHasher> loading_map; static void _thread_load_function(void *p_userdata);
static Mutex *thread_load_mutex;
static HashMap<String, ThreadLoadTask> thread_load_tasks;
static Semaphore *thread_load_semaphore;
static int thread_waiting_count;
static int thread_loading_count;
static int thread_suspended_count;
static int thread_load_max;
static bool _add_to_loading_map(const String &p_path); static float _dependency_get_progress(const String &p_path);
static void _remove_from_loading_map(const String &p_path);
static void _remove_from_loading_map_and_thread(const String &p_path, Thread::ID p_thread);
public: public:
static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL); static Error load_threaded_request(const String &p_path, const String &p_type_hint = "", bool p_use_sub_threads = false, const String &p_source_resource = String());
static ThreadLoadStatus load_threaded_get_status(const String &p_path, float *r_progress = nullptr);
static RES load_threaded_get(const String &p_path, Error *r_error = NULL);
static RES load(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL); static RES load(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL);
static bool exists(const String &p_path, const String &p_type_hint = ""); static bool exists(const String &p_path, const String &p_type_hint = "");

View File

@ -176,7 +176,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
return translation; return translation;
} }
RES TranslationLoaderPO::load(const String &p_path, const String &p_original_path, Error *r_error) { RES TranslationLoaderPO::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
if (r_error) if (r_error)
*r_error = ERR_CANT_OPEN; *r_error = ERR_CANT_OPEN;

View File

@ -38,7 +38,7 @@
class TranslationLoaderPO : public ResourceFormatLoader { class TranslationLoaderPO : public ResourceFormatLoader {
public: public:
static RES load_translation(FileAccess *f, Error *r_error, const String &p_path = String()); static RES load_translation(FileAccess *f, Error *r_error, const String &p_path = String());
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -126,6 +126,7 @@ enum PropertyUsageFlags {
PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT = 1 << 23, PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT = 1 << 23,
PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT = 1 << 24, PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT = 1 << 24,
PROPERTY_USAGE_KEYING_INCREMENTS = 1 << 25, // Used in inspector to increment property when keyed in animation player PROPERTY_USAGE_KEYING_INCREMENTS = 1 << 25, // Used in inspector to increment property when keyed in animation player
PROPERTY_USAGE_DEFERRED_SET_RESOURCE = 1 << 26, // when loading, the resource for this property can be set at the end of loading
PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK, PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK,
PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK | PROPERTY_USAGE_INTERNATIONALIZED, PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK | PROPERTY_USAGE_INTERNATIONALIZED,

View File

@ -186,8 +186,6 @@ void register_core_types() {
ClassDB::register_class<HTTPClient>(); ClassDB::register_class<HTTPClient>();
ClassDB::register_class<TriangleMesh>(); ClassDB::register_class<TriangleMesh>();
ClassDB::register_virtual_class<ResourceInteractiveLoader>();
ClassDB::register_class<ResourceFormatLoader>(); ClassDB::register_class<ResourceFormatLoader>();
ClassDB::register_class<ResourceFormatSaver>(); ClassDB::register_class<ResourceFormatSaver>();

View File

@ -35,7 +35,7 @@
#include <string.h> #include <string.h>
RES ResourceFormatDummyTexture::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatDummyTexture::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
unsigned int width = 8; unsigned int width = 8;
unsigned int height = 8; unsigned int height = 8;

View File

@ -36,7 +36,7 @@
class ResourceFormatDummyTexture : public ResourceFormatLoader { class ResourceFormatDummyTexture : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -94,7 +94,7 @@ static const DDSFormatInfo dds_format_info[DDS_MAX] = {
{ "GRAYSCALE_ALPHA", false, false, 1, 2, Image::FORMAT_LA8 } { "GRAYSCALE_ALPHA", false, false, 1, 2, Image::FORMAT_LA8 }
}; };
RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
if (r_error) if (r_error)
*r_error = ERR_CANT_OPEN; *r_error = ERR_CANT_OPEN;

View File

@ -36,7 +36,7 @@
class ResourceFormatDDS : public ResourceFormatLoader { class ResourceFormatDDS : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -42,7 +42,7 @@ struct ETC1Header {
uint16_t origHeight; uint16_t origHeight;
}; };
RES ResourceFormatPKM::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatPKM::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
if (r_error) if (r_error)
*r_error = ERR_CANT_OPEN; *r_error = ERR_CANT_OPEN;

View File

@ -36,7 +36,7 @@
class ResourceFormatPKM : public ResourceFormatLoader { class ResourceFormatPKM : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -493,7 +493,7 @@ Error GDNative::get_symbol(StringName p_procedure_name, void *&r_handle, bool p_
return result; return result;
} }
RES GDNativeLibraryResourceLoader::load(const String &p_path, const String &p_original_path, Error *r_error) { RES GDNativeLibraryResourceLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
Ref<GDNativeLibrary> lib; Ref<GDNativeLibrary> lib;
lib.instance(); lib.instance();

View File

@ -166,7 +166,7 @@ public:
class GDNativeLibraryResourceLoader : public ResourceFormatLoader { class GDNativeLibraryResourceLoader : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path, const String &p_original_path, Error *r_error); virtual RES load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -1931,7 +1931,7 @@ void NativeReloadNode::_notification(int p_what) {
#endif #endif
} }
RES ResourceFormatLoaderNativeScript::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoaderNativeScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
return ResourceFormatLoaderText::singleton->load(p_path, p_original_path, r_error); return ResourceFormatLoaderText::singleton->load(p_path, p_original_path, r_error);
} }

View File

@ -406,7 +406,7 @@ public:
class ResourceFormatLoaderNativeScript : public ResourceFormatLoader { class ResourceFormatLoaderNativeScript : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -39,7 +39,7 @@ ResourceFormatLoaderPluginScript::ResourceFormatLoaderPluginScript(PluginScriptL
_language = language; _language = language;
} }
RES ResourceFormatLoaderPluginScript::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoaderPluginScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
if (r_error) if (r_error)
*r_error = ERR_FILE_CANT_OPEN; *r_error = ERR_FILE_CANT_OPEN;

View File

@ -44,7 +44,7 @@ class ResourceFormatLoaderPluginScript : public ResourceFormatLoader {
public: public:
ResourceFormatLoaderPluginScript(PluginScriptLanguage *language); ResourceFormatLoaderPluginScript(PluginScriptLanguage *language);
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -373,7 +373,7 @@ void VideoStreamGDNative::set_audio_track(int p_track) {
/* --- NOTE ResourceFormatLoaderVideoStreamGDNative starts here. ----- */ /* --- NOTE ResourceFormatLoaderVideoStreamGDNative starts here. ----- */
RES ResourceFormatLoaderVideoStreamGDNative::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoaderVideoStreamGDNative::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ); FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (!f) { if (!f) {
if (r_error) { if (r_error) {

View File

@ -199,7 +199,7 @@ public:
class ResourceFormatLoaderVideoStreamGDNative : public ResourceFormatLoader { class ResourceFormatLoaderVideoStreamGDNative : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -2251,7 +2251,7 @@ Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_na
/*************** RESOURCE ***************/ /*************** RESOURCE ***************/
RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
if (r_error) if (r_error)
*r_error = ERR_FILE_CANT_OPEN; *r_error = ERR_FILE_CANT_OPEN;

View File

@ -542,7 +542,7 @@ public:
class ResourceFormatLoaderGDScript : public ResourceFormatLoader { class ResourceFormatLoaderGDScript : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -3451,7 +3451,7 @@ CSharpScript::~CSharpScript() {
/*************** RESOURCE ***************/ /*************** RESOURCE ***************/
RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
if (r_error) if (r_error)
*r_error = ERR_FILE_CANT_OPEN; *r_error = ERR_FILE_CANT_OPEN;

View File

@ -497,7 +497,7 @@ public:
class ResourceFormatLoaderCSharpScript : public ResourceFormatLoader { class ResourceFormatLoaderCSharpScript : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -354,7 +354,7 @@ AudioStreamPlaybackOpus::~AudioStreamPlaybackOpus() {
_clear_stream(); _clear_stream();
} }
RES ResourceFormatLoaderAudioStreamOpus::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoaderAudioStreamOpus::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
if (r_error) if (r_error)
*r_error = OK; *r_error = OK;

View File

@ -133,7 +133,7 @@ public:
class ResourceFormatLoaderAudioStreamOpus : public ResourceFormatLoader { class ResourceFormatLoaderAudioStreamOpus : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -51,7 +51,7 @@ enum PVRFLags {
}; };
RES ResourceFormatPVR::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatPVR::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
if (r_error) if (r_error)
*r_error = ERR_CANT_OPEN; *r_error = ERR_CANT_OPEN;

View File

@ -36,7 +36,7 @@
class ResourceFormatPVR : public ResourceFormatLoader { class ResourceFormatPVR : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path, const String &p_original_path, Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path, Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -725,7 +725,7 @@ void VideoStreamTheora::_bind_methods() {
//////////// ////////////
RES ResourceFormatLoaderTheora::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoaderTheora::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ); FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (!f) { if (!f) {

View File

@ -187,7 +187,7 @@ public:
class ResourceFormatLoaderTheora : public ResourceFormatLoader { class ResourceFormatLoaderTheora : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -381,7 +381,7 @@ AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() {
_clear_stream(); _clear_stream();
} }
RES ResourceFormatLoaderAudioStreamOGGVorbis::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoaderAudioStreamOGGVorbis::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
if (r_error) if (r_error)
*r_error = OK; *r_error = OK;

View File

@ -128,7 +128,7 @@ public:
class ResourceFormatLoaderAudioStreamOGGVorbis : public ResourceFormatLoader { class ResourceFormatLoaderAudioStreamOGGVorbis : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -474,7 +474,7 @@ void VideoStreamWebm::set_audio_track(int p_track) {
//////////// ////////////
RES ResourceFormatLoaderWebm::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoaderWebm::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ); FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (!f) { if (!f) {

View File

@ -128,7 +128,7 @@ public:
class ResourceFormatLoaderWebm : public ResourceFormatLoader { class ResourceFormatLoaderWebm : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -101,7 +101,7 @@ void MeshInstance::_get_property_list(List<PropertyInfo> *p_list) const {
if (mesh.is_valid()) { if (mesh.is_valid()) {
for (int i = 0; i < mesh->get_surface_count(); i++) { for (int i = 0; i < mesh->get_surface_count(); i++) {
p_list->push_back(PropertyInfo(Variant::OBJECT, "material/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D")); p_list->push_back(PropertyInfo(Variant::OBJECT, "material/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE));
} }
} }
} }

View File

@ -294,7 +294,7 @@ void GeometryInstance::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_aabb"), &GeometryInstance::get_aabb); ClassDB::bind_method(D_METHOD("get_aabb"), &GeometryInstance::get_aabb);
ADD_GROUP("Geometry", ""); ADD_GROUP("Geometry", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D"), "set_material_override", "get_material_override"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE), "set_material_override", "get_material_override");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01"), "set_extra_cull_margin", "get_extra_cull_margin"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01"), "set_extra_cull_margin", "get_extra_cull_margin");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_in_baked_light"), "set_flag", "get_flag", FLAG_USE_BAKED_LIGHT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_in_baked_light"), "set_flag", "get_flag", FLAG_USE_BAKED_LIGHT);

View File

@ -1063,7 +1063,7 @@ void DynamicFont::update_oversampling() {
///////////////////////// /////////////////////////
RES ResourceFormatLoaderDynamicFont::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoaderDynamicFont::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
if (r_error) if (r_error)
*r_error = ERR_FILE_CANT_OPEN; *r_error = ERR_FILE_CANT_OPEN;

View File

@ -302,7 +302,7 @@ VARIANT_ENUM_CAST(DynamicFont::SpacingType);
class ResourceFormatLoaderDynamicFont : public ResourceFormatLoader { class ResourceFormatLoaderDynamicFont : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -646,7 +646,7 @@ BitmapFont::~BitmapFont() {
//////////// ////////////
RES ResourceFormatLoaderBMFont::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoaderBMFont::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
if (r_error) if (r_error)
*r_error = ERR_FILE_CANT_OPEN; *r_error = ERR_FILE_CANT_OPEN;

View File

@ -200,7 +200,7 @@ public:
class ResourceFormatLoaderBMFont : public ResourceFormatLoader { class ResourceFormatLoaderBMFont : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -1004,7 +1004,6 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
} else { } else {
// if mesh does not exist (first time this is loaded, most likely), // if mesh does not exist (first time this is loaded, most likely),
// we can create it with a single call, which is a lot more efficient and thread friendly // we can create it with a single call, which is a lot more efficient and thread friendly
print_line("create mesh from surfaces: " + itos(surface_data.size()));
mesh = VS::get_singleton()->mesh_create_from_surfaces(surface_data); mesh = VS::get_singleton()->mesh_create_from_surfaces(surface_data);
VS::get_singleton()->mesh_set_blend_shape_mode(mesh, (VS::BlendShapeMode)blend_shape_mode); VS::get_singleton()->mesh_set_blend_shape_mode(mesh, (VS::BlendShapeMode)blend_shape_mode);
} }

View File

@ -45,17 +45,17 @@
/// ///
void ResourceInteractiveLoaderText::set_local_path(const String &p_local_path) { void ResourceLoaderText::set_local_path(const String &p_local_path) {
res_path = p_local_path; res_path = p_local_path;
} }
Ref<Resource> ResourceInteractiveLoaderText::get_resource() { Ref<Resource> ResourceLoaderText::get_resource() {
return resource; return resource;
} }
Error ResourceInteractiveLoaderText::_parse_sub_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { Error ResourceLoaderText::_parse_sub_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) {
VariantParser::Token token; VariantParser::Token token;
VariantParser::get_token(p_stream, token, line, r_err_str); VariantParser::get_token(p_stream, token, line, r_err_str);
@ -85,7 +85,7 @@ Error ResourceInteractiveLoaderText::_parse_sub_resource_dummy(DummyReadData *p_
return OK; return OK;
} }
Error ResourceInteractiveLoaderText::_parse_ext_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { Error ResourceLoaderText::_parse_ext_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) {
VariantParser::Token token; VariantParser::Token token;
VariantParser::get_token(p_stream, token, line, r_err_str); VariantParser::get_token(p_stream, token, line, r_err_str);
@ -109,7 +109,7 @@ Error ResourceInteractiveLoaderText::_parse_ext_resource_dummy(DummyReadData *p_
return OK; return OK;
} }
Error ResourceInteractiveLoaderText::_parse_sub_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { Error ResourceLoaderText::_parse_sub_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) {
VariantParser::Token token; VariantParser::Token token;
VariantParser::get_token(p_stream, token, line, r_err_str); VariantParser::get_token(p_stream, token, line, r_err_str);
@ -143,7 +143,7 @@ Error ResourceInteractiveLoaderText::_parse_sub_resource(VariantParser::Stream *
return OK; return OK;
} }
Error ResourceInteractiveLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { Error ResourceLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) {
VariantParser::Token token; VariantParser::Token token;
VariantParser::get_token(p_stream, token, line, r_err_str); VariantParser::get_token(p_stream, token, line, r_err_str);
@ -164,15 +164,30 @@ Error ResourceInteractiveLoaderText::_parse_ext_resource(VariantParser::Stream *
String path = ext_resources[id].path; String path = ext_resources[id].path;
String type = ext_resources[id].type; String type = ext_resources[id].type;
if (path.find("://") == -1 && path.is_rel_path()) { if (ext_resources[id].cache.is_valid()) {
// path is relative to file being loaded, so convert to a resource path r_res = ext_resources[id].cache;
path = ProjectSettings::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path)); } else if (use_sub_threads) {
}
r_res = ResourceLoader::load(path, type); RES res = ResourceLoader::load_threaded_get(path);
if (res.is_null()) {
if (r_res.is_null()) { if (ResourceLoader::get_abort_on_missing_resources()) {
WARN_PRINT(String("Couldn't load external resource: " + path).utf8().get_data()); error = ERR_FILE_CORRUPT;
error_text = "[ext_resource] referenced nonexistent resource at: " + path;
_printerr();
return error;
} else {
ResourceLoader::notify_dependency_error(local_path, path, type);
}
} else {
ext_resources[id].cache = res;
r_res = res;
}
} else {
error = ERR_FILE_CORRUPT;
error_text = "[ext_resource] referenced non-loaded resource at: " + path;
_printerr();
return error;
} }
} else { } else {
r_res = RES(); r_res = RES();
@ -187,7 +202,7 @@ Error ResourceInteractiveLoaderText::_parse_ext_resource(VariantParser::Stream *
return OK; return OK;
} }
Ref<PackedScene> ResourceInteractiveLoaderText::_parse_node_tag(VariantParser::ResourceParser &parser) { Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourceParser &parser) {
Ref<PackedScene> packed_scene; Ref<PackedScene> packed_scene;
packed_scene.instance(); packed_scene.instance();
@ -321,7 +336,7 @@ Ref<PackedScene> ResourceInteractiveLoaderText::_parse_node_tag(VariantParser::R
NodePath to = next_tag.fields["to"]; NodePath to = next_tag.fields["to"];
StringName method = next_tag.fields["method"]; StringName method = next_tag.fields["method"];
StringName signal = next_tag.fields["signal"]; StringName signal = next_tag.fields["signal"];
int flags = CONNECT_PERSIST; int flags = Object::CONNECT_PERSIST;
Array binds; Array binds;
if (next_tag.fields.has("flags")) { if (next_tag.fields.has("flags")) {
@ -389,12 +404,15 @@ Ref<PackedScene> ResourceInteractiveLoaderText::_parse_node_tag(VariantParser::R
return packed_scene; return packed_scene;
} }
Error ResourceInteractiveLoaderText::poll() { Error ResourceLoaderText::load() {
if (error != OK) if (error != OK)
return error; return error;
if (next_tag.name == "ext_resource") { while (true) {
if (next_tag.name != "ext_resource") {
break;
}
if (!next_tag.fields.has("path")) { if (!next_tag.fields.has("path")) {
error = ERR_FILE_CORRUPT; error = ERR_FILE_CORRUPT;
@ -430,30 +448,49 @@ Error ResourceInteractiveLoaderText::poll() {
path = remaps[path]; path = remaps[path];
} }
RES res = ResourceLoader::load(path, type);
if (res.is_null()) {
if (ResourceLoader::get_abort_on_missing_resources()) {
error = ERR_FILE_CORRUPT;
error_text = "[ext_resource] referenced nonexistent resource at: " + path;
_printerr();
return error;
} else {
ResourceLoader::notify_dependency_error(local_path, path, type);
}
} else {
resource_cache.push_back(res);
#ifdef TOOLS_ENABLED
//remember ID for saving
res->set_id_for_path(local_path, index);
#endif
}
ExtResource er; ExtResource er;
er.path = path; er.path = path;
er.type = type; er.type = type;
if (use_sub_threads) {
Error err = ResourceLoader::load_threaded_request(path, type, use_sub_threads, local_path);
if (err != OK) {
if (ResourceLoader::get_abort_on_missing_resources()) {
error = ERR_FILE_CORRUPT;
error_text = "[ext_resource] referenced broken resource at: " + path;
_printerr();
return error;
} else {
ResourceLoader::notify_dependency_error(local_path, path, type);
}
}
} else {
RES res = ResourceLoader::load(path, type);
if (res.is_null()) {
if (ResourceLoader::get_abort_on_missing_resources()) {
error = ERR_FILE_CORRUPT;
error_text = "[ext_resource] referenced nonexistent resource at: " + path;
_printerr();
return error;
} else {
ResourceLoader::notify_dependency_error(local_path, path, type);
}
} else {
#ifdef TOOLS_ENABLED
//remember ID for saving
res->set_id_for_path(local_path, index);
#endif
}
er.cache = res;
}
ext_resources[index] = er; ext_resources[index] = er;
error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp); error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp);
@ -463,9 +500,16 @@ Error ResourceInteractiveLoaderText::poll() {
} }
resource_current++; resource_current++;
return error; }
} else if (next_tag.name == "sub_resource") { //these are the ones that count
resources_total -= resource_current;
resource_current = 0;
while (true) {
if (next_tag.name != "sub_resource") {
break;
}
if (!next_tag.fields.has("type")) { if (!next_tag.fields.has("type")) {
error = ERR_FILE_CORRUPT; error = ERR_FILE_CORRUPT;
@ -546,9 +590,15 @@ Error ResourceInteractiveLoaderText::poll() {
} }
} }
return OK; if (progress) {
*progress = resource_current / float(resources_total);
}
}
} else if (next_tag.name == "resource") { while (true) {
if (next_tag.name != "resource") {
break;
}
if (is_scene) { if (is_scene) {
@ -609,14 +659,23 @@ Error ResourceInteractiveLoaderText::poll() {
_printerr(); _printerr();
return error; return error;
} else { } else {
error = ERR_FILE_EOF; error = OK;
if (progress) {
*progress = resource_current / float(resources_total);
}
return error; return error;
} }
} }
return OK; if (progress) {
*progress = resource_current / float(resources_total);
}
}
} else if (next_tag.name == "node") { //for scene files
if (next_tag.name == "node") {
if (!is_scene) { if (!is_scene) {
@ -631,49 +690,54 @@ Error ResourceInteractiveLoaderText::poll() {
if (!packed_scene.is_valid()) if (!packed_scene.is_valid())
return error; return error;
error = ERR_FILE_EOF; error = OK;
//get it here //get it here
resource = packed_scene; resource = packed_scene;
if (!ResourceCache::has(res_path)) { if (!ResourceCache::has(res_path)) {
packed_scene->set_path(res_path); packed_scene->set_path(res_path);
} }
return error; resource_current++;
if (progress) {
*progress = resource_current / float(resources_total);
}
return error;
} else { } else {
error_text += "Unknown tag in file: " + next_tag.name; error_text += "Unknown tag in file: " + next_tag.name;
_printerr(); _printerr();
error = ERR_FILE_CORRUPT; error = ERR_FILE_CORRUPT;
return error; return error;
} }
return OK;
} }
int ResourceInteractiveLoaderText::get_stage() const { int ResourceLoaderText::get_stage() const {
return resource_current; return resource_current;
} }
int ResourceInteractiveLoaderText::get_stage_count() const { int ResourceLoaderText::get_stage_count() const {
return resources_total; //+ext_resources; return resources_total; //+ext_resources;
} }
void ResourceInteractiveLoaderText::set_translation_remapped(bool p_remapped) { void ResourceLoaderText::set_translation_remapped(bool p_remapped) {
translation_remapped = p_remapped; translation_remapped = p_remapped;
} }
ResourceInteractiveLoaderText::ResourceInteractiveLoaderText() { ResourceLoaderText::ResourceLoaderText() {
progress = nullptr;
translation_remapped = false; translation_remapped = false;
use_sub_threads = false;
} }
ResourceInteractiveLoaderText::~ResourceInteractiveLoaderText() { ResourceLoaderText::~ResourceLoaderText() {
memdelete(f); memdelete(f);
} }
void ResourceInteractiveLoaderText::get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types) { void ResourceLoaderText::get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types) {
open(p_f); open(p_f);
ignore_resource_parsing = true; ignore_resource_parsing = true;
@ -720,7 +784,7 @@ void ResourceInteractiveLoaderText::get_dependencies(FileAccess *p_f, List<Strin
} }
} }
Error ResourceInteractiveLoaderText::rename_dependencies(FileAccess *p_f, const String &p_path, const Map<String, String> &p_map) { Error ResourceLoaderText::rename_dependencies(FileAccess *p_f, const String &p_path, const Map<String, String> &p_map) {
open(p_f, true); open(p_f, true);
ERR_FAIL_COND_V(error != OK, error); ERR_FAIL_COND_V(error != OK, error);
@ -822,7 +886,7 @@ Error ResourceInteractiveLoaderText::rename_dependencies(FileAccess *p_f, const
return OK; return OK;
} }
void ResourceInteractiveLoaderText::open(FileAccess *p_f, bool p_skip_first_tag) { void ResourceLoaderText::open(FileAccess *p_f, bool p_skip_first_tag) {
error = OK; error = OK;
@ -908,7 +972,7 @@ static void bs_save_unicode_string(FileAccess *f, const String &p_string, bool p
f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1); f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1);
} }
Error ResourceInteractiveLoaderText::save_as_binary(FileAccess *p_f, const String &p_path) { Error ResourceLoaderText::save_as_binary(FileAccess *p_f, const String &p_path) {
if (error) if (error)
return error; return error;
@ -1172,7 +1236,7 @@ Error ResourceInteractiveLoaderText::save_as_binary(FileAccess *p_f, const Strin
return OK; return OK;
} }
String ResourceInteractiveLoaderText::recognize(FileAccess *p_f) { String ResourceLoaderText::recognize(FileAccess *p_f) {
error = OK; error = OK;
@ -1217,24 +1281,34 @@ String ResourceInteractiveLoaderText::recognize(FileAccess *p_f) {
///////////////////// /////////////////////
Ref<ResourceInteractiveLoader> ResourceFormatLoaderText::load_interactive(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoaderText::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
if (r_error) if (r_error)
*r_error = ERR_CANT_OPEN; *r_error = ERR_CANT_OPEN;
Error err; Error err;
FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
ERR_FAIL_COND_V_MSG(err != OK, Ref<ResourceInteractiveLoader>(), "Cannot open file '" + p_path + "'."); ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot open file '" + p_path + "'.");
Ref<ResourceInteractiveLoaderText> ria = memnew(ResourceInteractiveLoaderText); ResourceLoaderText loader;
String path = p_original_path != "" ? p_original_path : p_path; String path = p_original_path != "" ? p_original_path : p_path;
ria->local_path = ProjectSettings::get_singleton()->localize_path(path); loader.use_sub_threads = p_use_sub_threads;
ria->res_path = ria->local_path; loader.local_path = ProjectSettings::get_singleton()->localize_path(path);
//ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); loader.progress = r_progress;
ria->open(f); loader.res_path = loader.local_path;
//loader.set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) );
return ria; loader.open(f);
err = loader.load();
if (r_error) {
*r_error = err;
}
if (err == OK) {
return loader.get_resource();
} else {
return RES();
}
} }
void ResourceFormatLoaderText::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const { void ResourceFormatLoaderText::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const {
@ -1276,11 +1350,11 @@ String ResourceFormatLoaderText::get_resource_type(const String &p_path) const {
return ""; //could not rwead return ""; //could not rwead
} }
Ref<ResourceInteractiveLoaderText> ria = memnew(ResourceInteractiveLoaderText); ResourceLoaderText loader;
ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
ria->res_path = ria->local_path; loader.res_path = loader.local_path;
//ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); //loader.set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) );
String r = ria->recognize(f); String r = loader.recognize(f);
return ClassDB::get_compatibility_remapped_class(r); return ClassDB::get_compatibility_remapped_class(r);
} }
@ -1292,11 +1366,11 @@ void ResourceFormatLoaderText::get_dependencies(const String &p_path, List<Strin
ERR_FAIL(); ERR_FAIL();
} }
Ref<ResourceInteractiveLoaderText> ria = memnew(ResourceInteractiveLoaderText); ResourceLoaderText loader;
ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
ria->res_path = ria->local_path; loader.res_path = loader.local_path;
//ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); //loader.set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) );
ria->get_dependencies(f, p_dependencies, p_add_types); loader.get_dependencies(f, p_dependencies, p_add_types);
} }
Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const Map<String, String> &p_map) { Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const Map<String, String> &p_map) {
@ -1307,11 +1381,11 @@ Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const
ERR_FAIL_V(ERR_CANT_OPEN); ERR_FAIL_V(ERR_CANT_OPEN);
} }
Ref<ResourceInteractiveLoaderText> ria = memnew(ResourceInteractiveLoaderText); ResourceLoaderText loader;
ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
ria->res_path = ria->local_path; loader.res_path = loader.local_path;
//ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); //loader.set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) );
return ria->rename_dependencies(f, p_path, p_map); return loader.rename_dependencies(f, p_path, p_map);
} }
ResourceFormatLoaderText *ResourceFormatLoaderText::singleton = NULL; ResourceFormatLoaderText *ResourceFormatLoaderText::singleton = NULL;
@ -1323,13 +1397,13 @@ Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path,
ERR_FAIL_COND_V_MSG(err != OK, ERR_CANT_OPEN, "Cannot open file '" + p_src_path + "'."); ERR_FAIL_COND_V_MSG(err != OK, ERR_CANT_OPEN, "Cannot open file '" + p_src_path + "'.");
Ref<ResourceInteractiveLoaderText> ria = memnew(ResourceInteractiveLoaderText); ResourceLoaderText loader;
const String &path = p_src_path; const String &path = p_src_path;
ria->local_path = ProjectSettings::get_singleton()->localize_path(path); loader.local_path = ProjectSettings::get_singleton()->localize_path(path);
ria->res_path = ria->local_path; loader.res_path = loader.local_path;
//ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); //loader.set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) );
ria->open(f); loader.open(f);
return ria->save_as_binary(f, p_dst_path); return loader.save_as_binary(f, p_dst_path);
} }
/*****************************************************************************************************/ /*****************************************************************************************************/

View File

@ -37,7 +37,7 @@
#include "core/variant_parser.h" #include "core/variant_parser.h"
#include "scene/resources/packed_scene.h" #include "scene/resources/packed_scene.h"
class ResourceInteractiveLoaderText : public ResourceInteractiveLoader { class ResourceLoaderText {
bool translation_remapped; bool translation_remapped;
String local_path; String local_path;
@ -49,6 +49,7 @@ class ResourceInteractiveLoaderText : public ResourceInteractiveLoader {
VariantParser::StreamFile stream; VariantParser::StreamFile stream;
struct ExtResource { struct ExtResource {
RES cache;
String path; String path;
String type; String type;
}; };
@ -68,13 +69,16 @@ class ResourceInteractiveLoaderText : public ResourceInteractiveLoader {
VariantParser::Tag next_tag; VariantParser::Tag next_tag;
bool use_sub_threads;
float *progress;
mutable int lines; mutable int lines;
Map<String, String> remaps; Map<String, String> remaps;
//void _printerr(); //void _printerr();
static Error _parse_sub_resources(void *p_self, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { return reinterpret_cast<ResourceInteractiveLoaderText *>(p_self)->_parse_sub_resource(p_stream, r_res, line, r_err_str); } static Error _parse_sub_resources(void *p_self, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { return reinterpret_cast<ResourceLoaderText *>(p_self)->_parse_sub_resource(p_stream, r_res, line, r_err_str); }
static Error _parse_ext_resources(void *p_self, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { return reinterpret_cast<ResourceInteractiveLoaderText *>(p_self)->_parse_ext_resource(p_stream, r_res, line, r_err_str); } static Error _parse_ext_resources(void *p_self, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { return reinterpret_cast<ResourceLoaderText *>(p_self)->_parse_ext_resource(p_stream, r_res, line, r_err_str); }
Error _parse_sub_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str); Error _parse_sub_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str);
Error _parse_ext_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str); Error _parse_ext_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str);
@ -110,12 +114,12 @@ class ResourceInteractiveLoaderText : public ResourceInteractiveLoader {
Ref<PackedScene> _parse_node_tag(VariantParser::ResourceParser &parser); Ref<PackedScene> _parse_node_tag(VariantParser::ResourceParser &parser);
public: public:
virtual void set_local_path(const String &p_local_path); void set_local_path(const String &p_local_path);
virtual Ref<Resource> get_resource(); Ref<Resource> get_resource();
virtual Error poll(); Error load();
virtual int get_stage() const; int get_stage() const;
virtual int get_stage_count() const; int get_stage_count() const;
virtual void set_translation_remapped(bool p_remapped); void set_translation_remapped(bool p_remapped);
void open(FileAccess *p_f, bool p_skip_first_tag = false); void open(FileAccess *p_f, bool p_skip_first_tag = false);
String recognize(FileAccess *p_f); String recognize(FileAccess *p_f);
@ -123,14 +127,14 @@ public:
Error rename_dependencies(FileAccess *p_f, const String &p_path, const Map<String, String> &p_map); Error rename_dependencies(FileAccess *p_f, const String &p_path, const Map<String, String> &p_map);
Error save_as_binary(FileAccess *p_f, const String &p_path); Error save_as_binary(FileAccess *p_f, const String &p_path);
ResourceInteractiveLoaderText(); ResourceLoaderText();
~ResourceInteractiveLoaderText(); ~ResourceLoaderText();
}; };
class ResourceFormatLoaderText : public ResourceFormatLoader { class ResourceFormatLoaderText : public ResourceFormatLoader {
public: public:
static ResourceFormatLoaderText *singleton; static ResourceFormatLoaderText *singleton;
virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;

View File

@ -173,7 +173,7 @@ Shader::~Shader() {
} }
//////////// ////////////
RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
if (r_error) if (r_error)
*r_error = ERR_FILE_CANT_OPEN; *r_error = ERR_FILE_CANT_OPEN;

View File

@ -101,7 +101,7 @@ VARIANT_ENUM_CAST(Shader::Mode);
class ResourceFormatLoaderShader : public ResourceFormatLoader { class ResourceFormatLoaderShader : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;

View File

@ -363,7 +363,6 @@ Ref<Image> StreamTexture::load_image_from_file(FileAccess *f, int p_size_limit)
uint32_t mipmaps = f->get_32(); uint32_t mipmaps = f->get_32();
Image::Format format = Image::Format(f->get_32()); Image::Format format = Image::Format(f->get_32());
print_line("format: " + itos(data_format) + " size " + Size2i(w, h) + " mipmaps: " + itos(mipmaps));
if (data_format == DATA_FORMAT_LOSSLESS || data_format == DATA_FORMAT_LOSSY || data_format == DATA_FORMAT_BASIS_UNIVERSAL) { if (data_format == DATA_FORMAT_LOSSLESS || data_format == DATA_FORMAT_LOSSY || data_format == DATA_FORMAT_BASIS_UNIVERSAL) {
//look for a PNG or WEBP file inside //look for a PNG or WEBP file inside
@ -797,7 +796,7 @@ StreamTexture::~StreamTexture() {
} }
} }
RES ResourceFormatLoaderStreamTexture::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoaderStreamTexture::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
Ref<StreamTexture> st; Ref<StreamTexture> st;
st.instance(); st.instance();
@ -2027,7 +2026,7 @@ TextureLayered::~TextureLayered() {
} }
} }
RES ResourceFormatLoaderTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error) { RES ResourceFormatLoaderTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
if (r_error) { if (r_error) {
*r_error = ERR_CANT_OPEN; *r_error = ERR_CANT_OPEN;

View File

@ -213,7 +213,7 @@ public:
class ResourceFormatLoaderStreamTexture : public ResourceFormatLoader { class ResourceFormatLoaderStreamTexture : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;
@ -421,7 +421,7 @@ public:
COMPRESSION_UNCOMPRESSED COMPRESSION_UNCOMPRESSED
}; };
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const; virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const; virtual String get_resource_type(const String &p_path) const;