refactor: Memory optimization and XTC format removal

Memory optimization:
- Add LOG_STACK_WATERMARK macro for task stack monitoring
- Add freeCoverBufferIfAllocated() and preloadCoverBuffer() for memory management
- Improve cover buffer reuse to reduce heap fragmentation
- Add grayscale buffer cleanup safety in GfxRenderer
- Make grayscale rendering conditional on successful buffer allocation
- Add detailed heap fragmentation logging with ESP-IDF API
- Add CSS parser memory usage estimation

XTC format removal:
- Remove entire lib/Xtc library (XTC parser and types)
- Remove XtcReaderActivity and XtcReaderChapterSelectionActivity
- Remove XTC file handling from HomeActivity, SleepActivity, ReaderActivity
- Remove .xtc/.xtch from supported extensions in BookManager
- Remove XTC cache prefix from Md5Utils
- Update web server and file browser to exclude XTC format
- Clear in-memory caches when disk cache is cleared
This commit is contained in:
cottongin
2026-01-27 20:35:32 -05:00
parent 158caacfe0
commit c2a966a6ea
30 changed files with 201 additions and 2624 deletions

View File

@@ -190,6 +190,8 @@ void EpubReaderActivity::onExit() {
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
xSemaphoreTake(renderingMutex, portMAX_DELAY);
if (displayTaskHandle) {
// Log stack high-water mark before deleting task (stack size: 8192 bytes)
LOG_STACK_WATERMARK("EpubReaderActivity", displayTaskHandle);
vTaskDelete(displayTaskHandle);
displayTaskHandle = nullptr;
vTaskDelay(10 / portTICK_PERIOD_MS); // Let idle task free stack
@@ -639,30 +641,33 @@ void EpubReaderActivity::renderContents(std::unique_ptr<Page> page, const int or
pagesUntilFullRefresh--;
}
// Save bw buffer to reset buffer state after grayscale data sync
renderer.storeBwBuffer();
// grayscale rendering
// grayscale rendering requires storing the BW buffer first
// If we can't allocate memory for the backup, skip grayscale to avoid artifacts
// TODO: Only do this if font supports it
if (SETTINGS.textAntiAliasing) {
renderer.clearScreen(0x00);
renderer.setRenderMode(GfxRenderer::GRAYSCALE_LSB);
page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop);
renderer.copyGrayscaleLsbBuffers();
// Try to save BW buffer - if this fails, skip grayscale rendering entirely
const bool bwBufferStored = renderer.storeBwBuffer();
// Render and copy to MSB buffer
renderer.clearScreen(0x00);
renderer.setRenderMode(GfxRenderer::GRAYSCALE_MSB);
page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop);
renderer.copyGrayscaleMsbBuffers();
if (bwBufferStored) {
renderer.clearScreen(0x00);
renderer.setRenderMode(GfxRenderer::GRAYSCALE_LSB);
page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop);
renderer.copyGrayscaleLsbBuffers();
// display grayscale part
renderer.displayGrayBuffer();
renderer.setRenderMode(GfxRenderer::BW);
// Render and copy to MSB buffer
renderer.clearScreen(0x00);
renderer.setRenderMode(GfxRenderer::GRAYSCALE_MSB);
page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop);
renderer.copyGrayscaleMsbBuffers();
// display grayscale part
renderer.displayGrayBuffer();
renderer.setRenderMode(GfxRenderer::BW);
// restore the bw data
renderer.restoreBwBuffer();
}
}
// restore the bw data
renderer.restoreBwBuffer();
}
void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const int orientedMarginBottom,