fix(uc8279-x4): HALF was a plain DU partial, not a clean - #56
Closed
alexanderbsd wants to merge 1 commit into
Closed
fix(uc8279-x4): HALF was a plain DU partial, not a clean#56alexanderbsd wants to merge 1 commit into
alexanderbsd wants to merge 1 commit into
Conversation
displayStart() classified the refresh with
const bool fast = (mode != RefreshMode::Full) && !_needFullClear && _oldPlaneValid;
so RefreshMode::Half fell into the partial path and became
indistinguishable from Fast: same DU CDI (0xD7), same forced temperature
(0x5A), same PFS/gate-scan re-assert, same PTIN/PTL window.
Every caller that asks for HALF is asking for a clean. In CrossPoint that
is the reader's periodic refresh cycle, every sleep-screen paint, and the
manual power-button refresh. On this driver none of them cleaned
anything, and a true FULL is only reached at boot/wake or from the
control-centre refresh tile, so nothing scrubbed the panel during a
session.
The failure mode is the one the UC8179 sibling documents: an unchanged
pixel pairs (white, white), selects WW, and idles with whatever charge an
earlier page parked under it. That charge is invisible at first and
surfaces over the following seconds, then compounds because nothing ever
clears it.
Give HALF the sibling's charge scrub (Uc8179Driver::displayStart): the
GC-class setup with the OLD plane written as the target's COMPLEMENT, so
every pixel is forced into a real transition cell and driven to its
endpoint. _needFullClear and !_oldPlaneValid still route to the
white-seeded absolute GC, so the first paint after boot or wake keeps
clearing whatever is physically on the panel.
Confirmed on an Xteink X4 Pro (UC8279 800x480, LUT_VER=0x02): the
ghosting that built up across a reading session and bloomed into the
sleep screen is gone. HALF now costs a real waveform, so the periodic
refresh cycle and sleep entry flash where they previously did not — that
is the behaviour those callers already assumed they were getting.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VNSi6FM8Yebueuv31hFkqz
Contributor
|
Thanks for your work on this @alexanderbsd. It encouraged me to take another look at the driver and I worked with a user on reddit and implemented this fix plus a bunch of others in the process. Going to close as already solved but this pushed me to take another look at the driver so I appreciate it |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
Uc8279X4Driver::displayStart()classified the refresh with:RefreshMode::Halfsatisfiesmode != Full, so it fell into the partial path and became indistinguishable fromFast— same DU CDI (0xD7), same forced temperature (0x5A), same PFS/gate-scan re-assert, same PTIN/PTL window. There was no code path on this driver where HALF did anything a FAST didn't.That matters because HALF is what consumers use everywhere they believe they're cleaning the panel. In CrossPoint Reader that's the reader's periodic refresh cycle (
ReaderUtils::displayWithRefreshCycle, default every 15 pages), every sleep-screen paint (all eightSleepActivityvariants), and the manual power-button refresh. None of them cleaned anything here. A trueFULLis only reached at boot/wake (requestResync) or from the control-centre refresh tile, so nothing scrubbed the panel during a session.The failure mode is the one the UC8179 sibling already documents:
Latent charge is invisible at first and surfaces over the following seconds, then compounds because nothing ever clears it.
The fix
Give HALF the sibling's charge scrub (
Uc8179Driver::displayStart): the GC-class setup with the OLD plane written as the target's complement, so every pixel is forced into a real transition cell and driven to its endpoint.The complement-write already existed in this file for dark-background content; this just triggers it for HALF too.
One deliberate difference from the UC8179 sibling:
_needFullClearand!_oldPlaneValidstill route to the white-seeded absolute GC rather than the scrub, so the first paint after boot or wake keeps clearing whatever is physically on the panel. The sibling gives scrub priority there.Testing
Confirmed on an Xteink X4 Pro, probe-promoted to UC8279 800x480,
LUT_VER=0x02:Symptom before: a screen painted clean and dark, then residue of the previous content bloomed back in over a few seconds, worsening across a session — reader pages, menus, cover art, and most visibly the sleep screen. After: gone.
Builds clean in the consumer (
crosspoint-reader) acrossx4pro,default(C3, X4+X3) andsticky.Tradeoff worth flagging
HALF now costs a real waveform, so the periodic refresh cycle and sleep entry flash where they previously did not. That is the behaviour those callers already assumed they were getting, and it makes the consumer's "refresh frequency" setting meaningful on this panel — it previously had no effect at all.
If you'd prefer something gentler, the alternative is to keep HALF as a DU partial but write the OLD plane inverted (re-driving every pixel without the GC flash). I have no evidence that scrubs hard enough, and the sibling driver chose the strong version for this exact role, so I went with parity. Happy to switch if you'd rather.
I only have UC8279
LUT_VER=0x02hardware — a second pair of eyes on0x68/0x69units would be welcome.🤖 Generated with Claude Code
https://claude.ai/code/session_01VNSi6FM8Yebueuv31hFkqz