Add framebuffer lending for memory-intensive builds
Temporarily release framebuffer memory during section pagination to reduce heap pressure. The framebuffer can be released before memory-intensive operations and restored afterward, allowing BLE stack startup threshold to be lowered from 80KB to 70KB. Implements RAII-style FrameBufferBuildLoan class to ensure proper cleanup and automatic restart on restoration failure.
This commit is contained in:
@@ -62,7 +62,14 @@ void FontCacheManager::resetStats() {
|
||||
bool FontCacheManager::isScanning() const { return scanMode_ == ScanMode::Scanning; }
|
||||
|
||||
void FontCacheManager::recordText(const char* text, int fontId, EpdFontFamily::Style style) {
|
||||
scanText_ += text;
|
||||
if (!text) return;
|
||||
const size_t remaining = (scanTextLen_ < SCAN_TEXT_CAPACITY - 1) ? (SCAN_TEXT_CAPACITY - 1 - scanTextLen_) : 0;
|
||||
if (remaining > 0) {
|
||||
const size_t textLen = strnlen(text, remaining);
|
||||
memcpy(scanText_ + scanTextLen_, text, textLen);
|
||||
scanTextLen_ += textLen;
|
||||
scanText_[scanTextLen_] = '\0';
|
||||
}
|
||||
if (scanFontId_ < 0) scanFontId_ = fontId;
|
||||
const uint8_t baseStyle = static_cast<uint8_t>(style) & 0x03;
|
||||
const unsigned char* p = reinterpret_cast<const unsigned char*>(text);
|
||||
@@ -80,15 +87,15 @@ FontCacheManager::PrewarmScope::PrewarmScope(FontCacheManager& manager) : manage
|
||||
manager_->scanMode_ = ScanMode::Scanning;
|
||||
manager_->clearCache();
|
||||
manager_->resetStats();
|
||||
manager_->scanText_.clear();
|
||||
manager_->scanText_.reserve(2048); // Pre-allocate to avoid heap fragmentation from repeated concat
|
||||
manager_->scanTextLen_ = 0;
|
||||
manager_->scanText_[0] = '\0';
|
||||
memset(manager_->scanStyleCounts_, 0, sizeof(manager_->scanStyleCounts_));
|
||||
manager_->scanFontId_ = -1;
|
||||
}
|
||||
|
||||
void FontCacheManager::PrewarmScope::endScanAndPrewarm() {
|
||||
manager_->scanMode_ = ScanMode::None;
|
||||
if (manager_->scanText_.empty()) return;
|
||||
if (manager_->scanTextLen_ == 0) return;
|
||||
|
||||
// Build style bitmask from all styles that appeared during the scan
|
||||
uint8_t styleMask = 0;
|
||||
@@ -97,11 +104,10 @@ void FontCacheManager::PrewarmScope::endScanAndPrewarm() {
|
||||
}
|
||||
if (styleMask == 0) styleMask = 1; // default to regular
|
||||
|
||||
manager_->prewarmCache(manager_->scanFontId_, manager_->scanText_.c_str(), styleMask);
|
||||
manager_->prewarmCache(manager_->scanFontId_, manager_->scanText_, styleMask);
|
||||
|
||||
// Free scan string memory
|
||||
manager_->scanText_.clear();
|
||||
manager_->scanText_.shrink_to_fit();
|
||||
manager_->scanTextLen_ = 0;
|
||||
manager_->scanText_[0] = '\0';
|
||||
}
|
||||
|
||||
FontCacheManager::PrewarmScope::~PrewarmScope() {
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
#include <EpdFontFamily.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class FontDecompressor;
|
||||
class SdCardFont;
|
||||
@@ -51,7 +51,9 @@ class FontCacheManager {
|
||||
|
||||
enum class ScanMode : uint8_t { None, Scanning };
|
||||
ScanMode scanMode_ = ScanMode::None;
|
||||
std::string scanText_;
|
||||
static constexpr size_t SCAN_TEXT_CAPACITY = 2048;
|
||||
char scanText_[SCAN_TEXT_CAPACITY] = {};
|
||||
size_t scanTextLen_ = 0;
|
||||
uint32_t scanStyleCounts_[4] = {};
|
||||
int scanFontId_ = -1;
|
||||
};
|
||||
|
||||
@@ -91,6 +91,20 @@ void GfxRenderer::begin() {
|
||||
bwBufferChunks.assign((frameBufferSize + BW_BUFFER_CHUNK_SIZE - 1) / BW_BUFFER_CHUNK_SIZE, nullptr);
|
||||
}
|
||||
|
||||
void GfxRenderer::releaseFrameBufferForBuild() {
|
||||
display.releaseFrameBuffers();
|
||||
frameBuffer = nullptr;
|
||||
}
|
||||
|
||||
bool GfxRenderer::restoreFrameBufferAfterBuild() {
|
||||
if (!display.reallocFrameBuffers()) {
|
||||
LOG_ERR("GFX", "Framebuffer realloc failed after build");
|
||||
return false;
|
||||
}
|
||||
frameBuffer = display.getFrameBuffer();
|
||||
return frameBuffer != nullptr;
|
||||
}
|
||||
|
||||
bool GfxRenderer::isFontCacheScanning() const { return fontCacheManager_ && fontCacheManager_->isScanning(); }
|
||||
|
||||
void GfxRenderer::insertFont(const int fontId, EpdFontFamily font) {
|
||||
|
||||
@@ -250,6 +250,13 @@ class GfxRenderer {
|
||||
// Font helpers
|
||||
const uint8_t* getGlyphBitmap(const EpdFontData* fontData, const EpdGlyph* glyph) const;
|
||||
|
||||
// Lend the framebuffer to memory-hungry phases such as section pagination.
|
||||
// Nothing may draw/display while it is released. restore returns the buffer
|
||||
// white, so callers must redraw the full screen afterward.
|
||||
void releaseFrameBufferForBuild();
|
||||
bool restoreFrameBufferAfterBuild();
|
||||
bool hasFrameBuffer() const { return frameBuffer != nullptr; }
|
||||
|
||||
// Low level functions
|
||||
uint8_t* getFrameBuffer() const;
|
||||
size_t getBufferSize() const;
|
||||
|
||||
@@ -77,6 +77,10 @@ void HalDisplay::deepSleep() { einkDisplay.deepSleep(); }
|
||||
|
||||
uint8_t* HalDisplay::getFrameBuffer() const { return einkDisplay.getFrameBuffer(); }
|
||||
|
||||
void HalDisplay::releaseFrameBuffers() { einkDisplay.releaseBuffers(); }
|
||||
|
||||
bool HalDisplay::reallocFrameBuffers() { return einkDisplay.reallocBuffers(); }
|
||||
|
||||
void HalDisplay::copyGrayscaleBuffers(const uint8_t* lsbBuffer, const uint8_t* msbBuffer) {
|
||||
einkDisplay.copyGrayscaleBuffers(lsbBuffer, msbBuffer);
|
||||
}
|
||||
|
||||
@@ -47,6 +47,12 @@ class HalDisplay {
|
||||
// Access to frame buffer
|
||||
uint8_t* getFrameBuffer() const;
|
||||
|
||||
// Lend the framebuffer's RAM to a memory-hungry phase. No display calls may
|
||||
// run between release and a successful realloc; buffers come back white, so
|
||||
// callers must redraw the full screen.
|
||||
void releaseFrameBuffers();
|
||||
bool reallocFrameBuffers();
|
||||
|
||||
// X3 grayscale preconditioning (OEM "AA-pre-BW(mid)" settle pass), windowed
|
||||
// to the gray region in physical panel coordinates (no-arg = full frame).
|
||||
// Call after the BW base frame is displayed and before the grayscale planes
|
||||
|
||||
Reference in New Issue
Block a user