From 8d8eace99c667f01bdf0e092229736821113c1b9 Mon Sep 17 00:00:00 2001 From: Jakub <106778416+MarekZegare4@users.noreply.github.com> Date: Mon, 6 Jul 2026 20:58:51 +0200 Subject: [PATCH] =?UTF-8?q?revert(eink):=20drop=20full=20refresh=20on=20sc?= =?UTF-8?q?reen=20change=20=E2=80=94=20too=20much=20black-flash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A full (non-partial) refresh on every screen change (638eea7b) turned out to be far too aggressive on real e-ink hardware: every navigation black-flashes, which is worse than the ghosting it was clearing. Remove the whole mechanism — DisplayDriver::forceFullRefresh() virtual, GxEPDDisplay's _force_full flag and override, the endFrame() branch, and the setCurrScreen() call. E-ink is back to interval-only full refreshes (Settings > Full refresh interval). The favourites "(gone)"-tile prune that shipped in the same commit is kept. Builds green: WioTrackerL1Eink_companion_solo_dual. Co-Authored-By: Claude Opus 4.8 --- examples/companion_radio/ui-new/UITask.cpp | 4 ---- release-notes.md | 1 - src/helpers/ui/DisplayDriver.h | 1 - src/helpers/ui/GxEPDDisplay.cpp | 6 +----- src/helpers/ui/GxEPDDisplay.h | 2 -- 5 files changed, 1 insertion(+), 13 deletions(-) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index a5b74d7e..4355365a 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -1923,10 +1923,6 @@ void UITask::setCurrScreen(UIScreen* c) { // that mistake is an inert no-op instead of a null deref in render()/poll(). if (!c) return; curr = c; - // E-ink: force a full refresh on the first frame of the new screen so leftover - // ghosting from the previous screen is cleared (the N-partials interval alone - // doesn't catch navigation). No-op on OLED. - if (_display) _display->forceFullRefresh(); c->onShow(); // central per-visit reset hook (see UIScreen::onShow) _next_refresh = 100; } diff --git a/release-notes.md b/release-notes.md index 84b65ae5..59f84b33 100644 --- a/release-notes.md +++ b/release-notes.md @@ -26,7 +26,6 @@ ### Under the hood - **OLED draws less** — the SH1106 driver now skips pushing a frame over I²C when it's byte-identical to the last one, cutting redundant traffic and a little power on the static screens (clock, home) that don't change between updates. -- **e-ink: cleaner screen changes** — switching screens now forces a full (non-partial) refresh on the first frame of the new screen, clearing leftover ghosting from the previous screen that the periodic partial-refresh interval didn't catch. ## MeshCore Solo Companion Firmware v1.21 diff --git a/src/helpers/ui/DisplayDriver.h b/src/helpers/ui/DisplayDriver.h index b57f818d..47220db1 100644 --- a/src/helpers/ui/DisplayDriver.h +++ b/src/helpers/ui/DisplayDriver.h @@ -272,7 +272,6 @@ public: virtual void setBrightness(uint8_t level) { } // level 0-4 (min to max), no-op default virtual void setDisplayRotation(uint8_t rot) { } // 0-3, no-op for fixed-orientation displays virtual void setFullRefreshInterval(uint8_t n) { } // e-ink: do full refresh every n partial refreshes (0=never) - virtual void forceFullRefresh() { } // e-ink: make the next frame a full (non-partial) refresh — clears ghosting on screen change; no-op on OLED virtual void endFrame() = 0; #ifdef ENABLE_SCREENSHOT diff --git a/src/helpers/ui/GxEPDDisplay.cpp b/src/helpers/ui/GxEPDDisplay.cpp index fa53bf01..5e45ac4a 100644 --- a/src/helpers/ui/GxEPDDisplay.cpp +++ b/src/helpers/ui/GxEPDDisplay.cpp @@ -275,14 +275,10 @@ void GxEPDDisplay::endFrame() { uint32_t crc = display_crc.finalize(); if (crc != last_display_crc_value) { bool partial = true; - // A forced full refresh (e.g. screen change) clears inter-screen ghosting. - // Short-circuit so _partial_count isn't bumped on the forced pass; the block - // resets it either way, matching the interval-driven full refresh. - if (_force_full || (_full_refresh_interval > 0 && ++_partial_count >= _full_refresh_interval)) { + if (_full_refresh_interval > 0 && ++_partial_count >= _full_refresh_interval) { partial = false; _partial_count = 0; } - _force_full = false; display.display(partial); last_display_crc_value = crc; } diff --git a/src/helpers/ui/GxEPDDisplay.h b/src/helpers/ui/GxEPDDisplay.h index 1372f540..c8837f48 100644 --- a/src/helpers/ui/GxEPDDisplay.h +++ b/src/helpers/ui/GxEPDDisplay.h @@ -64,7 +64,6 @@ class GxEPDDisplay : public DisplayDriver { int _text_sz = 1; uint8_t _full_refresh_interval = 0; uint8_t _partial_count = 0; - bool _force_full = false; // set by forceFullRefresh(); consumed by the next endFrame() int16_t drawLemonChar(int16_t x, int16_t y, uint32_t cp, int sc); uint8_t lemonXAdvance(uint32_t cp, int sc); @@ -145,6 +144,5 @@ public: } void setDisplayRotation(uint8_t rot) override; void setFullRefreshInterval(uint8_t n) override { _full_refresh_interval = n; _partial_count = 0; } - void forceFullRefresh() override { _force_full = true; } void endFrame() override; };