start texture cache for contacts (avatars)

This commit is contained in:
Green Sky 2023-07-31 20:47:22 +02:00
parent c0b57c30bd
commit ef59386e5c
No known key found for this signature in database
5 changed files with 216 additions and 5 deletions

View File

@ -23,6 +23,8 @@ add_executable(tomato
./texture_uploader.hpp ./texture_uploader.hpp
./sdlrenderer_texture_uploader.hpp ./sdlrenderer_texture_uploader.hpp
./sdlrenderer_texture_uploader.cpp ./sdlrenderer_texture_uploader.cpp
./texture_cache.hpp
./texture_cache.cpp
./sdl_clipboard_utils.hpp ./sdl_clipboard_utils.hpp
./sdl_clipboard_utils.cpp ./sdl_clipboard_utils.cpp
./file_selector.hpp ./file_selector.hpp

View File

@ -14,7 +14,6 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include "./sdl_clipboard_utils.hpp" #include "./sdl_clipboard_utils.hpp"
#include "SDL_clipboard.h"
#include <string> #include <string>
#include <variant> #include <variant>
@ -28,7 +27,7 @@ ChatGui4::ChatGui4(
RegistryMessageModel& rmm, RegistryMessageModel& rmm,
Contact3Registry& cr, Contact3Registry& cr,
TextureUploaderI& tu TextureUploaderI& tu
) : _conf(conf), _rmm(rmm), _cr(cr) { ) : _conf(conf), _rmm(rmm), _cr(cr), _contact_tc(tu) {
} }
void ChatGui4::render(void) { void ChatGui4::render(void) {
@ -277,7 +276,7 @@ void ChatGui4::render(void) {
_fss.render(); _fss.render();
//_tc.update(); _contact_tc.update();
//_tc.workLoadQueue(); //_tc.workLoadQueue();
} }
@ -514,8 +513,8 @@ bool ChatGui4::renderContactListContactBig(const Contact3 c) {
} }
// avatar // avatar
#if 0 #if 1
const auto [id, width, height] = _tc.get("test"); const auto [id, width, height] = _contact_tc.get(c);
ImGui::Image( ImGui::Image(
id, id,
ImVec2{img_y, img_y}, ImVec2{img_y, img_y},

View File

@ -4,6 +4,7 @@
#include <solanaceae/util/config_model.hpp> #include <solanaceae/util/config_model.hpp>
#include "./texture_uploader.hpp" #include "./texture_uploader.hpp"
#include "./texture_cache.hpp"
#include "./file_selector.hpp" #include "./file_selector.hpp"
#include <vector> #include <vector>
@ -14,6 +15,9 @@ class ChatGui4 {
RegistryMessageModel& _rmm; RegistryMessageModel& _rmm;
Contact3Registry& _cr; Contact3Registry& _cr;
TextureCache<void*, Contact3> _contact_tc;
//TextureCache<Message3Handle> _msg_tc;
FileSelector _fss; FileSelector _fss;
std::optional<Contact3> _selected_contact; std::optional<Contact3> _selected_contact;

59
src/texture_cache.cpp Normal file
View File

@ -0,0 +1,59 @@
#include "./texture_cache.hpp"
#include <chrono>
void TextureEntry::doAnimation(const uint64_t ts_now) {
if (frame_duration.size() > 1) { // is animation
do { // why is this loop so ugly
const uint64_t duration = getDuration();
if (ts_now - timestamp_last_rendered >= duration) {
timestamp_last_rendered += duration;
next();
} else {
break;
}
} while(true);
} else {
timestamp_last_rendered = ts_now;
}
}
TextureEntry generateTestAnim(TextureUploaderI& tu) {
TextureEntry new_entry;
new_entry.timestamp_last_rendered = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
new_entry.current_texture = 0;
for (size_t i = 0; i < 4; i++) {
// hack
// generate frame
const size_t width {2};
const size_t height {2};
std::array<uint8_t, width*height*4> pixels;
for (size_t pen = 0; pen < width*height; pen++) {
if (pen == i) {
pixels[pen*4+0] = 0xff;
pixels[pen*4+1] = 0xff;
pixels[pen*4+2] = 0xff;
pixels[pen*4+3] = 0xff;
} else {
pixels[pen*4+0] = 0x00;
pixels[pen*4+1] = 0x00;
pixels[pen*4+2] = 0x00;
pixels[pen*4+3] = 0xff;
}
}
const auto n_t = tu.uploadRGBA(pixels.data(), width, height);
// this is so ugly
new_entry.textures.emplace_back(n_t);
new_entry.frame_duration.emplace_back(250);
}
new_entry.width = 2;
new_entry.height = 2;
return new_entry;
}
uint64_t getNowMS(void) {
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}

147
src/texture_cache.hpp Normal file
View File

@ -0,0 +1,147 @@
#pragma once
#include "./texture_uploader.hpp"
#include <entt/container/dense_map.hpp>
#include <entt/container/dense_set.hpp>
#include <iostream>
struct TextureEntry {
uint32_t width {0};
uint32_t height {0};
std::vector<uint64_t> textures;
std::vector<uint32_t> frame_duration; // ms
size_t current_texture {0};
bool rendered_this_frame {false};
// or flipped for animations
uint64_t timestamp_last_rendered {0}; // ms
TextureEntry(void) = default;
TextureEntry(const TextureEntry& other) :
width(other.width),
height(other.height),
textures(other.textures),
frame_duration(other.frame_duration),
current_texture(other.current_texture),
rendered_this_frame(other.rendered_this_frame),
timestamp_last_rendered(other.timestamp_last_rendered)
{}
TextureEntry& operator=(const TextureEntry& other) {
width = other.width;
height = other.height;
textures = other.textures;
frame_duration = other.frame_duration;
current_texture = other.current_texture;
rendered_this_frame = other.rendered_this_frame;
timestamp_last_rendered = other.timestamp_last_rendered;
return *this;
}
uint32_t getDuration(void) const {
return frame_duration.at(current_texture);
}
void next(void) {
current_texture = (current_texture + 1) % frame_duration.size();
}
void doAnimation(const uint64_t ts_now);
template<typename TextureType>
TextureType getID(void) {
static_assert(
sizeof(TextureType) == sizeof(uint64_t) ||
sizeof(TextureType) == sizeof(uint32_t)
);
rendered_this_frame = true;
assert(current_texture < textures.size());
if constexpr (sizeof(TextureType) == sizeof(uint64_t)) {
return reinterpret_cast<TextureType>(textures.at(current_texture));
} else if constexpr (sizeof(TextureType) == sizeof(uint32_t)) {
return reinterpret_cast<TextureType>(static_cast<uint32_t>(textures.at(current_texture)));
}
}
};
TextureEntry generateTestAnim(TextureUploaderI& tu);
uint64_t getNowMS(void);
template<typename TextureType, typename KeyType>
struct TextureCache {
static_assert(
sizeof(TextureType) == sizeof(uint64_t) ||
sizeof(TextureType) == sizeof(uint32_t)
);
TextureUploaderI& _tu;
TextureEntry _default_texture;
entt::dense_map<KeyType, TextureEntry> _cache;
entt::dense_set<KeyType> _to_load;
const uint64_t ms_before_purge {60 * 1000ull};
const size_t min_count_before_purge {0}; // starts purging after that
TextureCache(TextureUploaderI& tu) : _tu(tu) {
//_image_loaders.push_back(std::make_unique<ImageLoaderWebP>());
//_image_loaders.push_back(std::make_unique<ImageLoaderSTB>());
_default_texture = generateTestAnim(_tu);
//_default_texture = loadTestWebPAnim();
}
struct GetInfo {
TextureType id;
uint32_t width;
uint32_t height;
};
GetInfo get(const KeyType& key) {
auto it = _cache.find(key);
if (it != _cache.end()) {
return {
it->second.template getID<TextureType>(),
it->second.width,
it->second.height
};
} else {
_to_load.insert(key);
return {
_default_texture.getID<TextureType>(),
_default_texture.width,
_default_texture.height
};
}
}
void update(void) {
const uint64_t ts_now = getNowMS();
std::vector<KeyType> to_purge;
for (auto&& [key, te] : _cache) {
if (te.rendered_this_frame) {
te.doAnimation(ts_now);
te.rendered_this_frame = false;
} else if (_cache.size() > min_count_before_purge && ts_now - te.timestamp_last_rendered >= ms_before_purge) {
to_purge.push_back(key);
}
}
for (const auto& key : to_purge) {
for (const auto& tex_id : _cache.at(key).textures) {
_tu.destroy(tex_id);
}
_cache.erase(key);
}
_default_texture.doAnimation(ts_now);
}
};