texture cache refactor to later allow async loading
Some checks failed
ContinuousDelivery / linux-ubuntu (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android]) (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android]) (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android]) (push) Has been cancelled
ContinuousDelivery / windows (push) Has been cancelled
ContinuousDelivery / windows-asan (push) Has been cancelled
ContinuousIntegration / linux (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android]) (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android]) (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android]) (push) Has been cancelled
ContinuousIntegration / macos (push) Has been cancelled
ContinuousIntegration / windows (push) Has been cancelled
ContinuousDelivery / release (push) Has been cancelled

This commit is contained in:
Green Sky 2024-12-16 00:32:07 +01:00
parent f2027befc8
commit 11ae259f67
No known key found for this signature in database
9 changed files with 54 additions and 41 deletions

@ -1 +1 @@
Subproject commit 717748e8fc6ecd2170aa98ca442727fb1fe32834 Subproject commit 85bbbb0e5a572b61067f3db188f3cfbda0948e7e

View File

@ -71,27 +71,27 @@ std::optional<TextureEntry> BitsetImageLoader::haveToTexture(TextureUploaderI& t
BitsetImageLoader::BitsetImageLoader(void) { BitsetImageLoader::BitsetImageLoader(void) {
} }
std::optional<TextureEntry> BitsetImageLoader::load(TextureUploaderI& tu, ObjectHandle o) { TextureLoaderResult BitsetImageLoader::load(TextureUploaderI& tu, ObjectHandle o) {
if (!static_cast<bool>(o)) { if (!static_cast<bool>(o)) {
std::cerr << "BIL error: trying to load invalid object\n"; std::cerr << "BIL error: trying to load invalid object\n";
return std::nullopt; return {std::nullopt};
} }
if (!o.any_of<ObjComp::F::LocalHaveBitset, ObjComp::F::RemoteHaveBitset>()) { if (!o.any_of<ObjComp::F::LocalHaveBitset, ObjComp::F::RemoteHaveBitset>()) {
// after completion, this is called until the texture times out // after completion, this is called until the texture times out
//std::cout << "BIL: no local have bitset\n"; //std::cout << "BIL: no local have bitset\n";
return std::nullopt; return {std::nullopt};
} }
if (o.all_of<ObjComp::F::LocalHaveBitset>()) { if (o.all_of<ObjComp::F::LocalHaveBitset>()) {
auto& have = o.get<ObjComp::F::LocalHaveBitset>().have; auto& have = o.get<ObjComp::F::LocalHaveBitset>().have;
assert(have.size_bits() > 0); assert(have.size_bits() > 0);
return haveToTexture(tu, have, o); return {haveToTexture(tu, have, o)};
} else if (o.all_of<ObjComp::F::RemoteHaveBitset>()) { } else if (o.all_of<ObjComp::F::RemoteHaveBitset>()) {
auto& list = o.get<ObjComp::F::RemoteHaveBitset>().others; auto& list = o.get<ObjComp::F::RemoteHaveBitset>().others;
if (list.empty()) { if (list.empty()) {
std::cout << "BIL: remote set list empty\n"; std::cout << "BIL: remote set list empty\n";
return std::nullopt; return {std::nullopt};
} }
const auto& first_entry = list.begin()->second; const auto& first_entry = list.begin()->second;
@ -115,10 +115,10 @@ std::optional<TextureEntry> 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<TextureEntry> BitsetImageLoader::load(TextureUploaderI& tu, ObjectContactSub ocs) { std::optional<TextureEntry> BitsetImageLoader::load(TextureUploaderI& tu, ObjectContactSub ocs) {

View File

@ -30,7 +30,7 @@ class BitsetImageLoader {
public: public:
BitsetImageLoader(void); BitsetImageLoader(void);
std::optional<TextureEntry> load(TextureUploaderI& tu, ObjectHandle o); TextureLoaderResult load(TextureUploaderI& tu, ObjectHandle o);
std::optional<TextureEntry> load(TextureUploaderI& tu, ObjectContactSub ocs); std::optional<TextureEntry> load(TextureUploaderI& tu, ObjectContactSub ocs);
}; };

View File

@ -30,29 +30,29 @@ MessageImageLoader::MessageImageLoader(void) {
_image_loaders.push_back(std::make_unique<ImageLoaderSDLImage>()); _image_loaders.push_back(std::make_unique<ImageLoaderSDLImage>());
} }
std::optional<TextureEntry> MessageImageLoader::load(TextureUploaderI& tu, Message3Handle m) { TextureLoaderResult MessageImageLoader::load(TextureUploaderI& tu, Message3Handle m) {
if (!static_cast<bool>(m)) { if (!static_cast<bool>(m)) {
return std::nullopt; return {std::nullopt};
} }
if (m.all_of<Message::Components::TagNotImage>()) { if (m.all_of<Message::Components::TagNotImage>()) {
return std::nullopt; return {std::nullopt};
} }
if (!m.all_of<Message::Components::MessageFileObject>()) { if (!m.all_of<Message::Components::MessageFileObject>()) {
// not a file message // not a file message
return std::nullopt; return {std::nullopt};
} }
const auto& o = m.get<Message::Components::MessageFileObject>().o; const auto& o = m.get<Message::Components::MessageFileObject>().o;
if (!static_cast<bool>(o)) { if (!static_cast<bool>(o)) {
std::cerr << "MIL error: invalid object in file message\n"; std::cerr << "MIL error: invalid object in file message\n";
return std::nullopt; return {std::nullopt};
} }
if (!o.all_of<ObjComp::Ephemeral::Backend, ObjComp::F::SingleInfo>()) { if (!o.all_of<ObjComp::Ephemeral::Backend, ObjComp::F::SingleInfo>()) {
std::cerr << "MIL error: object missing backend (?)\n"; std::cerr << "MIL error: object missing backend (?)\n";
return std::nullopt; return {std::nullopt};
} }
// TODO: handle collections // TODO: handle collections
@ -60,40 +60,40 @@ std::optional<TextureEntry> MessageImageLoader::load(TextureUploaderI& tu, Messa
if (file_size > 50*1024*1024) { if (file_size > 50*1024*1024) {
std::cerr << "MIL error: image file too large\n"; std::cerr << "MIL error: image file too large\n";
return std::nullopt; return {std::nullopt};
} }
if (file_size == 0) { if (file_size == 0) {
std::cerr << "MIL warning: empty file\n"; std::cerr << "MIL warning: empty file\n";
return std::nullopt; return {std::nullopt};
} }
if (!o.all_of<ObjComp::F::TagLocalHaveAll>()) { if (!o.all_of<ObjComp::F::TagLocalHaveAll>()) {
// not ready yet // not ready yet
return std::nullopt; return {std::nullopt};
} }
auto* file_backend = o.get<ObjComp::Ephemeral::Backend>().ptr; auto* file_backend = o.get<ObjComp::Ephemeral::Backend>().ptr;
if (file_backend == nullptr) { if (file_backend == nullptr) {
std::cerr << "MIL error: object backend nullptr\n"; std::cerr << "MIL error: object backend nullptr\n";
return std::nullopt; return {std::nullopt};
} }
auto file2 = file_backend->file2(o, StorageBackendI::FILE2_READ); auto file2 = file_backend->file2(o, StorageBackendI::FILE2_READ);
if (!file2 || !file2->isGood() || !file2->can_read) { if (!file2 || !file2->isGood() || !file2->can_read) {
std::cerr << "MIL error: creating file2 from object via backendI\n"; 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); auto read_data = file2->read(file_size, 0);
if (read_data.ptr == nullptr) { if (read_data.ptr == nullptr) {
std::cerr << "MMIL error: reading from file2 returned nullptr\n"; std::cerr << "MMIL error: reading from file2 returned nullptr\n";
return std::nullopt; return {std::nullopt};
} }
if (read_data.size != file_size) { if (read_data.size != file_size) {
std::cerr << "MIL error: reading from file2 size missmatch, should be " << file_size << ", is " << read_data.size << "\n"; 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 // try all loaders after another
@ -107,7 +107,7 @@ std::optional<TextureEntry> MessageImageLoader::load(TextureUploaderI& tu, Messa
new_entry.timestamp_last_rendered = Message::getTimeMS(); new_entry.timestamp_last_rendered = Message::getTimeMS();
new_entry.current_texture = 0; new_entry.current_texture = 0;
for (const auto& [ms, data] : res.frames) { 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.textures.push_back(n_t);
new_entry.frame_duration.push_back(ms); new_entry.frame_duration.push_back(ms);
} }
@ -117,10 +117,10 @@ std::optional<TextureEntry> MessageImageLoader::load(TextureUploaderI& tu, Messa
std::cout << "MIL: loaded image file o:" << /*file_path*/ entt::to_integral(o.entity()) << "\n"; 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"; std::cerr << "MIL error: failed to load message (unhandled format)\n";
return std::nullopt; return {std::nullopt};
} }

View File

@ -12,6 +12,6 @@ class MessageImageLoader {
public: public:
MessageImageLoader(void); MessageImageLoader(void);
std::optional<TextureEntry> load(TextureUploaderI& tu, Message3Handle m); TextureLoaderResult load(TextureUploaderI& tu, Message3Handle m);
}; };

View File

@ -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 // this is so ugly
new_entry.textures.emplace_back(n_t); new_entry.textures.emplace_back(n_t);

View File

@ -6,6 +6,7 @@
#include <entt/container/dense_set.hpp> #include <entt/container/dense_set.hpp>
#include <iostream> #include <iostream>
#include <optional>
struct TextureEntry { struct TextureEntry {
uint32_t width {0}; uint32_t width {0};
@ -70,6 +71,11 @@ struct TextureEntry {
} }
}; };
struct TextureLoaderResult {
std::optional<TextureEntry> texture;
bool keep_trying{false}; // if set, cant be cleared, as some async might be going on
};
TextureEntry generateTestAnim(TextureUploaderI& tu); TextureEntry generateTestAnim(TextureUploaderI& tu);
// fwd // fwd
@ -188,12 +194,12 @@ struct TextureCache {
for (; it != _to_load.end(); it++) { for (; it != _to_load.end(); it++) {
if (_cache.count(*it)) { if (_cache.count(*it)) {
auto new_entry_opt = _l.load(_tu, *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); auto old_entry = _cache.at(*it);
for (const auto& tex_id : old_entry.textures) { for (const auto& tex_id : old_entry.textures) {
_tu.destroy(tex_id); _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.current_texture = old_entry.current_texture; // ??
new_it->second.rendered_this_frame = old_entry.rendered_this_frame; new_it->second.rendered_this_frame = old_entry.rendered_this_frame;
new_it->second.timestamp_last_rendered = old_entry.timestamp_last_rendered; new_it->second.timestamp_last_rendered = old_entry.timestamp_last_rendered;
@ -202,15 +208,21 @@ struct TextureCache {
// TODO: not a good idea? // TODO: not a good idea?
break; // end load from queue/onlyload 1 per update 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 { } else {
auto new_entry_opt = _l.load(_tu, *it); auto new_entry_opt = _l.load(_tu, *it);
if (new_entry_opt.has_value()) { if (new_entry_opt.texture.has_value()) {
_cache.emplace(*it, new_entry_opt.value()); _cache.emplace(*it, new_entry_opt.texture.value());
it = _to_load.erase(it); it = _to_load.erase(it);
// TODO: not a good idea? // TODO: not a good idea?
break; // end load from queue/onlyload 1 per update 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);
} }
} }
} }

View File

@ -4,6 +4,7 @@
#include "./image_loader_qoi.hpp" #include "./image_loader_qoi.hpp"
#include "./image_loader_webp.hpp" #include "./image_loader_webp.hpp"
#include "./image_loader_sdl_image.hpp" #include "./image_loader_sdl_image.hpp"
#include "texture_uploader.hpp"
#include <solanaceae/contact/components.hpp> #include <solanaceae/contact/components.hpp>
#include <solanaceae/tox_contacts/components.hpp> #include <solanaceae/tox_contacts/components.hpp>
@ -119,9 +120,9 @@ static std::vector<uint8_t> generateToxIdenticon(const ToxKey& key) {
return pixels; return pixels;
} }
std::optional<TextureEntry> ToxAvatarLoader::load(TextureUploaderI& tu, Contact3 c) { TextureLoaderResult ToxAvatarLoader::load(TextureUploaderI& tu, Contact3 c) {
if (!_cr.valid(c)) { if (!_cr.valid(c)) {
return std::nullopt; return {std::nullopt};
} }
if (_cr.all_of<Contact::Components::AvatarMemory>(c)) { if (_cr.all_of<Contact::Components::AvatarMemory>(c)) {
@ -134,13 +135,13 @@ std::optional<TextureEntry> ToxAvatarLoader::load(TextureUploaderI& tu, Contact3
new_entry.width = a_m.width; new_entry.width = a_m.width;
new_entry.height = a_m.height; 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.textures.push_back(n_t);
new_entry.frame_duration.push_back(250); new_entry.frame_duration.push_back(250);
std::cout << "TAL: loaded memory buffer\n"; std::cout << "TAL: loaded memory buffer\n";
return new_entry; return {new_entry};
} }
if (_cr.all_of<Contact::Components::AvatarFile>(c)) { if (_cr.all_of<Contact::Components::AvatarFile>(c)) {
@ -169,7 +170,7 @@ std::optional<TextureEntry> ToxAvatarLoader::load(TextureUploaderI& tu, Contact3
new_entry.timestamp_last_rendered = Message::getTimeMS(); new_entry.timestamp_last_rendered = Message::getTimeMS();
new_entry.current_texture = 0; new_entry.current_texture = 0;
for (const auto& [ms, data] : res.frames) { 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.textures.push_back(n_t);
new_entry.frame_duration.push_back(ms); new_entry.frame_duration.push_back(ms);
} }
@ -179,7 +180,7 @@ std::optional<TextureEntry> ToxAvatarLoader::load(TextureUploaderI& tu, Contact3
std::cout << "TAL: loaded image file " << a_f.file_path << "\n"; std::cout << "TAL: loaded image file " << a_f.file_path << "\n";
return new_entry; return {new_entry};
} }
} }
} // continues if loading img fails } // continues if loading img fails
@ -190,7 +191,7 @@ std::optional<TextureEntry> ToxAvatarLoader::load(TextureUploaderI& tu, Contact3
Contact::Components::ToxGroupPeerPersistent, Contact::Components::ToxGroupPeerPersistent,
Contact::Components::ID Contact::Components::ID
>(c)) { >(c)) {
return std::nullopt; return {std::nullopt};
} }
std::vector<uint8_t> pixels; std::vector<uint8_t> pixels;
@ -212,7 +213,7 @@ std::optional<TextureEntry> ToxAvatarLoader::load(TextureUploaderI& tu, Contact3
new_entry.timestamp_last_rendered = Message::getTimeMS(); new_entry.timestamp_last_rendered = Message::getTimeMS();
new_entry.current_texture = 0; 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.textures.push_back(n_t);
new_entry.frame_duration.push_back(250); new_entry.frame_duration.push_back(250);
@ -221,6 +222,6 @@ std::optional<TextureEntry> ToxAvatarLoader::load(TextureUploaderI& tu, Contact3
std::cout << "TAL: generated ToxIdenticon\n"; std::cout << "TAL: generated ToxIdenticon\n";
return new_entry; return {new_entry};
} }

View File

@ -14,6 +14,6 @@ class ToxAvatarLoader {
public: public:
ToxAvatarLoader(Contact3Registry& cr); ToxAvatarLoader(Contact3Registry& cr);
std::optional<TextureEntry> load(TextureUploaderI& tu, Contact3 c); TextureLoaderResult load(TextureUploaderI& tu, Contact3 c);
}; };