Added rudimentary frame caching support to LottieComponent.

This commit is contained in:
Leon Styhre 2022-01-08 15:04:10 +01:00
parent 3f629b6c1e
commit b3421823a7
3 changed files with 77 additions and 4 deletions

View file

@ -277,6 +277,8 @@ void Settings::setDefaults()
mBoolMap["DebugSkipInputLogging"] = {false, false};
mStringMap["ROMDirectory"] = {"", ""};
mStringMap["UIMode_passkey"] = {"uuddlrlrba", "uuddlrlrba"};
mIntMap["LottieMaxFileCache"] = {100, 100};
mIntMap["LottieMaxTotalCache"] = {1024, 1024};
//
// Hardcoded or program-internal settings.

View file

@ -17,6 +17,10 @@
LottieComponent::LottieComponent(Window* window)
: GuiComponent{window}
, mCacheFrames{true}
, mMaxCacheSize{0}
, mCacheSize{0}
, mFrameSize{0}
, mAnimation{nullptr}
, mSurface{nullptr}
, mTotalFrames{0}
@ -35,6 +39,17 @@ LottieComponent::LottieComponent(Window* window)
mTexture->setFormat(Renderer::Texture::BGRA);
#endif
// Keep per-file cache size within 0 to 1024 MiB.
mMaxCacheSize = static_cast<size_t>(
glm::clamp(Settings::getInstance()->getInt("LottieMaxFileCache"), 0, 1024) * 1024 * 1024);
// Keep total cache size within 0 to 4096 MiB.
int maxTotalCache =
glm::clamp(Settings::getInstance()->getInt("LottieMaxTotalCache"), 0, 4096) * 1024 * 1024;
if (mMaxTotalFrameCache != static_cast<size_t>(maxTotalCache))
mMaxTotalFrameCache = static_cast<size_t>(maxTotalCache);
// Set component defaults.
setOrigin(0.5f, 0.5f);
setSize(Renderer::getScreenWidth() * 0.2f, Renderer::getScreenHeight() * 0.2f);
@ -43,6 +58,13 @@ LottieComponent::LottieComponent(Window* window)
setZIndex(30.0f);
}
LottieComponent::~LottieComponent()
{
if (mFuture.valid())
mFuture.get();
mTotalFrameCache -= mCacheSize;
}
void LottieComponent::setAnimation(const std::string& path)
{
if (mAnimation != nullptr) {
@ -51,6 +73,7 @@ void LottieComponent::setAnimation(const std::string& path)
mSurface.reset();
mAnimation.reset();
mPictureRGBA.clear();
mCacheSize = 0;
}
mPath = path;
@ -98,6 +121,7 @@ void LottieComponent::setAnimation(const std::string& path)
double duration = mAnimation->duration();
mTotalFrames = mAnimation->totalFrame();
mFrameRate = mAnimation->frameRate();
mFrameSize = width * height * 4;
mTargetPacing = static_cast<int>(1000.0 / mFrameRate);
@ -109,7 +133,8 @@ void LottieComponent::setAnimation(const std::string& path)
void LottieComponent::onSizeChanged()
{
// Setting the animation again will completely reinitialize it.
setAnimation(mPath);
if (mPath != "")
setAnimation(mPath);
}
void LottieComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
@ -156,16 +181,45 @@ void LottieComponent::render(const glm::mat4& parentTrans)
if (mFuture.valid()) {
if (mFuture.wait_for(std::chrono::milliseconds(1)) == std::future_status::ready) {
mFuture.get();
// Cache frame if caching is enabled and we're not exceeding either the per-file
// max cache size or the total cache size. Note that this is completely unrelated
// to the texture caching used for images.
if (mCacheFrames && mFrameCache.find(mFrameNum) == mFrameCache.end()) {
size_t newCacheSize = mCacheSize + mFrameSize;
if (newCacheSize < mMaxCacheSize &&
mTotalFrameCache + mFrameSize < mMaxTotalFrameCache) {
mFrameCache[mFrameNum] = mPictureRGBA;
mCacheSize += mFrameSize;
mTotalFrameCache += mFrameSize;
}
}
mTexture->initFromPixels(&mPictureRGBA.at(0), static_cast<size_t>(mSize.x),
static_cast<size_t>(mSize.y));
mFuture.get();
++mFrameNum;
renderNextFrame = true;
if (mFrameNum == mTotalFrames)
renderNextFrame = false;
else
renderNextFrame = true;
}
}
else {
renderNextFrame = true;
if (mFrameCache.find(mFrameNum) != mFrameCache.end()) {
if (!mHoldFrame) {
mTexture->initFromPixels(&mFrameCache[mFrameNum][0], static_cast<size_t>(mSize.x),
static_cast<size_t>(mSize.y));
++mFrameNum;
}
}
else {
renderNextFrame = true;
}
}
if (renderNextFrame && !mHoldFrame)
mFuture = mAnimation->render(mFrameNum, *mSurface, mKeepAspectRatio);

View file

@ -12,19 +12,27 @@
#include "GuiComponent.h"
#include "renderers/Renderer.h"
#include "resources/TextureResource.h"
#include "utils/MathUtil.h"
#include "rlottie.h"
#include <chrono>
#include <future>
#include <unordered_map>
class LottieComponent : public GuiComponent
{
public:
LottieComponent(Window* window);
~LottieComponent();
void setAnimation(const std::string& path);
void setKeepAspectRatio(bool value) { mKeepAspectRatio = value; }
void setFrameCaching(bool value) { mCacheFrames = value; }
void setMaxCacheSize(int value)
{
mMaxCacheSize = static_cast<size_t>(glm::clamp(value, 0, 1024) * 1024 * 1024);
}
void onSizeChanged() override;
@ -39,6 +47,14 @@ private:
std::shared_ptr<TextureResource> mTexture;
std::vector<uint8_t> mPictureRGBA;
std::unordered_map<size_t, std::vector<uint8_t>> mFrameCache;
// Set a 1024 MiB total Lottie animation cache as default.
inline static size_t mMaxTotalFrameCache = 1024 * 1024 * 1024;
inline static size_t mTotalFrameCache;
bool mCacheFrames;
size_t mMaxCacheSize;
size_t mCacheSize;
size_t mFrameSize;
std::unique_ptr<rlottie::Animation> mAnimation;
std::unique_ptr<rlottie::Surface> mSurface;
@ -53,6 +69,7 @@ private:
bool mKeepAspectRatio;
// TEMPORARY.
std::chrono::time_point<std::chrono::system_clock> mAnimationStartTime;
std::chrono::time_point<std::chrono::system_clock> mAnimationEndTime;
};