Add minimal allback buffer for future use
This commit is contained in:
@@ -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
|
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.
|
// 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).
|
// This is the rare path (prewarm should cover all glyphs on a normal page).
|
||||||
uint16_t groupIndex = getGroupIndex(fontData, glyphIndex);
|
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);
|
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);
|
free(groupBuf);
|
||||||
|
|
||||||
|
_fallbackCache[lruIndex].fontData = fontData;
|
||||||
|
_fallbackCache[lruIndex].glyphIndex = glyphIndex;
|
||||||
|
_fallbackCache[lruIndex].lastUsedTick = ++_fallbackTick;
|
||||||
|
|
||||||
stats.getBitmapTimeUs += micros() - tStart;
|
stats.getBitmapTimeUs += micros() - tStart;
|
||||||
return _hotGlyphBuf;
|
return _fallbackCache[lruIndex].buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Prewarm: pre-decompress glyph bitmaps for a page of text ---
|
// --- 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,
|
LOG_DBG("FDC", "[%s] getBitmap: %lu calls, %luus total, %luus/call avg", label, stats.getBitmapCalls,
|
||||||
stats.getBitmapTimeUs, stats.getBitmapTimeUs / 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();
|
resetStats();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ class FontDecompressor {
|
|||||||
uint32_t peakTempBytes = 0; // largest temp buffer in prewarm or getBitmap miss
|
uint32_t peakTempBytes = 0; // largest temp buffer in prewarm or getBitmap miss
|
||||||
uint32_t getBitmapTimeUs = 0; // cumulative getBitmap time (micros)
|
uint32_t getBitmapTimeUs = 0; // cumulative getBitmap time (micros)
|
||||||
uint32_t getBitmapCalls = 0; // number of getBitmap calls
|
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 logStats(const char* label = "FDC");
|
||||||
void resetStats();
|
void resetStats();
|
||||||
@@ -68,10 +72,18 @@ class FontDecompressor {
|
|||||||
uint8_t pageSlotCount = 0;
|
uint8_t pageSlotCount = 0;
|
||||||
|
|
||||||
static constexpr uint16_t HOT_GLYPH_BUF_SIZE = 512; // largest packed single glyph
|
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.
|
struct FallbackSlot {
|
||||||
// Valid until the next getBitmap() call.
|
const EpdFontData* fontData;
|
||||||
uint8_t _hotGlyphBuf[HOT_GLYPH_BUF_SIZE] = {};
|
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();
|
void freePageBuffer();
|
||||||
uint16_t getGroupIndex(const EpdFontData* fontData, uint32_t glyphIndex);
|
uint16_t getGroupIndex(const EpdFontData* fontData, uint32_t glyphIndex);
|
||||||
|
|||||||
Reference in New Issue
Block a user