Codechange: Use std::unordered_map for storing TrueTypeFontCache's GlyphEntry.

This commit is contained in:
Peter Nelson 2024-05-12 15:03:03 +01:00 committed by Peter Nelson
parent 7b717fcccb
commit 48539992e8
7 changed files with 48 additions and 69 deletions

View File

@ -273,14 +273,14 @@ const Sprite *FreeTypeFontCache::InternalGetGlyph(GlyphID key, bool aa)
}
}
UniquePtrSpriteAllocator allocator;
BlitterFactory::GetCurrentBlitter()->Encode(spritecollection, allocator);
GlyphEntry new_glyph;
SimpleSpriteAllocator allocator;
new_glyph.sprite = BlitterFactory::GetCurrentBlitter()->Encode(spritecollection, allocator);
new_glyph.width = slot->advance.x >> 6;
new_glyph.data = std::move(allocator.data);
new_glyph.width = slot->advance.x >> 6;
this->SetGlyphPtr(key, &new_glyph);
return new_glyph.sprite;
return this->SetGlyphPtr(key, std::move(new_glyph)).GetSprite();
}

View File

@ -21,7 +21,7 @@
* @param fs The font size that is going to be cached.
* @param pixels The number of pixels this font should be high.
*/
TrueTypeFontCache::TrueTypeFontCache(FontSize fs, int pixels) : FontCache(fs), req_size(pixels), glyph_to_sprite(nullptr)
TrueTypeFontCache::TrueTypeFontCache(FontSize fs, int pixels) : FontCache(fs), req_size(pixels)
{
}
@ -39,47 +39,22 @@ TrueTypeFontCache::~TrueTypeFontCache()
*/
void TrueTypeFontCache::ClearFontCache()
{
if (this->glyph_to_sprite == nullptr) return;
for (int i = 0; i < 256; i++) {
if (this->glyph_to_sprite[i] == nullptr) continue;
for (int j = 0; j < 256; j++) {
free(this->glyph_to_sprite[i][j].sprite);
}
free(this->glyph_to_sprite[i]);
}
free(this->glyph_to_sprite);
this->glyph_to_sprite = nullptr;
this->glyph_to_sprite_map.clear();
Layouter::ResetFontCache(this->fs);
}
TrueTypeFontCache::GlyphEntry *TrueTypeFontCache::GetGlyphPtr(GlyphID key)
{
if (this->glyph_to_sprite == nullptr) return nullptr;
if (this->glyph_to_sprite[GB(key, 8, 8)] == nullptr) return nullptr;
return &this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)];
auto found = this->glyph_to_sprite_map.find(key);
if (found == std::end(this->glyph_to_sprite_map)) return nullptr;
return &found->second;
}
void TrueTypeFontCache::SetGlyphPtr(GlyphID key, const GlyphEntry *glyph)
TrueTypeFontCache::GlyphEntry &TrueTypeFontCache::SetGlyphPtr(GlyphID key, GlyphEntry &&glyph)
{
if (this->glyph_to_sprite == nullptr) {
Debug(fontcache, 3, "Allocating root glyph cache for size {}", this->fs);
this->glyph_to_sprite = CallocT<GlyphEntry*>(256);
}
if (this->glyph_to_sprite[GB(key, 8, 8)] == nullptr) {
Debug(fontcache, 3, "Allocating glyph cache for range 0x{:02X}00, size {}", GB(key, 8, 8), this->fs);
this->glyph_to_sprite[GB(key, 8, 8)] = CallocT<GlyphEntry>(256);
}
Debug(fontcache, 4, "Set glyph for unicode character 0x{:04X}, size {}", key, this->fs);
this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].sprite = glyph->sprite;
this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].width = glyph->width;
this->glyph_to_sprite_map[key] = std::move(glyph);
return this->glyph_to_sprite_map[key];
}
bool TrueTypeFontCache::GetDrawGlyphShadow()
@ -92,7 +67,7 @@ uint TrueTypeFontCache::GetGlyphWidth(GlyphID key)
if ((key & SPRITE_GLYPH) != 0) return this->parent->GetGlyphWidth(key);
GlyphEntry *glyph = this->GetGlyphPtr(key);
if (glyph == nullptr || glyph->sprite == nullptr) {
if (glyph == nullptr || glyph->data == nullptr) {
this->GetGlyph(key);
glyph = this->GetGlyphPtr(key);
}
@ -106,7 +81,7 @@ const Sprite *TrueTypeFontCache::GetGlyph(GlyphID key)
/* Check for the glyph in our cache */
GlyphEntry *glyph = this->GetGlyphPtr(key);
if (glyph != nullptr && glyph->sprite != nullptr) return glyph->sprite;
if (glyph != nullptr && glyph->data != nullptr) return glyph->GetSprite();
return this->InternalGetGlyph(key, GetFontAAState());
}

View File

@ -29,27 +29,16 @@ protected:
/** Container for information about a glyph. */
struct GlyphEntry {
Sprite *sprite; ///< The loaded sprite.
uint8_t width; ///< The width of the glyph.
std::unique_ptr<uint8_t[]> data; ///< The loaded sprite.
uint8_t width = 0; ///< The width of the glyph.
Sprite *GetSprite() { return reinterpret_cast<Sprite *>(data.get()); }
};
/**
* The glyph cache. This is structured to reduce memory consumption.
* 1) There is a 'segment' table for each font size.
* 2) Each segment table is a discrete block of characters.
* 3) Each block contains 256 (aligned) characters sequential characters.
*
* The cache is accessed in the following way:
* For character 0x0041 ('A'): glyph_to_sprite[0x00][0x41]
* For character 0x20AC (Euro): glyph_to_sprite[0x20][0xAC]
*
* Currently only 256 segments are allocated, "limiting" us to 65536 characters.
* This can be simply changed in the two functions Get & SetGlyphPtr.
*/
GlyphEntry **glyph_to_sprite;
std::unordered_map<GlyphID, GlyphEntry> glyph_to_sprite_map{};
GlyphEntry *GetGlyphPtr(GlyphID key);
void SetGlyphPtr(GlyphID key, const GlyphEntry *glyph);
GlyphEntry &SetGlyphPtr(GlyphID key, GlyphEntry &&glyph);
virtual const Sprite *InternalGetGlyph(GlyphID key, bool aa) = 0;

View File

@ -276,13 +276,14 @@ const Sprite *CoreTextFontCache::InternalGetGlyph(GlyphID key, bool use_aa)
}
}
GlyphEntry new_glyph;
SimpleSpriteAllocator allocator;
new_glyph.sprite = BlitterFactory::GetCurrentBlitter()->Encode(spritecollection, allocator);
new_glyph.width = (uint8_t)std::round(CTFontGetAdvancesForGlyphs(this->font.get(), kCTFontOrientationDefault, &glyph, nullptr, 1));
this->SetGlyphPtr(key, &new_glyph);
UniquePtrSpriteAllocator allocator;
BlitterFactory::GetCurrentBlitter()->Encode(spritecollection, allocator);
return new_glyph.sprite;
GlyphEntry new_glyph;
new_glyph.data = std::move(allocator.data);
new_glyph.width = (uint8_t)std::round(CTFontGetAdvancesForGlyphs(this->font.get(), kCTFontOrientationDefault, &glyph, nullptr, 1));
return this->SetGlyphPtr(key, std::move(new_glyph)).GetSprite();
}
static CTFontDescriptorRef LoadFontFromFile(const std::string &font_name)

View File

@ -252,14 +252,14 @@ void Win32FontCache::ClearFontCache()
}
}
UniquePtrSpriteAllocator allocator;
BlitterFactory::GetCurrentBlitter()->Encode(spritecollection, allocator);
GlyphEntry new_glyph;
SimpleSpriteAllocator allocator;
new_glyph.sprite = BlitterFactory::GetCurrentBlitter()->Encode(spritecollection, allocator);
new_glyph.data = std::move(allocator.data);
new_glyph.width = gm.gmCellIncX;
this->SetGlyphPtr(key, &new_glyph);
return new_glyph.sprite;
return this->SetGlyphPtr(key, std::move(new_glyph)).GetSprite();
}
/* virtual */ GlyphID Win32FontCache::MapCharToGlyph(char32_t key, bool allow_fallback)

View File

@ -894,6 +894,12 @@ void *SimpleSpriteAllocator::AllocatePtr(size_t size)
return MallocT<uint8_t>(size);
}
void *UniquePtrSpriteAllocator::AllocatePtr(size_t size)
{
this->data = std::make_unique<uint8_t[]>(size);
return this->data.get();
}
/**
* Handles the case when a sprite of different type is requested than is present in the SpriteCache.
* For SpriteType::Font sprites, it is normal. In other cases, default sprite is loaded instead.

View File

@ -37,6 +37,14 @@ protected:
void *AllocatePtr(size_t size) override;
};
/** SpriteAllocator that allocates memory via a unique_ptr array. */
class UniquePtrSpriteAllocator : public SpriteAllocator {
public:
std::unique_ptr<uint8_t[]> data;
protected:
void *AllocatePtr(size_t size) override;
};
void *GetRawSprite(SpriteID sprite, SpriteType type, SpriteAllocator *allocator = nullptr, SpriteEncoder *encoder = nullptr);
bool SpriteExists(SpriteID sprite);