From 11ae259f67b475f23082584b622abc7d511fc825 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Mon, 16 Dec 2024 00:32:07 +0100 Subject: [PATCH] texture cache refactor to later allow async loading --- external/solanaceae_util | 2 +- src/bitset_image_loader.cpp | 14 +++++++------- src/bitset_image_loader.hpp | 2 +- src/message_image_loader.cpp | 32 ++++++++++++++++---------------- src/message_image_loader.hpp | 2 +- src/texture_cache.cpp | 2 +- src/texture_cache.hpp | 20 ++++++++++++++++---- src/tox_avatar_loader.cpp | 19 ++++++++++--------- src/tox_avatar_loader.hpp | 2 +- 9 files changed, 54 insertions(+), 41 deletions(-) diff --git a/external/solanaceae_util b/external/solanaceae_util index 717748e..85bbbb0 160000 --- a/external/solanaceae_util +++ b/external/solanaceae_util @@ -1 +1 @@ -Subproject commit 717748e8fc6ecd2170aa98ca442727fb1fe32834 +Subproject commit 85bbbb0e5a572b61067f3db188f3cfbda0948e7e diff --git a/src/bitset_image_loader.cpp b/src/bitset_image_loader.cpp index 07bc266..baa2e26 100644 --- a/src/bitset_image_loader.cpp +++ b/src/bitset_image_loader.cpp @@ -71,27 +71,27 @@ std::optional BitsetImageLoader::haveToTexture(TextureUploaderI& t BitsetImageLoader::BitsetImageLoader(void) { } -std::optional BitsetImageLoader::load(TextureUploaderI& tu, ObjectHandle o) { +TextureLoaderResult BitsetImageLoader::load(TextureUploaderI& tu, ObjectHandle o) { if (!static_cast(o)) { std::cerr << "BIL error: trying to load invalid object\n"; - return std::nullopt; + return {std::nullopt}; } if (!o.any_of()) { // after completion, this is called until the texture times out //std::cout << "BIL: no local have bitset\n"; - return std::nullopt; + return {std::nullopt}; } if (o.all_of()) { auto& have = o.get().have; assert(have.size_bits() > 0); - return haveToTexture(tu, have, o); + return {haveToTexture(tu, have, o)}; } else if (o.all_of()) { auto& list = o.get().others; if (list.empty()) { std::cout << "BIL: remote set list empty\n"; - return std::nullopt; + return {std::nullopt}; } const auto& first_entry = list.begin()->second; @@ -115,10 +115,10 @@ std::optional BitsetImageLoader::load(TextureUploaderI& tu, Object } } - return haveToTexture(tu, _tmp_bitset, o); + return {haveToTexture(tu, _tmp_bitset, o)}; } - return std::nullopt; + return {std::nullopt}; } std::optional BitsetImageLoader::load(TextureUploaderI& tu, ObjectContactSub ocs) { diff --git a/src/bitset_image_loader.hpp b/src/bitset_image_loader.hpp index 12975e3..59a1101 100644 --- a/src/bitset_image_loader.hpp +++ b/src/bitset_image_loader.hpp @@ -30,7 +30,7 @@ class BitsetImageLoader { public: BitsetImageLoader(void); - std::optional load(TextureUploaderI& tu, ObjectHandle o); + TextureLoaderResult load(TextureUploaderI& tu, ObjectHandle o); std::optional load(TextureUploaderI& tu, ObjectContactSub ocs); }; diff --git a/src/message_image_loader.cpp b/src/message_image_loader.cpp index baca828..c8be17c 100644 --- a/src/message_image_loader.cpp +++ b/src/message_image_loader.cpp @@ -30,29 +30,29 @@ MessageImageLoader::MessageImageLoader(void) { _image_loaders.push_back(std::make_unique()); } -std::optional MessageImageLoader::load(TextureUploaderI& tu, Message3Handle m) { +TextureLoaderResult MessageImageLoader::load(TextureUploaderI& tu, Message3Handle m) { if (!static_cast(m)) { - return std::nullopt; + return {std::nullopt}; } if (m.all_of()) { - return std::nullopt; + return {std::nullopt}; } if (!m.all_of()) { // not a file message - return std::nullopt; + return {std::nullopt}; } const auto& o = m.get().o; if (!static_cast(o)) { std::cerr << "MIL error: invalid object in file message\n"; - return std::nullopt; + return {std::nullopt}; } if (!o.all_of()) { std::cerr << "MIL error: object missing backend (?)\n"; - return std::nullopt; + return {std::nullopt}; } // TODO: handle collections @@ -60,40 +60,40 @@ std::optional MessageImageLoader::load(TextureUploaderI& tu, Messa if (file_size > 50*1024*1024) { std::cerr << "MIL error: image file too large\n"; - return std::nullopt; + return {std::nullopt}; } if (file_size == 0) { std::cerr << "MIL warning: empty file\n"; - return std::nullopt; + return {std::nullopt}; } if (!o.all_of()) { // not ready yet - return std::nullopt; + return {std::nullopt}; } auto* file_backend = o.get().ptr; if (file_backend == nullptr) { std::cerr << "MIL error: object backend nullptr\n"; - return std::nullopt; + return {std::nullopt}; } auto file2 = file_backend->file2(o, StorageBackendI::FILE2_READ); if (!file2 || !file2->isGood() || !file2->can_read) { std::cerr << "MIL error: creating file2 from object via backendI\n"; - return std::nullopt; + return {std::nullopt}; } auto read_data = file2->read(file_size, 0); if (read_data.ptr == nullptr) { std::cerr << "MMIL error: reading from file2 returned nullptr\n"; - return std::nullopt; + return {std::nullopt}; } if (read_data.size != file_size) { std::cerr << "MIL error: reading from file2 size missmatch, should be " << file_size << ", is " << read_data.size << "\n"; - return std::nullopt; + return {std::nullopt}; } // try all loaders after another @@ -107,7 +107,7 @@ std::optional MessageImageLoader::load(TextureUploaderI& tu, Messa new_entry.timestamp_last_rendered = Message::getTimeMS(); new_entry.current_texture = 0; for (const auto& [ms, data] : res.frames) { - const auto n_t = tu.uploadRGBA(data.data(), res.width, res.height); + const auto n_t = tu.upload(data.data(), res.width, res.height); new_entry.textures.push_back(n_t); new_entry.frame_duration.push_back(ms); } @@ -117,10 +117,10 @@ std::optional MessageImageLoader::load(TextureUploaderI& tu, Messa std::cout << "MIL: loaded image file o:" << /*file_path*/ entt::to_integral(o.entity()) << "\n"; - return new_entry; + return {new_entry}; } std::cerr << "MIL error: failed to load message (unhandled format)\n"; - return std::nullopt; + return {std::nullopt}; } diff --git a/src/message_image_loader.hpp b/src/message_image_loader.hpp index bbbfe71..50a52ea 100644 --- a/src/message_image_loader.hpp +++ b/src/message_image_loader.hpp @@ -12,6 +12,6 @@ class MessageImageLoader { public: MessageImageLoader(void); - std::optional load(TextureUploaderI& tu, Message3Handle m); + TextureLoaderResult load(TextureUploaderI& tu, Message3Handle m); }; diff --git a/src/texture_cache.cpp b/src/texture_cache.cpp index b7657cb..658effb 100644 --- a/src/texture_cache.cpp +++ b/src/texture_cache.cpp @@ -46,7 +46,7 @@ TextureEntry generateTestAnim(TextureUploaderI& tu) { } } - const auto n_t = tu.uploadRGBA(pixels.data(), width, height); + const auto n_t = tu.upload(pixels.data(), width, height); // this is so ugly new_entry.textures.emplace_back(n_t); diff --git a/src/texture_cache.hpp b/src/texture_cache.hpp index eb0ef6b..4b0b9c7 100644 --- a/src/texture_cache.hpp +++ b/src/texture_cache.hpp @@ -6,6 +6,7 @@ #include #include +#include struct TextureEntry { uint32_t width {0}; @@ -70,6 +71,11 @@ struct TextureEntry { } }; +struct TextureLoaderResult { + std::optional texture; + bool keep_trying{false}; // if set, cant be cleared, as some async might be going on +}; + TextureEntry generateTestAnim(TextureUploaderI& tu); // fwd @@ -188,12 +194,12 @@ struct TextureCache { for (; it != _to_load.end(); it++) { if (_cache.count(*it)) { auto new_entry_opt = _l.load(_tu, *it); - if (new_entry_opt.has_value()) { + if (new_entry_opt.texture.has_value()) { auto old_entry = _cache.at(*it); for (const auto& tex_id : old_entry.textures) { _tu.destroy(tex_id); } - auto [new_it, _] = _cache.insert_or_assign(*it, new_entry_opt.value()); + auto [new_it, _] = _cache.insert_or_assign(*it, new_entry_opt.texture.value()); //new_it->second.current_texture = old_entry.current_texture; // ?? new_it->second.rendered_this_frame = old_entry.rendered_this_frame; new_it->second.timestamp_last_rendered = old_entry.timestamp_last_rendered; @@ -202,15 +208,21 @@ struct TextureCache { // TODO: not a good idea? break; // end load from queue/onlyload 1 per update + } else if (!new_entry_opt.keep_trying) { + // failed to load and the loader is done + it = _to_load.erase(it); } } else { auto new_entry_opt = _l.load(_tu, *it); - if (new_entry_opt.has_value()) { - _cache.emplace(*it, new_entry_opt.value()); + if (new_entry_opt.texture.has_value()) { + _cache.emplace(*it, new_entry_opt.texture.value()); it = _to_load.erase(it); // TODO: not a good idea? break; // end load from queue/onlyload 1 per update + } else if (!new_entry_opt.keep_trying) { + // failed to load and the loader is done + it = _to_load.erase(it); } } } diff --git a/src/tox_avatar_loader.cpp b/src/tox_avatar_loader.cpp index 29eeac4..85fe0aa 100644 --- a/src/tox_avatar_loader.cpp +++ b/src/tox_avatar_loader.cpp @@ -4,6 +4,7 @@ #include "./image_loader_qoi.hpp" #include "./image_loader_webp.hpp" #include "./image_loader_sdl_image.hpp" +#include "texture_uploader.hpp" #include #include @@ -119,9 +120,9 @@ static std::vector generateToxIdenticon(const ToxKey& key) { return pixels; } -std::optional ToxAvatarLoader::load(TextureUploaderI& tu, Contact3 c) { +TextureLoaderResult ToxAvatarLoader::load(TextureUploaderI& tu, Contact3 c) { if (!_cr.valid(c)) { - return std::nullopt; + return {std::nullopt}; } if (_cr.all_of(c)) { @@ -134,13 +135,13 @@ std::optional ToxAvatarLoader::load(TextureUploaderI& tu, Contact3 new_entry.width = a_m.width; new_entry.height = a_m.height; - const auto n_t = tu.uploadRGBA(a_m.data.data(), a_m.width, a_m.height); + const auto n_t = tu.upload(a_m.data.data(), a_m.width, a_m.height); new_entry.textures.push_back(n_t); new_entry.frame_duration.push_back(250); std::cout << "TAL: loaded memory buffer\n"; - return new_entry; + return {new_entry}; } if (_cr.all_of(c)) { @@ -169,7 +170,7 @@ std::optional ToxAvatarLoader::load(TextureUploaderI& tu, Contact3 new_entry.timestamp_last_rendered = Message::getTimeMS(); new_entry.current_texture = 0; for (const auto& [ms, data] : res.frames) { - const auto n_t = tu.uploadRGBA(data.data(), res.width, res.height); + const auto n_t = tu.upload(data.data(), res.width, res.height); new_entry.textures.push_back(n_t); new_entry.frame_duration.push_back(ms); } @@ -179,7 +180,7 @@ std::optional ToxAvatarLoader::load(TextureUploaderI& tu, Contact3 std::cout << "TAL: loaded image file " << a_f.file_path << "\n"; - return new_entry; + return {new_entry}; } } } // continues if loading img fails @@ -190,7 +191,7 @@ std::optional ToxAvatarLoader::load(TextureUploaderI& tu, Contact3 Contact::Components::ToxGroupPeerPersistent, Contact::Components::ID >(c)) { - return std::nullopt; + return {std::nullopt}; } std::vector pixels; @@ -212,7 +213,7 @@ std::optional ToxAvatarLoader::load(TextureUploaderI& tu, Contact3 new_entry.timestamp_last_rendered = Message::getTimeMS(); new_entry.current_texture = 0; - const auto n_t = tu.uploadRGBA(pixels.data(), 5, 5, TextureUploaderI::NEAREST); + const auto n_t = tu.upload(pixels.data(), 5, 5, TextureUploaderI::RGBA, TextureUploaderI::NEAREST); new_entry.textures.push_back(n_t); new_entry.frame_duration.push_back(250); @@ -221,6 +222,6 @@ std::optional ToxAvatarLoader::load(TextureUploaderI& tu, Contact3 std::cout << "TAL: generated ToxIdenticon\n"; - return new_entry; + return {new_entry}; } diff --git a/src/tox_avatar_loader.hpp b/src/tox_avatar_loader.hpp index 41541a7..87d95fb 100644 --- a/src/tox_avatar_loader.hpp +++ b/src/tox_avatar_loader.hpp @@ -14,6 +14,6 @@ class ToxAvatarLoader { public: ToxAvatarLoader(Contact3Registry& cr); - std::optional load(TextureUploaderI& tu, Contact3 c); + TextureLoaderResult load(TextureUploaderI& tu, Contact3 c); };