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
|
./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
|
||||||
|
@ -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},
|
||||||
|
@ -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
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