shrink HomeActivity cover cache from 48KB framebuffer to 16KB region (#2035)
This commit is contained in:
@@ -2020,6 +2020,69 @@ int GfxRenderer::getScreenHeight() const {
|
|||||||
return panelWidth;
|
return panelWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool logicalRectToPhysicalBounds(GfxRenderer::Orientation orientation, int lx, int ly, int lw, int lh,
|
||||||
|
uint16_t panelWidth, uint16_t panelHeight, int* outX0, int* outY0, int* outX1,
|
||||||
|
int* outY1) {
|
||||||
|
if (lw <= 0 || lh <= 0) return false;
|
||||||
|
int minX = INT32_MAX, minY = INT32_MAX, maxX = INT32_MIN, maxY = INT32_MIN;
|
||||||
|
const int corners[4][2] = {{lx, ly}, {lx + lw - 1, ly}, {lx, ly + lh - 1}, {lx + lw - 1, ly + lh - 1}};
|
||||||
|
for (auto& c : corners) {
|
||||||
|
int phyX, phyY;
|
||||||
|
rotateCoordinates(orientation, c[0], c[1], &phyX, &phyY, panelWidth, panelHeight);
|
||||||
|
if (phyX < minX) minX = phyX;
|
||||||
|
if (phyY < minY) minY = phyY;
|
||||||
|
if (phyX > maxX) maxX = phyX;
|
||||||
|
if (phyY > maxY) maxY = phyY;
|
||||||
|
}
|
||||||
|
if (minX < 0) minX = 0;
|
||||||
|
if (minY < 0) minY = 0;
|
||||||
|
if (maxX >= panelWidth) maxX = panelWidth - 1;
|
||||||
|
if (maxY >= panelHeight) maxY = panelHeight - 1;
|
||||||
|
if (minX > maxX || minY > maxY) return false;
|
||||||
|
*outX0 = minX;
|
||||||
|
*outY0 = minY;
|
||||||
|
*outX1 = maxX;
|
||||||
|
*outY1 = maxY;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GfxRenderer::getRegionByteSize(int lx, int ly, int lw, int lh) const {
|
||||||
|
int x0, y0, x1, y1;
|
||||||
|
if (!logicalRectToPhysicalBounds(getOrientation(), lx, ly, lw, lh, panelWidth, panelHeight, &x0, &y0, &x1, &y1))
|
||||||
|
return 0;
|
||||||
|
const int byteX0 = x0 / 8;
|
||||||
|
const int byteX1 = x1 / 8;
|
||||||
|
return static_cast<size_t>(byteX1 - byteX0 + 1) * static_cast<size_t>(y1 - y0 + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GfxRenderer::copyRegionToBuffer(int lx, int ly, int lw, int lh, uint8_t* buf, size_t bufSize) const {
|
||||||
|
int x0, y0, x1, y1;
|
||||||
|
if (!logicalRectToPhysicalBounds(getOrientation(), lx, ly, lw, lh, panelWidth, panelHeight, &x0, &y0, &x1, &y1))
|
||||||
|
return false;
|
||||||
|
const int byteX0 = x0 / 8;
|
||||||
|
const int bytesPerRow = x1 / 8 - byteX0 + 1;
|
||||||
|
const int rowCount = y1 - y0 + 1;
|
||||||
|
const size_t needed = static_cast<size_t>(bytesPerRow) * static_cast<size_t>(rowCount);
|
||||||
|
if (bufSize < needed || !frameBuffer || !buf) return false;
|
||||||
|
for (int row = 0; row < rowCount; row++)
|
||||||
|
memcpy(buf + row * bytesPerRow, frameBuffer + (y0 + row) * panelWidthBytes + byteX0, bytesPerRow);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GfxRenderer::copyBufferToRegion(int lx, int ly, int lw, int lh, const uint8_t* buf, size_t bufSize) const {
|
||||||
|
int x0, y0, x1, y1;
|
||||||
|
if (!logicalRectToPhysicalBounds(getOrientation(), lx, ly, lw, lh, panelWidth, panelHeight, &x0, &y0, &x1, &y1))
|
||||||
|
return false;
|
||||||
|
const int byteX0 = x0 / 8;
|
||||||
|
const int bytesPerRow = x1 / 8 - byteX0 + 1;
|
||||||
|
const int rowCount = y1 - y0 + 1;
|
||||||
|
const size_t needed = static_cast<size_t>(bytesPerRow) * static_cast<size_t>(rowCount);
|
||||||
|
if (bufSize < needed || !frameBuffer || !buf) return false;
|
||||||
|
for (int row = 0; row < rowCount; row++)
|
||||||
|
memcpy(frameBuffer + (y0 + row) * panelWidthBytes + byteX0, buf + row * bytesPerRow, bytesPerRow);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int GfxRenderer::getSpaceWidth(const int fontId, const EpdFontFamily::Style style) const {
|
int GfxRenderer::getSpaceWidth(const int fontId, const EpdFontFamily::Style style) const {
|
||||||
const auto fontIt = fontMap.find(fontId);
|
const auto fontIt = fontMap.find(fontId);
|
||||||
if (fontIt == fontMap.end()) {
|
if (fontIt == fontMap.end()) {
|
||||||
|
|||||||
@@ -223,4 +223,12 @@ class GfxRenderer {
|
|||||||
uint16_t getDisplayWidth() const { return panelWidth; }
|
uint16_t getDisplayWidth() const { return panelWidth; }
|
||||||
uint16_t getDisplayHeight() const { return panelHeight; }
|
uint16_t getDisplayHeight() const { return panelHeight; }
|
||||||
uint16_t getDisplayWidthBytes() const { return panelWidthBytes; }
|
uint16_t getDisplayWidthBytes() const { return panelWidthBytes; }
|
||||||
|
|
||||||
|
// Region cache helpers: operate on a logical (orientation-aware) rect and
|
||||||
|
// copy only the framebuffer bytes it touches. Used by HomeActivity to snapshot
|
||||||
|
// the cover tile (~16 KB) instead of the full 48 KB framebuffer.
|
||||||
|
size_t getRegionByteSize(int logicalX, int logicalY, int logicalW, int logicalH) const;
|
||||||
|
bool copyRegionToBuffer(int logicalX, int logicalY, int logicalW, int logicalH, uint8_t* buf, size_t bufSize) const;
|
||||||
|
bool copyBufferToRegion(int logicalX, int logicalY, int logicalW, int logicalH, const uint8_t* buf,
|
||||||
|
size_t bufSize) const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -384,37 +384,28 @@ void HomeActivity::onExit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool HomeActivity::storeCoverBuffer() {
|
bool HomeActivity::storeCoverBuffer() {
|
||||||
uint8_t* frameBuffer = renderer.getFrameBuffer();
|
if (coverRectW <= 0 || coverRectH <= 0) return false;
|
||||||
if (!frameBuffer) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free any existing buffer first
|
|
||||||
freeCoverBuffer();
|
freeCoverBuffer();
|
||||||
|
const size_t needed = renderer.getRegionByteSize(coverRectX, coverRectY, coverRectW, coverRectH);
|
||||||
const size_t bufferSize = renderer.getBufferSize();
|
if (needed == 0) return false;
|
||||||
coverBuffer = static_cast<uint8_t*>(malloc(bufferSize));
|
coverBuffer = static_cast<uint8_t*>(malloc(needed));
|
||||||
if (!coverBuffer) {
|
if (!coverBuffer) {
|
||||||
|
LOG_ERR("HOME", "OOM: cover buffer (%u bytes)", (unsigned)needed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
coverBufferSize = needed;
|
||||||
|
if (!renderer.copyRegionToBuffer(coverRectX, coverRectY, coverRectW, coverRectH, coverBuffer, coverBufferSize)) {
|
||||||
|
free(coverBuffer);
|
||||||
|
coverBuffer = nullptr;
|
||||||
|
coverBufferSize = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(coverBuffer, frameBuffer, bufferSize);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HomeActivity::restoreCoverBuffer() {
|
bool HomeActivity::restoreCoverBuffer() {
|
||||||
if (!coverBuffer) {
|
if (!coverBuffer || coverRectW <= 0 || coverRectH <= 0) return false;
|
||||||
return false;
|
return renderer.copyBufferToRegion(coverRectX, coverRectY, coverRectW, coverRectH, coverBuffer, coverBufferSize);
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t* frameBuffer = renderer.getFrameBuffer();
|
|
||||||
if (!frameBuffer) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t bufferSize = renderer.getBufferSize();
|
|
||||||
memcpy(frameBuffer, coverBuffer, bufferSize);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HomeActivity::freeCoverBuffer() {
|
void HomeActivity::freeCoverBuffer() {
|
||||||
@@ -422,6 +413,7 @@ void HomeActivity::freeCoverBuffer() {
|
|||||||
free(coverBuffer);
|
free(coverBuffer);
|
||||||
coverBuffer = nullptr;
|
coverBuffer = nullptr;
|
||||||
}
|
}
|
||||||
|
coverBufferSize = 0;
|
||||||
coverBufferStored = false;
|
coverBufferStored = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -549,6 +541,11 @@ void HomeActivity::render(RenderLock&&) {
|
|||||||
|
|
||||||
const HomeScreenLayout layout = computeHomeScreenLayout(metrics, contentRect.height, menuCount);
|
const HomeScreenLayout layout = computeHomeScreenLayout(metrics, contentRect.height, menuCount);
|
||||||
|
|
||||||
|
coverRectX = contentRect.x;
|
||||||
|
coverRectY = metrics.homeTopPadding;
|
||||||
|
coverRectW = contentRect.width;
|
||||||
|
coverRectH = layout.recentTileHeight;
|
||||||
|
|
||||||
GUI.drawRecentBookCover(renderer,
|
GUI.drawRecentBookCover(renderer,
|
||||||
Rect{contentRect.x, metrics.homeTopPadding, contentRect.width, layout.recentTileHeight},
|
Rect{contentRect.x, metrics.homeTopPadding, contentRect.width, layout.recentTileHeight},
|
||||||
recentBooks, selectorIndex, coverRendered, coverBufferStored, bufferRestored,
|
recentBooks, selectorIndex, coverRendered, coverBufferStored, bufferRestored,
|
||||||
|
|||||||
@@ -41,6 +41,11 @@ class HomeActivity final : public Activity {
|
|||||||
bool coverBufferStored = false;
|
bool coverBufferStored = false;
|
||||||
size_t nextRecentCoverIndex = 0;
|
size_t nextRecentCoverIndex = 0;
|
||||||
uint8_t* coverBuffer = nullptr;
|
uint8_t* coverBuffer = nullptr;
|
||||||
|
size_t coverBufferSize = 0;
|
||||||
|
int coverRectX = 0;
|
||||||
|
int coverRectY = 0;
|
||||||
|
int coverRectW = 0;
|
||||||
|
int coverRectH = 0;
|
||||||
|
|
||||||
std::vector<RecentBook> recentBooks;
|
std::vector<RecentBook> recentBooks;
|
||||||
std::vector<MenuEntry> menuEntries;
|
std::vector<MenuEntry> menuEntries;
|
||||||
|
|||||||
Reference in New Issue
Block a user