Add minimal allback buffer for future use

This commit is contained in:
jpirnay
2026-05-04 16:44:28 +02:00
parent aeafe42348
commit 7a0dc31c2f
2 changed files with 51 additions and 5 deletions
+36 -2
View File
@@ -147,6 +147,19 @@ const uint8_t* FontDecompressor::getBitmap(const EpdFontData* fontData, const Ep
break; // Found the right slot but glyph wasn't in it; don't check other slots
}
// Check fallback LRU cache
for (uint8_t i = 0; i < FALLBACK_CACHE_SLOTS; i++) {
if (_fallbackCache[i].fontData == fontData && _fallbackCache[i].glyphIndex == glyphIndex) {
_fallbackCache[i].lastUsedTick = ++_fallbackTick;
stats.cacheHits++;
stats.fallbackCacheHits++;
stats.getBitmapTimeUs += micros() - tStart;
return _fallbackCache[i].buffer;
}
}
stats.fallbackCacheMisses++;
// Fallback: glyph wasn't in the page buffer — decompress its group transiently.
// This is the rare path (prewarm should cover all glyphs on a normal page).
uint16_t groupIndex = getGroupIndex(fontData, glyphIndex);
@@ -181,11 +194,25 @@ const uint8_t* FontDecompressor::getBitmap(const EpdFontData* fontData, const Ep
}
uint32_t alignedOff = getAlignedOffset(fontData, groupIndex, glyphIndex);
compactSingleGlyph(&groupBuf[alignedOff], _hotGlyphBuf, glyph->width, glyph->height);
uint8_t lruIndex = 0;
uint32_t oldestTick = UINT32_MAX;
for (uint8_t i = 0; i < FALLBACK_CACHE_SLOTS; i++) {
if (_fallbackCache[i].lastUsedTick < oldestTick) {
oldestTick = _fallbackCache[i].lastUsedTick;
lruIndex = i;
}
}
compactSingleGlyph(&groupBuf[alignedOff], _fallbackCache[lruIndex].buffer, glyph->width, glyph->height);
free(groupBuf);
_fallbackCache[lruIndex].fontData = fontData;
_fallbackCache[lruIndex].glyphIndex = glyphIndex;
_fallbackCache[lruIndex].lastUsedTick = ++_fallbackTick;
stats.getBitmapTimeUs += micros() - tStart;
return _hotGlyphBuf;
return _fallbackCache[lruIndex].buffer;
}
// --- Prewarm: pre-decompress glyph bitmaps for a page of text ---
@@ -537,5 +564,12 @@ void FontDecompressor::logStats(const char* label) {
LOG_DBG("FDC", "[%s] getBitmap: %lu calls, %luus total, %luus/call avg", label, stats.getBitmapCalls,
stats.getBitmapTimeUs, stats.getBitmapTimeUs / stats.getBitmapCalls);
}
uint32_t lruTotal = stats.fallbackCacheHits + stats.fallbackCacheMisses;
if (lruTotal > 0) {
LOG_DBG("FDC", "[%s] LRU Fallback: hits=%lu misses=%lu (%.1f%%)", label, stats.fallbackCacheHits,
stats.fallbackCacheMisses, 100.0f * stats.fallbackCacheHits / lruTotal);
}
resetStats();
}
+15 -3
View File
@@ -41,6 +41,10 @@ class FontDecompressor {
uint32_t peakTempBytes = 0; // largest temp buffer in prewarm or getBitmap miss
uint32_t getBitmapTimeUs = 0; // cumulative getBitmap time (micros)
uint32_t getBitmapCalls = 0; // number of getBitmap calls
// LRU specific stats
uint32_t fallbackCacheHits = 0;
uint32_t fallbackCacheMisses = 0;
};
void logStats(const char* label = "FDC");
void resetStats();
@@ -68,10 +72,18 @@ class FontDecompressor {
uint8_t pageSlotCount = 0;
static constexpr uint16_t HOT_GLYPH_BUF_SIZE = 512; // largest packed single glyph
static constexpr uint8_t FALLBACK_CACHE_SLOTS = 1;
// Scratch buffer for compacting a single glyph after a getBitmap() miss.
// Valid until the next getBitmap() call.
uint8_t _hotGlyphBuf[HOT_GLYPH_BUF_SIZE] = {};
struct FallbackSlot {
const EpdFontData* fontData;
uint32_t glyphIndex;
uint32_t lastUsedTick;
uint8_t buffer[HOT_GLYPH_BUF_SIZE];
};
// LRU cache for fallback glyph decompresion
FallbackSlot _fallbackCache[FALLBACK_CACHE_SLOTS] = {};
uint32_t _fallbackTick = 0;
void freePageBuffer();
uint16_t getGroupIndex(const EpdFontData* fontData, uint32_t glyphIndex);