Cache rendered fonts to speed up mobile load

This commit is contained in:
elasota
2020-10-24 11:41:39 -04:00
parent daebba7d47
commit 26c423bb58
10 changed files with 216 additions and 12 deletions

View File

@@ -123,18 +123,21 @@ GpFileSystem_Win32::GpFileSystem_Win32()
m_userSavesDir = m_prefsDir + L"\\SavedGames"; m_userSavesDir = m_prefsDir + L"\\SavedGames";
m_scoresDir = m_prefsDir + L"\\Scores"; m_scoresDir = m_prefsDir + L"\\Scores";
m_logsDir = m_prefsDir + L"\\Logs"; m_logsDir = m_prefsDir + L"\\Logs";
m_fontCacheDir = m_prefsDir + L"\\FontCache";
CreateDirectoryW(m_prefsDir.c_str(), nullptr); CreateDirectoryW(m_prefsDir.c_str(), nullptr);
CreateDirectoryW(m_scoresDir.c_str(), nullptr); CreateDirectoryW(m_scoresDir.c_str(), nullptr);
CreateDirectoryW(m_userHousesDir.c_str(), nullptr); CreateDirectoryW(m_userHousesDir.c_str(), nullptr);
CreateDirectoryW(m_userSavesDir.c_str(), nullptr); CreateDirectoryW(m_userSavesDir.c_str(), nullptr);
CreateDirectoryW(m_logsDir.c_str(), nullptr); CreateDirectoryW(m_logsDir.c_str(), nullptr);
CreateDirectoryW(m_fontCacheDir.c_str(), nullptr);
m_prefsDir.append(L"\\"); m_prefsDir.append(L"\\");
m_scoresDir.append(L"\\"); m_scoresDir.append(L"\\");
m_userHousesDir.append(L"\\"); m_userHousesDir.append(L"\\");
m_userSavesDir.append(L"\\"); m_userSavesDir.append(L"\\");
m_logsDir.append(L"\\"); m_logsDir.append(L"\\");
m_fontCacheDir.append(L"\\");
} }
DWORD modulePathSize = GetModuleFileNameW(nullptr, m_executablePath, MAX_PATH); DWORD modulePathSize = GetModuleFileNameW(nullptr, m_executablePath, MAX_PATH);
@@ -462,6 +465,9 @@ bool GpFileSystem_Win32::ResolvePath(PortabilityLayer::VirtualDirectory_t virtua
case PortabilityLayer::VirtualDirectories::kLogs: case PortabilityLayer::VirtualDirectories::kLogs:
baseDir = m_logsDir.c_str(); baseDir = m_logsDir.c_str();
break; break;
case PortabilityLayer::VirtualDirectories::kFontCache:
baseDir = m_fontCacheDir.c_str();
break;
default: default:
return false; return false;
} }

View File

@@ -41,6 +41,7 @@ private:
std::wstring m_userHousesDir; std::wstring m_userHousesDir;
std::wstring m_userSavesDir; std::wstring m_userSavesDir;
std::wstring m_resourcesDir; std::wstring m_resourcesDir;
std::wstring m_fontCacheDir;
wchar_t m_executablePath[MAX_PATH]; wchar_t m_executablePath[MAX_PATH];
static GpFileSystem_Win32 ms_instance; static GpFileSystem_Win32 ms_instance;

View File

@@ -441,6 +441,9 @@ bool GpFileSystem_Android::ResolvePath(PortabilityLayer::VirtualDirectory_t virt
case PortabilityLayer::VirtualDirectories::kPrefs: case PortabilityLayer::VirtualDirectories::kPrefs:
prefsAppend = "Prefs"; prefsAppend = "Prefs";
break; break;
case PortabilityLayer::VirtualDirectories::kFontCache:
prefsAppend = "FontCache";
break;
default: default:
return false; return false;
}; };
@@ -509,7 +512,7 @@ void GpFileSystem_Android::InitJNI()
prefsDir[i] = '/'; prefsDir[i] = '/';
} }
} }
const char *extensions[] = { "HighScores", "Houses", "SavedGames", "Prefs" }; const char *extensions[] = { "HighScores", "Houses", "SavedGames", "Prefs", "FontCache" };
for (size_t i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++) for (size_t i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++)
{ {
std::string prefsPath = std::string(prefsDir) + extensions[i]; std::string prefsPath = std::string(prefsDir) + extensions[i];

View File

@@ -60,13 +60,18 @@ namespace PortabilityLayer
return m_hacks[variation]; return m_hacks[variation];
} }
FontFamily *FontFamily::Create() int FontFamily::GetCacheID() const
{
return m_cacheID;
}
FontFamily *FontFamily::Create(int cacheID)
{ {
void *storage = malloc(sizeof(FontFamily)); void *storage = malloc(sizeof(FontFamily));
if (!storage) if (!storage)
return nullptr; return nullptr;
return new (storage) FontFamily(); return new (storage) FontFamily(cacheID);
} }
void FontFamily::Destroy() void FontFamily::Destroy()
@@ -75,8 +80,9 @@ namespace PortabilityLayer
free(this); free(this);
} }
FontFamily::FontFamily() FontFamily::FontFamily(int cacheID)
: m_defaultVariation(0) : m_defaultVariation(0)
, m_cacheID(cacheID)
{ {
for (unsigned int i = 0; i < kNumVariations; i++) for (unsigned int i = 0; i < kNumVariations; i++)
{ {

View File

@@ -29,15 +29,18 @@ namespace PortabilityLayer
IGpFont *GetFontForVariation(int variation) const; IGpFont *GetFontForVariation(int variation) const;
FontHacks GetHacksForVariation(int variation) const; FontHacks GetHacksForVariation(int variation) const;
static FontFamily *Create(); int GetCacheID() const;
static FontFamily *Create(int cacheID);
void Destroy(); void Destroy();
private: private:
FontHacks m_hacks[kNumVariations]; FontHacks m_hacks[kNumVariations];
IGpFont *m_fonts[kNumVariations]; IGpFont *m_fonts[kNumVariations];
uint8_t m_defaultVariation; uint8_t m_defaultVariation;
int m_cacheID;
FontFamily(); explicit FontFamily(int cacheID);
~FontFamily(); ~FontFamily();
}; };
} }

View File

@@ -7,7 +7,9 @@
#include "HostFontHandler.h" #include "HostFontHandler.h"
#include "GpIOStream.h" #include "GpIOStream.h"
#include "RenderedFont.h" #include "RenderedFont.h"
#include "PLBigEndian.h"
#include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@@ -27,10 +29,17 @@ namespace PortabilityLayer
RenderedFont *GetRenderedFont(IGpFont *font, int size, bool aa, FontHacks fontHacks) override; RenderedFont *GetRenderedFont(IGpFont *font, int size, bool aa, FontHacks fontHacks) override;
RenderedFont *GetRenderedFontFromFamily(FontFamily *font, int size, bool aa, int flags) override; RenderedFont *GetRenderedFontFromFamily(FontFamily *font, int size, bool aa, int flags) override;
RenderedFont *LoadCachedRenderedFont(int cacheID, int size, bool aa, int flags) const override;
void SaveCachedRenderedFont(const RenderedFont *rfont, int cacheID, int size, bool aa, int flags) const override;
static FontManagerImpl *GetInstance(); static FontManagerImpl *GetInstance();
private: private:
static const unsigned int kNumCachedRenderedFonts = 32; static const unsigned int kNumCachedRenderedFonts = 32;
static const int kSystemFontCacheID = 1;
static const int kApplicationFontCacheID = 2;
static const int kFontCacheVersion = 1;
static const int kFontCacheNameSize = 64;
struct CachedRenderedFont struct CachedRenderedFont
{ {
@@ -46,6 +55,8 @@ namespace PortabilityLayer
void ResetUsageCounter(); void ResetUsageCounter();
static int CRFSortPredicate(const void *a, const void *b); static int CRFSortPredicate(const void *a, const void *b);
static void GenerateCacheFileName(char(&str)[kFontCacheNameSize], int cacheID, int size, bool aa, int flags);
FontFamily *m_systemFont; FontFamily *m_systemFont;
FontFamily *m_applicationFont; FontFamily *m_applicationFont;
uint32_t m_usageCounter; uint32_t m_usageCounter;
@@ -57,8 +68,8 @@ namespace PortabilityLayer
void FontManagerImpl::Init() void FontManagerImpl::Init()
{ {
m_systemFont = FontFamily::Create(); m_systemFont = FontFamily::Create(kSystemFontCacheID);
m_applicationFont = FontFamily::Create(); m_applicationFont = FontFamily::Create(kApplicationFontCacheID);
if (m_systemFont) if (m_systemFont)
m_systemFont->AddFont(FontFamilyFlag_None, "Fonts/OpenSans/OpenSans-ExtraBold.ttf", FontHacks_None); m_systemFont->AddFont(FontFamilyFlag_None, "Fonts/OpenSans/OpenSans-ExtraBold.ttf", FontHacks_None);
@@ -162,13 +173,71 @@ namespace PortabilityLayer
RenderedFont *FontManagerImpl::GetRenderedFontFromFamily(FontFamily *fontFamily, int size, bool aa, int flags) RenderedFont *FontManagerImpl::GetRenderedFontFromFamily(FontFamily *fontFamily, int size, bool aa, int flags)
{ {
PortabilityLayer::FontManager *fm = PortabilityLayer::FontManager::GetInstance();
RenderedFont *rfont = fm->LoadCachedRenderedFont(fontFamily->GetCacheID(), size, aa, flags);
if (rfont)
return rfont;
const int variation = fontFamily->GetVariationForFlags(flags); const int variation = fontFamily->GetVariationForFlags(flags);
IGpFont *hostFont = fontFamily->GetFontForVariation(variation); IGpFont *hostFont = fontFamily->GetFontForVariation(variation);
if (!hostFont) if (!hostFont)
return nullptr; return nullptr;
return PortabilityLayer::FontManager::GetInstance()->GetRenderedFont(hostFont, size, aa, fontFamily->GetHacksForVariation(variation)); rfont = fm->GetRenderedFont(hostFont, size, aa, fontFamily->GetHacksForVariation(variation));
if (rfont)
fm->SaveCachedRenderedFont(rfont, fontFamily->GetCacheID(), size, aa, flags);
return rfont;
}
RenderedFont *FontManagerImpl::LoadCachedRenderedFont(int cacheID, int size, bool aa, int flags) const
{
char filename[kFontCacheNameSize];
GenerateCacheFileName(filename, cacheID, size, aa, flags);
GpIOStream *stream = PortabilityLayer::HostFileSystem::GetInstance()->OpenFile(PortabilityLayer::VirtualDirectories::kFontCache, filename, false, GpFileCreationDispositions::kOpenExisting);
if (!stream)
return nullptr;
BEUInt32_t version;
if (stream->Read(&version, sizeof(version)) != sizeof(version) || version != kFontCacheVersion)
{
stream->Close();
return nullptr;
}
RenderedFont *rfont = PortabilityLayer::FontRenderer::GetInstance()->LoadCache(stream);
stream->Close();
return rfont;
}
void FontManagerImpl::SaveCachedRenderedFont(const RenderedFont *rfont, int cacheID, int size, bool aa, int flags) const
{
char filename[kFontCacheNameSize];
GenerateCacheFileName(filename, cacheID, size, aa, flags);
GpIOStream *stream = PortabilityLayer::HostFileSystem::GetInstance()->OpenFile(PortabilityLayer::VirtualDirectories::kFontCache, filename, true, GpFileCreationDispositions::kCreateOrOverwrite);
if (!stream)
return;
BEUInt32_t zero32(0);
if (stream->Write(&zero32, sizeof(zero32)) != sizeof(zero32))
{
stream->Close();
return;
}
if (PortabilityLayer::FontRenderer::GetInstance()->SaveCache(rfont, stream))
{
BEUInt32_t version(kFontCacheVersion);
stream->SeekStart(0);
stream->Write(&version, sizeof(version));
}
stream->Close();
} }
FontManagerImpl *FontManagerImpl::GetInstance() FontManagerImpl *FontManagerImpl::GetInstance()
@@ -222,6 +291,11 @@ namespace PortabilityLayer
return 0; return 0;
} }
void FontManagerImpl::GenerateCacheFileName(char(&str)[kFontCacheNameSize], int cacheID, int size, bool aa, int flags)
{
sprintf(str, "rf_%i_%i_%s_%i.cache", cacheID, size, aa ? "aa" : "mc", flags);
}
FontManagerImpl FontManagerImpl::ms_instance; FontManagerImpl FontManagerImpl::ms_instance;
FontManager *FontManager::GetInstance() FontManager *FontManager::GetInstance()

View File

@@ -21,6 +21,9 @@ namespace PortabilityLayer
virtual RenderedFont *GetRenderedFont(IGpFont *font, int size, bool aa, FontHacks fontHacks) = 0; virtual RenderedFont *GetRenderedFont(IGpFont *font, int size, bool aa, FontHacks fontHacks) = 0;
virtual RenderedFont *GetRenderedFontFromFamily(FontFamily *fontFamily, int fontSize, bool aa, int flags) = 0; virtual RenderedFont *GetRenderedFontFromFamily(FontFamily *fontFamily, int fontSize, bool aa, int flags) = 0;
virtual RenderedFont *LoadCachedRenderedFont(int cacheID, int size, bool aa, int flags) const = 0;
virtual void SaveCachedRenderedFont(const RenderedFont *rfont, int cacheID, int size, bool aa, int flags) const = 0;
static FontManager *GetInstance(); static FontManager *GetInstance();
}; };
} }

View File

@@ -2,9 +2,11 @@
#include "CoreDefs.h" #include "CoreDefs.h"
#include "IGpFont.h" #include "IGpFont.h"
#include "GpIOStream.h"
#include "HostFontHandler.h" #include "HostFontHandler.h"
#include "IGpFontRenderedGlyph.h" #include "IGpFontRenderedGlyph.h"
#include "MacRomanConversion.h" #include "MacRomanConversion.h"
#include "PLBigEndian.h"
#include "PLPasStr.h" #include "PLPasStr.h"
#include "RenderedFont.h" #include "RenderedFont.h"
#include "GpRenderedFontMetrics.h" #include "GpRenderedFontMetrics.h"
@@ -30,12 +32,28 @@ namespace PortabilityLayer
void SetCharData(unsigned int charID, const void *data, size_t dataOffset, const GpRenderedGlyphMetrics &metrics); void SetCharData(unsigned int charID, const void *data, size_t dataOffset, const GpRenderedGlyphMetrics &metrics);
void SetFontMetrics(const GpRenderedFontMetrics &metrics); void SetFontMetrics(const GpRenderedFontMetrics &metrics);
static RenderedFont *Load(GpIOStream *stream);
bool Save(GpIOStream *stream) const;
static RenderedFontImpl *Create(size_t glyphDataSize, bool aa); static RenderedFontImpl *Create(size_t glyphDataSize, bool aa);
private: private:
RenderedFontImpl(void *data, bool aa); struct CacheHeader
{
BEUInt32_t m_cacheVersion;
BEUInt32_t m_glyphDataSize;
BEUInt32_t m_sizeSize;
BEUInt32_t m_isAA;
};
static const uint32_t kRFontCacheVersion = 2;
RenderedFontImpl(void *data, size_t dataSize, bool aa);
~RenderedFontImpl(); ~RenderedFontImpl();
bool LoadInternal(GpIOStream *stream);
size_t m_dataOffsets[256]; size_t m_dataOffsets[256];
GpRenderedGlyphMetrics m_glyphMetrics[256]; GpRenderedGlyphMetrics m_glyphMetrics[256];
@@ -43,12 +61,15 @@ namespace PortabilityLayer
bool m_isAntiAliased; bool m_isAntiAliased;
void *m_data; void *m_data;
size_t m_dataSize;
}; };
class FontRendererImpl final : public FontRenderer class FontRendererImpl final : public FontRenderer
{ {
public: public:
RenderedFont *RenderFont(IGpFont *font, int size, bool aa, FontHacks fontHacks) override; RenderedFont *RenderFont(IGpFont *font, int size, bool aa, FontHacks fontHacks) override;
RenderedFont *LoadCache(GpIOStream *stream) override;
bool SaveCache(const RenderedFont *rfont, GpIOStream *stream) override;
static FontRendererImpl *GetInstance(); static FontRendererImpl *GetInstance();
@@ -109,6 +130,57 @@ namespace PortabilityLayer
m_fontMetrics = metrics; m_fontMetrics = metrics;
} }
RenderedFont *RenderedFontImpl::Load(GpIOStream *stream)
{
CacheHeader header;
if (stream->Read(&header, sizeof(header)) != sizeof(header))
return nullptr;
if (header.m_cacheVersion != kRFontCacheVersion)
return nullptr;
if (header.m_sizeSize != sizeof(size_t))
return nullptr;
RenderedFontImpl *rfont = RenderedFontImpl::Create(header.m_glyphDataSize, header.m_isAA != 0);
if (!rfont)
return nullptr;
if (!rfont->LoadInternal(stream))
{
rfont->Destroy();
return nullptr;
}
return rfont;
}
bool RenderedFontImpl::Save(GpIOStream *stream) const
{
CacheHeader header;
header.m_cacheVersion = kRFontCacheVersion;
header.m_glyphDataSize = this->m_dataSize;
header.m_isAA = m_isAntiAliased;
header.m_sizeSize = sizeof(size_t);
if (stream->Write(&header, sizeof(header)) != sizeof(header))
return false;
if (stream->Write(m_data, m_dataSize) != m_dataSize)
return false;
if (stream->Write(m_dataOffsets, sizeof(m_dataOffsets)) != sizeof(m_dataOffsets))
return false;
if (stream->Write(m_glyphMetrics, sizeof(m_glyphMetrics)) != sizeof(m_glyphMetrics))
return false;
if (stream->Write(&m_fontMetrics, sizeof(m_fontMetrics)) != sizeof(m_fontMetrics))
return false;
return true;
}
RenderedFontImpl *RenderedFontImpl::Create(size_t glyphDataSize, bool aa) RenderedFontImpl *RenderedFontImpl::Create(size_t glyphDataSize, bool aa)
{ {
size_t alignedPrefixSize = sizeof(RenderedFontImpl) + GP_SYSTEM_MEMORY_ALIGNMENT - 1; size_t alignedPrefixSize = sizeof(RenderedFontImpl) + GP_SYSTEM_MEMORY_ALIGNMENT - 1;
@@ -125,11 +197,12 @@ namespace PortabilityLayer
memset(storage, 0, allocSize); memset(storage, 0, allocSize);
return new (storage) RenderedFontImpl(static_cast<uint8_t*>(storage) + alignedPrefixSize, aa); return new (storage) RenderedFontImpl(static_cast<uint8_t*>(storage) + alignedPrefixSize, glyphDataSize, aa);
} }
RenderedFontImpl::RenderedFontImpl(void *data, bool aa) RenderedFontImpl::RenderedFontImpl(void *data, size_t dataSize, bool aa)
: m_data(data) : m_data(data)
, m_dataSize(dataSize)
, m_isAntiAliased(aa) , m_isAntiAliased(aa)
{ {
memset(m_glyphMetrics, 0, sizeof(m_glyphMetrics)); memset(m_glyphMetrics, 0, sizeof(m_glyphMetrics));
@@ -141,6 +214,24 @@ namespace PortabilityLayer
{ {
} }
bool RenderedFontImpl::LoadInternal(GpIOStream *stream)
{
if (stream->Read(m_data, m_dataSize) != m_dataSize)
return false;
if (stream->Read(m_dataOffsets, sizeof(m_dataOffsets)) != sizeof(m_dataOffsets))
return false;
if (stream->Read(m_glyphMetrics, sizeof(m_glyphMetrics)) != sizeof(m_glyphMetrics))
return false;
if (stream->Read(&m_fontMetrics, sizeof(m_fontMetrics)) != sizeof(m_fontMetrics))
return false;
return true;
}
RenderedFont *FontRendererImpl::RenderFont(IGpFont *font, int size, bool aa, FontHacks fontHacks) RenderedFont *FontRendererImpl::RenderFont(IGpFont *font, int size, bool aa, FontHacks fontHacks)
{ {
const unsigned int numCharacters = 256; const unsigned int numCharacters = 256;
@@ -262,6 +353,19 @@ namespace PortabilityLayer
return rfont; return rfont;
} }
RenderedFont *FontRendererImpl::LoadCache(GpIOStream *stream)
{
return RenderedFontImpl::Load(stream);
}
bool FontRendererImpl::SaveCache(const RenderedFont *rfont, GpIOStream *stream)
{
if (!static_cast<const RenderedFontImpl*>(rfont)->Save(stream))
return false;
return true;
}
FontRendererImpl *FontRendererImpl::GetInstance() FontRendererImpl *FontRendererImpl::GetInstance()
{ {
return &ms_instance; return &ms_instance;

View File

@@ -3,6 +3,7 @@
#include "FontHacks.h" #include "FontHacks.h"
struct IGpFont; struct IGpFont;
class GpIOStream;
namespace PortabilityLayer namespace PortabilityLayer
{ {
@@ -12,6 +13,8 @@ namespace PortabilityLayer
{ {
public: public:
virtual RenderedFont *RenderFont(IGpFont *font, int size, bool aa, FontHacks fontHacks) = 0; virtual RenderedFont *RenderFont(IGpFont *font, int size, bool aa, FontHacks fontHacks) = 0;
virtual RenderedFont *LoadCache(GpIOStream *stream) = 0;
virtual bool SaveCache(const RenderedFont *rfont, GpIOStream *stream) = 0;
static FontRenderer *GetInstance(); static FontRenderer *GetInstance();
}; };

View File

@@ -17,6 +17,7 @@ namespace PortabilityLayer
kCursors, kCursors,
kHighScores, kHighScores,
kLogs, kLogs,
kFontCache,
kSourceExport, kSourceExport,
}; };