Add new icon cache, for caching small images.

It doesn't try to insert or fetch missing things itself, re-fetching is up to the caller.

This will be required for handling the many achievement icons.

Saving/loading the cache to a single file on disk is implemented but not
hooked up yet. It works without it, though of course will have to
re-fetch things on the next startup.
This commit is contained in:
Henrik Rydgård 2023-06-18 12:10:52 +02:00
parent 9f88dbd656
commit 2bee5b64e4
6 changed files with 51 additions and 13 deletions

View File

@ -259,6 +259,7 @@ public:
// We pass in width/height here even though it's not strictly needed until we support glTextureStorage
// and then we'll also need formats and stuff.
GLRTexture *CreateTexture(GLenum target, int width, int height, int depth, int numMips) {
_dbg_assert_(target != 0);
GLRInitStep &step = initSteps_.push_uninitialized();
step.stepType = GLRInitStepType::CREATE_TEXTURE;
step.create_texture.texture = new GLRTexture(caps_, width, height, depth, numMips);

View File

@ -822,7 +822,7 @@ InputLayout *OpenGLContext::CreateInputLayout(const InputLayoutDesc &desc) {
return fmt;
}
GLuint TypeToTarget(TextureType type) {
static GLuint TypeToTarget(TextureType type) {
switch (type) {
#ifndef USING_GLES2
case TextureType::LINEAR1D: return GL_TEXTURE_1D;
@ -875,6 +875,10 @@ private:
};
OpenGLTexture::OpenGLTexture(GLRenderManager *render, const TextureDesc &desc) : render_(render) {
_dbg_assert_(desc.format != Draw::DataFormat::UNDEFINED);
_dbg_assert_(desc.width > 0 && desc.height > 0 && desc.depth > 0);
_dbg_assert_(type_ != Draw::TextureType::UNKNOWN);
generatedMips_ = false;
generateMips_ = desc.generateMips;
width_ = desc.width;

View File

@ -463,10 +463,10 @@ public:
class Texture : public RefCountedObject {
public:
Texture() : RefCountedObject("Texture") {}
int Width() { return width_; }
int Height() { return height_; }
int Depth() { return depth_; }
DataFormat Format() { return format_; }
int Width() const { return width_; }
int Height() const { return height_; }
int Depth() const { return depth_; }
DataFormat Format() const { return format_; }
protected:
int width_ = -1, height_ = -1, depth_ = -1;

View File

@ -119,6 +119,29 @@ void IconCache::Decimate() {
}
bool IconCache::GetDimensions(const std::string &key, int *width, int *height) {
std::unique_lock<std::mutex> lock(lock_);
auto iter = cache_.find(key);
if (iter == cache_.end()) {
// Don't have this entry.
return false;
}
if (iter->second.texture) {
// TODO: Store the width/height in the cache.
*width = iter->second.texture->Width();
*height = iter->second.texture->Height();
return true;
} else {
return false;
}
}
bool IconCache::Contains(const std::string &key) {
std::unique_lock<std::mutex> lock(lock_);
return cache_.find(key) != cache_.end();
}
bool IconCache::InsertIcon(const std::string &key, IconFormat format, std::string &&data) {
std::unique_lock<std::mutex> lock(lock_);
@ -141,22 +164,22 @@ bool IconCache::InsertIcon(const std::string &key, IconFormat format, std::strin
return true;
}
bool IconCache::BindIconTexture(UIContext *context, const std::string &key) {
Draw::Texture *IconCache::BindIconTexture(UIContext *context, const std::string &key) {
std::unique_lock<std::mutex> lock(lock_);
auto iter = cache_.find(key);
if (iter == cache_.end()) {
// Don't have this entry.
return false;
return nullptr;
}
if (iter->second.texture) {
context->GetDrawContext()->BindTexture(0, iter->second.texture);
iter->second.usedTimeStamp = time_now_d();
return true;
return iter->second.texture;
}
if (iter->second.badData) {
return false;
return nullptr;
}
// OK, don't have a texture. Upload it!
@ -174,13 +197,13 @@ bool IconCache::BindIconTexture(UIContext *context, const std::string &key) {
if (result != 1) {
ERROR_LOG(G3D, "IconCache: Failed to load png (%d bytes) for key %s", (int)iter->second.data.size(), key.c_str());
iter->second.badData = true;
return false;
return nullptr;
}
dataFormat = Draw::DataFormat::R8G8B8A8_UNORM;
break;
}
default:
return false;
return nullptr;
}
Draw::TextureDesc iconDesc{};
@ -192,11 +215,13 @@ bool IconCache::BindIconTexture(UIContext *context, const std::string &key) {
iconDesc.swizzle = Draw::TextureSwizzle::DEFAULT;
iconDesc.generateMips = false;
iconDesc.tag = key.c_str();
iconDesc.format = dataFormat;
iconDesc.type = Draw::TextureType::LINEAR2D;
Draw::Texture *texture = context->GetDrawContext()->CreateTexture(iconDesc);
iter->second.texture = texture;
free(buffer);
return true;
return texture;
}

View File

@ -14,14 +14,20 @@ enum class IconFormat : uint32_t {
PNG,
};
namespace Draw {
class Texture;
}
// TODO: Possibly make this smarter and use instead of ManagedTexture?
class IconCache {
public:
bool BindIconTexture(UIContext *context, const std::string &key);
Draw::Texture *BindIconTexture(UIContext *context, const std::string &key);
// It's okay to call this from any thread.
bool InsertIcon(const std::string &key, IconFormat format, std::string &&pngData);
bool GetDimensions(const std::string &key, int *width, int *height);
bool Contains(const std::string &key);
void SaveToFile(FILE *file);
bool LoadFromFile(FILE *file);

View File

@ -6,6 +6,7 @@
#include "Common/UI/UI.h"
#include "Common/UI/View.h"
#include "Common/UI/ViewGroup.h"
#include "Common/UI/IconCache.h"
#include "Common/Log.h"
#include "Common/TimeUtil.h"
@ -130,6 +131,7 @@ void ScreenManager::axis(const AxisInput &axis) {
void ScreenManager::deviceLost() {
for (auto &iter : stack_)
iter.screen->deviceLost();
g_iconCache.ClearTextures();
}
void ScreenManager::deviceRestored() {