mirror of
https://github.com/elasota/Aerofoil.git
synced 2025-09-23 06:53:43 +00:00
Cache rendered fonts to speed up mobile load
This commit is contained in:
@@ -123,18 +123,21 @@ GpFileSystem_Win32::GpFileSystem_Win32()
|
||||
m_userSavesDir = m_prefsDir + L"\\SavedGames";
|
||||
m_scoresDir = m_prefsDir + L"\\Scores";
|
||||
m_logsDir = m_prefsDir + L"\\Logs";
|
||||
m_fontCacheDir = m_prefsDir + L"\\FontCache";
|
||||
|
||||
CreateDirectoryW(m_prefsDir.c_str(), nullptr);
|
||||
CreateDirectoryW(m_scoresDir.c_str(), nullptr);
|
||||
CreateDirectoryW(m_userHousesDir.c_str(), nullptr);
|
||||
CreateDirectoryW(m_userSavesDir.c_str(), nullptr);
|
||||
CreateDirectoryW(m_logsDir.c_str(), nullptr);
|
||||
CreateDirectoryW(m_fontCacheDir.c_str(), nullptr);
|
||||
|
||||
m_prefsDir.append(L"\\");
|
||||
m_scoresDir.append(L"\\");
|
||||
m_userHousesDir.append(L"\\");
|
||||
m_userSavesDir.append(L"\\");
|
||||
m_logsDir.append(L"\\");
|
||||
m_fontCacheDir.append(L"\\");
|
||||
}
|
||||
|
||||
DWORD modulePathSize = GetModuleFileNameW(nullptr, m_executablePath, MAX_PATH);
|
||||
@@ -462,6 +465,9 @@ bool GpFileSystem_Win32::ResolvePath(PortabilityLayer::VirtualDirectory_t virtua
|
||||
case PortabilityLayer::VirtualDirectories::kLogs:
|
||||
baseDir = m_logsDir.c_str();
|
||||
break;
|
||||
case PortabilityLayer::VirtualDirectories::kFontCache:
|
||||
baseDir = m_fontCacheDir.c_str();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@@ -41,6 +41,7 @@ private:
|
||||
std::wstring m_userHousesDir;
|
||||
std::wstring m_userSavesDir;
|
||||
std::wstring m_resourcesDir;
|
||||
std::wstring m_fontCacheDir;
|
||||
wchar_t m_executablePath[MAX_PATH];
|
||||
|
||||
static GpFileSystem_Win32 ms_instance;
|
||||
|
@@ -441,6 +441,9 @@ bool GpFileSystem_Android::ResolvePath(PortabilityLayer::VirtualDirectory_t virt
|
||||
case PortabilityLayer::VirtualDirectories::kPrefs:
|
||||
prefsAppend = "Prefs";
|
||||
break;
|
||||
case PortabilityLayer::VirtualDirectories::kFontCache:
|
||||
prefsAppend = "FontCache";
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
@@ -509,7 +512,7 @@ void GpFileSystem_Android::InitJNI()
|
||||
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++)
|
||||
{
|
||||
std::string prefsPath = std::string(prefsDir) + extensions[i];
|
||||
|
@@ -60,13 +60,18 @@ namespace PortabilityLayer
|
||||
return m_hacks[variation];
|
||||
}
|
||||
|
||||
FontFamily *FontFamily::Create()
|
||||
int FontFamily::GetCacheID() const
|
||||
{
|
||||
return m_cacheID;
|
||||
}
|
||||
|
||||
FontFamily *FontFamily::Create(int cacheID)
|
||||
{
|
||||
void *storage = malloc(sizeof(FontFamily));
|
||||
if (!storage)
|
||||
return nullptr;
|
||||
|
||||
return new (storage) FontFamily();
|
||||
return new (storage) FontFamily(cacheID);
|
||||
}
|
||||
|
||||
void FontFamily::Destroy()
|
||||
@@ -75,8 +80,9 @@ namespace PortabilityLayer
|
||||
free(this);
|
||||
}
|
||||
|
||||
FontFamily::FontFamily()
|
||||
FontFamily::FontFamily(int cacheID)
|
||||
: m_defaultVariation(0)
|
||||
, m_cacheID(cacheID)
|
||||
{
|
||||
for (unsigned int i = 0; i < kNumVariations; i++)
|
||||
{
|
||||
|
@@ -29,15 +29,18 @@ namespace PortabilityLayer
|
||||
IGpFont *GetFontForVariation(int variation) const;
|
||||
FontHacks GetHacksForVariation(int variation) const;
|
||||
|
||||
static FontFamily *Create();
|
||||
int GetCacheID() const;
|
||||
|
||||
static FontFamily *Create(int cacheID);
|
||||
void Destroy();
|
||||
|
||||
private:
|
||||
FontHacks m_hacks[kNumVariations];
|
||||
IGpFont *m_fonts[kNumVariations];
|
||||
uint8_t m_defaultVariation;
|
||||
int m_cacheID;
|
||||
|
||||
FontFamily();
|
||||
explicit FontFamily(int cacheID);
|
||||
~FontFamily();
|
||||
};
|
||||
}
|
||||
|
@@ -7,7 +7,9 @@
|
||||
#include "HostFontHandler.h"
|
||||
#include "GpIOStream.h"
|
||||
#include "RenderedFont.h"
|
||||
#include "PLBigEndian.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -27,10 +29,17 @@ namespace PortabilityLayer
|
||||
RenderedFont *GetRenderedFont(IGpFont *font, int size, bool aa, FontHacks fontHacks) 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();
|
||||
|
||||
private:
|
||||
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
|
||||
{
|
||||
@@ -46,6 +55,8 @@ namespace PortabilityLayer
|
||||
void ResetUsageCounter();
|
||||
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_applicationFont;
|
||||
uint32_t m_usageCounter;
|
||||
@@ -57,8 +68,8 @@ namespace PortabilityLayer
|
||||
|
||||
void FontManagerImpl::Init()
|
||||
{
|
||||
m_systemFont = FontFamily::Create();
|
||||
m_applicationFont = FontFamily::Create();
|
||||
m_systemFont = FontFamily::Create(kSystemFontCacheID);
|
||||
m_applicationFont = FontFamily::Create(kApplicationFontCacheID);
|
||||
|
||||
if (m_systemFont)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
IGpFont *hostFont = fontFamily->GetFontForVariation(variation);
|
||||
if (!hostFont)
|
||||
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()
|
||||
@@ -222,6 +291,11 @@ namespace PortabilityLayer
|
||||
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;
|
||||
|
||||
FontManager *FontManager::GetInstance()
|
||||
|
@@ -21,6 +21,9 @@ namespace PortabilityLayer
|
||||
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 *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();
|
||||
};
|
||||
}
|
||||
|
@@ -2,9 +2,11 @@
|
||||
|
||||
#include "CoreDefs.h"
|
||||
#include "IGpFont.h"
|
||||
#include "GpIOStream.h"
|
||||
#include "HostFontHandler.h"
|
||||
#include "IGpFontRenderedGlyph.h"
|
||||
#include "MacRomanConversion.h"
|
||||
#include "PLBigEndian.h"
|
||||
#include "PLPasStr.h"
|
||||
#include "RenderedFont.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 SetFontMetrics(const GpRenderedFontMetrics &metrics);
|
||||
|
||||
static RenderedFont *Load(GpIOStream *stream);
|
||||
bool Save(GpIOStream *stream) const;
|
||||
|
||||
static RenderedFontImpl *Create(size_t glyphDataSize, bool aa);
|
||||
|
||||
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();
|
||||
|
||||
bool LoadInternal(GpIOStream *stream);
|
||||
|
||||
size_t m_dataOffsets[256];
|
||||
GpRenderedGlyphMetrics m_glyphMetrics[256];
|
||||
|
||||
@@ -43,12 +61,15 @@ namespace PortabilityLayer
|
||||
bool m_isAntiAliased;
|
||||
|
||||
void *m_data;
|
||||
size_t m_dataSize;
|
||||
};
|
||||
|
||||
class FontRendererImpl final : public FontRenderer
|
||||
{
|
||||
public:
|
||||
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();
|
||||
|
||||
@@ -109,6 +130,57 @@ namespace PortabilityLayer
|
||||
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)
|
||||
{
|
||||
size_t alignedPrefixSize = sizeof(RenderedFontImpl) + GP_SYSTEM_MEMORY_ALIGNMENT - 1;
|
||||
@@ -125,11 +197,12 @@ namespace PortabilityLayer
|
||||
|
||||
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_dataSize(dataSize)
|
||||
, m_isAntiAliased(aa)
|
||||
{
|
||||
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)
|
||||
{
|
||||
const unsigned int numCharacters = 256;
|
||||
@@ -262,6 +353,19 @@ namespace PortabilityLayer
|
||||
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()
|
||||
{
|
||||
return &ms_instance;
|
||||
|
@@ -3,6 +3,7 @@
|
||||
#include "FontHacks.h"
|
||||
|
||||
struct IGpFont;
|
||||
class GpIOStream;
|
||||
|
||||
namespace PortabilityLayer
|
||||
{
|
||||
@@ -12,6 +13,8 @@ namespace PortabilityLayer
|
||||
{
|
||||
public:
|
||||
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();
|
||||
};
|
||||
|
@@ -17,6 +17,7 @@ namespace PortabilityLayer
|
||||
kCursors,
|
||||
kHighScores,
|
||||
kLogs,
|
||||
kFontCache,
|
||||
|
||||
kSourceExport,
|
||||
};
|
||||
|
Reference in New Issue
Block a user