start texture cache for contacts (avatars)
This commit is contained in:
parent
c0b57c30bd
commit
ef59386e5c
@ -23,6 +23,8 @@ add_executable(tomato
|
||||
./texture_uploader.hpp
|
||||
./sdlrenderer_texture_uploader.hpp
|
||||
./sdlrenderer_texture_uploader.cpp
|
||||
./texture_cache.hpp
|
||||
./texture_cache.cpp
|
||||
./sdl_clipboard_utils.hpp
|
||||
./sdl_clipboard_utils.cpp
|
||||
./file_selector.hpp
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "./sdl_clipboard_utils.hpp"
|
||||
#include "SDL_clipboard.h"
|
||||
|
||||
#include <string>
|
||||
#include <variant>
|
||||
@ -28,7 +27,7 @@ ChatGui4::ChatGui4(
|
||||
RegistryMessageModel& rmm,
|
||||
Contact3Registry& cr,
|
||||
TextureUploaderI& tu
|
||||
) : _conf(conf), _rmm(rmm), _cr(cr) {
|
||||
) : _conf(conf), _rmm(rmm), _cr(cr), _contact_tc(tu) {
|
||||
}
|
||||
|
||||
void ChatGui4::render(void) {
|
||||
@ -277,7 +276,7 @@ void ChatGui4::render(void) {
|
||||
|
||||
_fss.render();
|
||||
|
||||
//_tc.update();
|
||||
_contact_tc.update();
|
||||
//_tc.workLoadQueue();
|
||||
}
|
||||
|
||||
@ -514,8 +513,8 @@ bool ChatGui4::renderContactListContactBig(const Contact3 c) {
|
||||
}
|
||||
|
||||
// avatar
|
||||
#if 0
|
||||
const auto [id, width, height] = _tc.get("test");
|
||||
#if 1
|
||||
const auto [id, width, height] = _contact_tc.get(c);
|
||||
ImGui::Image(
|
||||
id,
|
||||
ImVec2{img_y, img_y},
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <solanaceae/util/config_model.hpp>
|
||||
|
||||
#include "./texture_uploader.hpp"
|
||||
#include "./texture_cache.hpp"
|
||||
#include "./file_selector.hpp"
|
||||
|
||||
#include <vector>
|
||||
@ -14,6 +15,9 @@ class ChatGui4 {
|
||||
RegistryMessageModel& _rmm;
|
||||
Contact3Registry& _cr;
|
||||
|
||||
TextureCache<void*, Contact3> _contact_tc;
|
||||
//TextureCache<Message3Handle> _msg_tc;
|
||||
|
||||
FileSelector _fss;
|
||||
|
||||
std::optional<Contact3> _selected_contact;
|
||||
|
59
src/texture_cache.cpp
Normal file
59
src/texture_cache.cpp
Normal 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
147
src/texture_cache.hpp
Normal 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);
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user