Make chunk size variable depending on available heap size

This commit is contained in:
jpirnay
2026-04-17 16:34:33 +02:00
parent feda048dfa
commit e3145439fc
2 changed files with 51 additions and 24 deletions
+38 -12
View File
@@ -4,6 +4,7 @@
#include <HalGPIO.h> #include <HalGPIO.h>
#include <Logging.h> #include <Logging.h>
#include <Utf8.h> #include <Utf8.h>
#include <esp_heap_caps.h>
#include "FontCacheManager.h" #include "FontCacheManager.h"
@@ -33,7 +34,8 @@ void GfxRenderer::begin() {
panelHeight = display.getDisplayHeight(); panelHeight = display.getDisplayHeight();
panelWidthBytes = display.getDisplayWidthBytes(); panelWidthBytes = display.getDisplayWidthBytes();
frameBufferSize = display.getBufferSize(); frameBufferSize = display.getBufferSize();
bwBufferChunks.assign((frameBufferSize + BW_BUFFER_CHUNK_SIZE - 1) / BW_BUFFER_CHUNK_SIZE, nullptr); bwBufferChunkSize = BW_BUFFER_CHUNK_SIZE;
bwBufferChunks.assign((frameBufferSize + bwBufferChunkSize - 1) / bwBufferChunkSize, nullptr);
} }
void GfxRenderer::insertFont(const int fontId, EpdFontFamily font) { fontMap.insert({fontId, font}); } void GfxRenderer::insertFont(const int fontId, EpdFontFamily font) { fontMap.insert({fontId, font}); }
@@ -2037,32 +2039,56 @@ void GfxRenderer::freeBwBufferChunks() {
* Returns true if buffer was stored successfully, false if allocation failed. * Returns true if buffer was stored successfully, false if allocation failed.
*/ */
bool GfxRenderer::storeBwBuffer() { bool GfxRenderer::storeBwBuffer() {
// Allocate and copy each chunk auto attemptStore = [&](size_t chunkSize) {
bwBufferChunks.assign((frameBufferSize + chunkSize - 1) / chunkSize, nullptr);
for (size_t i = 0; i < bwBufferChunks.size(); i++) { for (size_t i = 0; i < bwBufferChunks.size(); i++) {
// Check if any chunks are already allocated
if (bwBufferChunks[i]) { if (bwBufferChunks[i]) {
LOG_ERR("GFX", "!! BW buffer chunk %zu already stored - this is likely a bug, freeing chunk", i); LOG_ERR("GFX", "!! BW buffer chunk %zu already stored - this is likely a bug, freeing chunk", i);
free(bwBufferChunks[i]); free(bwBufferChunks[i]);
bwBufferChunks[i] = nullptr; bwBufferChunks[i] = nullptr;
} }
const size_t offset = i * BW_BUFFER_CHUNK_SIZE; const size_t offset = i * chunkSize;
const size_t chunkSize = std::min(BW_BUFFER_CHUNK_SIZE, static_cast<size_t>(frameBufferSize - offset)); const size_t allocSize = std::min(chunkSize, static_cast<size_t>(frameBufferSize - offset));
bwBufferChunks[i] = static_cast<uint8_t*>(malloc(chunkSize)); bwBufferChunks[i] = static_cast<uint8_t*>(malloc(allocSize));
if (!bwBufferChunks[i]) { if (!bwBufferChunks[i]) {
LOG_ERR("GFX", "!! Failed to allocate BW buffer chunk %zu (%zu bytes)", i, chunkSize); const uint32_t freeHeap = esp_get_free_heap_size();
// Free previously allocated chunks const uint32_t contigHeap = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_DEFAULT);
LOG_ERR("GFX", "!! Failed to allocate BW buffer chunk %zu (%zu bytes): free=%u contig=%u", i, allocSize,
freeHeap, contigHeap);
freeBwBufferChunks(); freeBwBufferChunks();
return false; return false;
} }
memcpy(bwBufferChunks[i], frameBuffer + offset, chunkSize); memcpy(bwBufferChunks[i], frameBuffer + offset, allocSize);
}
bwBufferChunkSize = chunkSize;
LOG_DBG("GFX", "Stored BW buffer in %zu chunks (%zu bytes each)", bwBufferChunks.size(), chunkSize);
return true;
};
if (attemptStore(bwBufferChunkSize)) {
return true;
} }
LOG_DBG("GFX", "Stored BW buffer in %zu chunks (%zu bytes each)", bwBufferChunks.size(), BW_BUFFER_CHUNK_SIZE); if (bwBufferChunkSize > 4096) {
LOG_INF("GFX", "BW buffer allocation failed with chunk size %zu, retrying with 4096", bwBufferChunkSize);
if (attemptStore(4096)) {
return true; return true;
} }
}
if (bwBufferChunkSize > 2048) {
LOG_INF("GFX", "BW buffer allocation still failed, retrying with 2048");
if (attemptStore(2048)) {
return true;
}
}
LOG_ERR("GFX", "!! BW buffer storage failed after retrying smaller chunk sizes");
return false;
}
/** /**
* This can only be called if `storeBwBuffer` was called prior to the grayscale render. * This can only be called if `storeBwBuffer` was called prior to the grayscale render.
@@ -2090,8 +2116,8 @@ void GfxRenderer::restoreBwBuffer() {
} }
for (size_t i = 0; i < bwBufferChunks.size(); i++) { for (size_t i = 0; i < bwBufferChunks.size(); i++) {
const size_t offset = i * BW_BUFFER_CHUNK_SIZE; const size_t offset = i * bwBufferChunkSize;
const size_t chunkSize = std::min(BW_BUFFER_CHUNK_SIZE, static_cast<size_t>(frameBufferSize - offset)); const size_t chunkSize = std::min(bwBufferChunkSize, static_cast<size_t>(frameBufferSize - offset));
memcpy(frameBuffer + offset, bwBufferChunks[i], chunkSize); memcpy(frameBuffer + offset, bwBufferChunks[i], chunkSize);
} }
+1
View File
@@ -54,6 +54,7 @@ class GfxRenderer {
uint16_t panelHeight = 0; // set in begin() uint16_t panelHeight = 0; // set in begin()
uint16_t panelWidthBytes = 0; // set in begin() uint16_t panelWidthBytes = 0; // set in begin()
uint32_t frameBufferSize = 0; // set in begin() uint32_t frameBufferSize = 0; // set in begin()
size_t bwBufferChunkSize = BW_BUFFER_CHUNK_SIZE;
std::vector<uint8_t*> bwBufferChunks; std::vector<uint8_t*> bwBufferChunks;
std::map<int, EpdFontFamily> fontMap; std::map<int, EpdFontFamily> fontMap;