Skip to content

fix(mhires): hysteresis on percell bg0 to damp background/letterbox $D021 flash#41

Merged
kfox merged 1 commit into
mainfrom
fix/mhires-percell-bg0-hysteresis
Jun 24, 2026
Merged

fix(mhires): hysteresis on percell bg0 to damp background/letterbox $D021 flash#41
kfox merged 1 commit into
mainfrom
fix/mhires-percell-bg0-hysteresis

Conversation

@kfox

@kfox kfox commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Problem

In palette_mode = "percell" (the MultiHires default), 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 (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 bg0 sticky with relative hysteresis (BG0_HYSTERESIS_MARGIN = 0.25): keep the current bg0 unless a challenger's smoothed count beats it by the margin. A sustained dominant-colour shift still moves bg0 (a real blue scene eventually turns the bars blue); a bg0 that 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 pin bg0 deterministically. 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

  • New PercellBg0HysteresisTest (2 cases): a slight/sustained majority does not flip bg0; an overwhelming sustained change still does.
  • Full suite green (1573 tests); ruff + pyright clean; pre-commit hooks pass.
  • HW-verified on TeensyROM over serial — measurable improvement in the background/bar flash.

…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.
@kfox kfox merged commit eff769c into main Jun 24, 2026
6 checks passed
@kfox kfox deleted the fix/mhires-percell-bg0-hysteresis branch June 24, 2026 15:34
@codecov

codecov Bot commented Jun 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.59%. Comparing base (29487b0) to head (08d06de).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

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.
📢 Have feedback on the report? Share it here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant