Add GLES2 2D renderer + Linux display manager

First implementation with Linux display manager.

- Add single-threaded mode for EditorResourcePreview (needed for OpenGL).

Co-authored-by: clayjohn <claynjohn@gmail.com>
Co-authored-by: Fabio Alessandrelli <fabio.alessandrelli@gmail.com>
This commit is contained in:
lawnjelly
2020-11-18 18:11:30 +00:00
committed by Hugo Locurcio
parent d046817536
commit e3491a3744
88 changed files with 41666 additions and 358 deletions

View File

@ -210,126 +210,130 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<
}
}
void EditorResourcePreview::_iterate() {
preview_mutex.lock();
if (queue.size()) {
QueueItem item = queue.front()->get();
queue.pop_front();
if (cache.has(item.path)) {
//already has it because someone loaded it, just let it know it's ready
String path = item.path;
if (item.resource.is_valid()) {
path += ":" + itos(cache[item.path].last_hash); //keep last hash (see description of what this is in condition below)
}
_preview_ready(path, cache[item.path].preview, cache[item.path].small_preview, item.id, item.function, item.userdata);
preview_mutex.unlock();
} else {
preview_mutex.unlock();
Ref<ImageTexture> texture;
Ref<ImageTexture> small_texture;
int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
thumbnail_size *= EDSCALE;
if (item.resource.is_valid()) {
_generate_preview(texture, small_texture, item, String());
//adding hash to the end of path (should be ID:<objid>:<hash>) because of 5 argument limit to call_deferred
_preview_ready(item.path + ":" + itos(item.resource->hash_edited_version()), texture, small_texture, item.id, item.function, item.userdata);
} else {
String temp_path = EditorPaths::get_singleton()->get_cache_dir();
String cache_base = ProjectSettings::get_singleton()->globalize_path(item.path).md5_text();
cache_base = temp_path.plus_file("resthumb-" + cache_base);
//does not have it, try to load a cached thumbnail
String file = cache_base + ".txt";
FileAccess *f = FileAccess::open(file, FileAccess::READ);
if (!f) {
// No cache found, generate
_generate_preview(texture, small_texture, item, cache_base);
} else {
uint64_t modtime = FileAccess::get_modified_time(item.path);
int tsize = f->get_line().to_int();
bool has_small_texture = f->get_line().to_int();
uint64_t last_modtime = f->get_line().to_int();
bool cache_valid = true;
if (tsize != thumbnail_size) {
cache_valid = false;
memdelete(f);
} else if (last_modtime != modtime) {
String last_md5 = f->get_line();
String md5 = FileAccess::get_md5(item.path);
memdelete(f);
if (last_md5 != md5) {
cache_valid = false;
} else {
//update modified time
f = FileAccess::open(file, FileAccess::WRITE);
if (!f) {
// Not returning as this would leave the thread hanging and would require
// some proper cleanup/disabling of resource preview generation.
ERR_PRINT("Cannot create file '" + file + "'. Check user write permissions.");
} else {
f->store_line(itos(thumbnail_size));
f->store_line(itos(has_small_texture));
f->store_line(itos(modtime));
f->store_line(md5);
memdelete(f);
}
}
} else {
memdelete(f);
}
if (cache_valid) {
Ref<Image> img;
img.instantiate();
Ref<Image> small_img;
small_img.instantiate();
if (img->load(cache_base + ".png") != OK) {
cache_valid = false;
} else {
texture.instantiate();
texture->create_from_image(img);
if (has_small_texture) {
if (small_img->load(cache_base + "_small.png") != OK) {
cache_valid = false;
} else {
small_texture.instantiate();
small_texture->create_from_image(small_img);
}
}
}
}
if (!cache_valid) {
_generate_preview(texture, small_texture, item, cache_base);
}
}
_preview_ready(item.path, texture, small_texture, item.id, item.function, item.userdata);
}
}
} else {
preview_mutex.unlock();
}
}
void EditorResourcePreview::_thread() {
exited.clear();
while (!exit.is_set()) {
preview_sem.wait();
preview_mutex.lock();
if (queue.size()) {
QueueItem item = queue.front()->get();
queue.pop_front();
if (cache.has(item.path)) {
//already has it because someone loaded it, just let it know it's ready
String path = item.path;
if (item.resource.is_valid()) {
path += ":" + itos(cache[item.path].last_hash); //keep last hash (see description of what this is in condition below)
}
_preview_ready(path, cache[item.path].preview, cache[item.path].small_preview, item.id, item.function, item.userdata);
preview_mutex.unlock();
} else {
preview_mutex.unlock();
Ref<ImageTexture> texture;
Ref<ImageTexture> small_texture;
int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
thumbnail_size *= EDSCALE;
if (item.resource.is_valid()) {
_generate_preview(texture, small_texture, item, String());
//adding hash to the end of path (should be ID:<objid>:<hash>) because of 5 argument limit to call_deferred
_preview_ready(item.path + ":" + itos(item.resource->hash_edited_version()), texture, small_texture, item.id, item.function, item.userdata);
} else {
String temp_path = EditorPaths::get_singleton()->get_cache_dir();
String cache_base = ProjectSettings::get_singleton()->globalize_path(item.path).md5_text();
cache_base = temp_path.plus_file("resthumb-" + cache_base);
//does not have it, try to load a cached thumbnail
String file = cache_base + ".txt";
FileAccess *f = FileAccess::open(file, FileAccess::READ);
if (!f) {
// No cache found, generate
_generate_preview(texture, small_texture, item, cache_base);
} else {
uint64_t modtime = FileAccess::get_modified_time(item.path);
int tsize = f->get_line().to_int();
bool has_small_texture = f->get_line().to_int();
uint64_t last_modtime = f->get_line().to_int();
bool cache_valid = true;
if (tsize != thumbnail_size) {
cache_valid = false;
memdelete(f);
} else if (last_modtime != modtime) {
String last_md5 = f->get_line();
String md5 = FileAccess::get_md5(item.path);
memdelete(f);
if (last_md5 != md5) {
cache_valid = false;
} else {
//update modified time
f = FileAccess::open(file, FileAccess::WRITE);
if (!f) {
// Not returning as this would leave the thread hanging and would require
// some proper cleanup/disabling of resource preview generation.
ERR_PRINT("Cannot create file '" + file + "'. Check user write permissions.");
} else {
f->store_line(itos(thumbnail_size));
f->store_line(itos(has_small_texture));
f->store_line(itos(modtime));
f->store_line(md5);
memdelete(f);
}
}
} else {
memdelete(f);
}
if (cache_valid) {
Ref<Image> img;
img.instantiate();
Ref<Image> small_img;
small_img.instantiate();
if (img->load(cache_base + ".png") != OK) {
cache_valid = false;
} else {
texture.instantiate();
texture->create_from_image(img);
if (has_small_texture) {
if (small_img->load(cache_base + "_small.png") != OK) {
cache_valid = false;
} else {
small_texture.instantiate();
small_texture->create_from_image(small_img);
}
}
}
}
if (!cache_valid) {
_generate_preview(texture, small_texture, item, cache_base);
}
}
_preview_ready(item.path, texture, small_texture, item.id, item.function, item.userdata);
}
}
} else {
preview_mutex.unlock();
}
_iterate();
}
exited.set();
}
@ -429,8 +433,12 @@ void EditorResourcePreview::check_for_invalidation(const String &p_path) {
}
void EditorResourcePreview::start() {
ERR_FAIL_COND_MSG(thread.is_started(), "Thread already started.");
thread.start(_thread_func, this);
if (OS::get_singleton()->get_render_main_thread_mode() == OS::RENDER_ANY_THREAD) {
ERR_FAIL_COND_MSG(thread.is_started(), "Thread already started.");
thread.start(_thread_func, this);
} else {
_mainthread_only = true;
}
}
void EditorResourcePreview::stop() {
@ -453,3 +461,18 @@ EditorResourcePreview::EditorResourcePreview() {
EditorResourcePreview::~EditorResourcePreview() {
stop();
}
void EditorResourcePreview::update() {
if (!_mainthread_only) {
return;
}
if (!exit.is_set()) {
// no need to even lock the mutex if the size is zero
// there is no problem if queue.size() is wrong, even if
// there was a race condition.
if (queue.size()) {
_iterate();
}
}
}