fix(mhires): hysteresis on percell bg0 to damp background/letterbox $D021 flash#41
Merged
Merged
Conversation
…D021 flash In palette_mode="percell", bg0 (the global %00 colour, written to $D021) was picked each frame as the raw argmax of the EMA-smoothed palette counts. On near-tied content — a mostly-black frame with a bright moment, or letterboxed/pillarboxed video whose bars quantize to black — the argmax flip-flops frame-to-frame, strobing every %00 pixel (background + bars) a different colour. It's a single instant register change (not a write tear), so it's especially visible on a slow transport (TeensyROM serial) where the rest of the frame lags. Make bg0 sticky: keep the current bg0 unless a challenger's smoothed count beats it by BG0_HYSTERESIS_MARGIN (25%). A sustained dominant-colour shift still moves bg0; a vanished bg0 (smoothed count -> ~0) is never sticky, so it can't get stuck on an absent colour. Reduces the flash (HW-verified on TeensyROM over serial); the residual is the separate per-cell screen/color-RAM bus-DMA tear, which only double-buffering or a lower frame rate addresses.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #41 +/- ##
==========================================
+ Coverage 79.57% 79.59% +0.02%
==========================================
Files 68 68
Lines 12861 12870 +9
Branches 1898 1899 +1
==========================================
+ Hits 10234 10244 +10
Misses 2188 2188
+ Partials 439 438 -1 ☔ View full report in Codecov by Harness. |
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.
Problem
In
palette_mode = "percell"(the MultiHires default),bg0— the global%00colour written to$D021— was picked each frame as the rawargmaxof the EMA-smoothed palette counts. On near-tied content (a mostly-black frame with a bright moment, or letterboxed/pillarboxed video whose bars quantize to black) theargmaxflip-flops frame-to-frame, strobing every%00pixel (the background and the letterbox/pillarbox bars) a different colour for a frame. It's a single instant register change — not a screen/color/bitmap write tear — so it's especially visible on a slow transport (TeensyROM serial) where the rest of the frame lags behind.Fix
Make
bg0sticky with relative hysteresis (BG0_HYSTERESIS_MARGIN = 0.25): keep the currentbg0unless a challenger's smoothed count beats it by the margin. A sustained dominant-colour shift still movesbg0(a real blue scene eventually turns the bars blue); abg0that vanishes from the frame (smoothed count → ~0) is never sticky, so it can't get stuck on an absent colour.This is independent of
palette_mode's slot allocation and only touches the percell path; cheap/vivid/grayscale already pinbg0deterministically. This is not a perfect fix, but does reduce the bg flashes.Scope / residual
Reduces the flash; it does not eliminate all motion artifacts. The remaining per-cell "sparkle" is the separate non-atomic screen/color/bitmap bus-DMA tear, which only host-DMA double-buffering or a lower frame rate addresses (tracked separately).
Verification
PercellBg0HysteresisTest(2 cases): a slight/sustained majority does not flipbg0; an overwhelming sustained change still does.