Skip to content

fix(st7789): improve PWM backlight dimming color accuracy - #4

Merged
dzo merged 1 commit into
a159x36:esp-develop-9.2from
MicroPythonOS:improve-pwm-brightness-colors
Apr 2, 2026
Merged

dzo merged 1 commit into
a159x36:esp-develop-9.2from
MicroPythonOS:improve-pwm-brightness-colors

Conversation

@ThomasFarstrike

@ThomasFarstrike ThomasFarstrike commented Feb 27, 2026 •

Copy link
Copy Markdown

Original code expanded RGB565 to 8-bit channels, multiplied with truncating division (/256), then shifted back, causing consistent darkening and minor hue errors, especially noticeable at 40–80% brightness.

Improved version:

  • Extracts components in native precision: 5-bit red/blue, 6-bit green
  • Scales with proper rounding: (val * backlight + 127) >> 8
  • Packs directly back to RGB565 format

Improves visual quality dramatically:

  • Grays/whites stay neutral instead of going too dark or greenish
  • Better preservation of shadow detail
  • More natural fade-to-black behavior overall

Before:

90p_brightness_default_scroll

at 90% brightness, the gray and blue turned greenish

After:
90p_brightness_fixed_scroll

at 90% brightness, all the colors look as they should

…ss bias

Original code expanded RGB565 to 8-bit channels, multiplied with truncating
division (/256), then shifted back — causing consistent darkening and minor
hue errors, especially noticeable at 40–80% brightness.

Improved version:
- Extracts components in native precision: 5-bit red/blue, 6-bit green
- Scales with proper rounding: (val * backlight + 127) >> 8
- Packs directly back to RGB565 format

Improves visual quality dramatically:
- Grays/whites stay neutral instead of going too dark or greenish
- Better preservation of shadow detail
- More natural fade-to-black behavior overall
@ThomasFarstrike

Copy link
Copy Markdown
Author

Again, this work was done by the https://micropythonos.com/ team to allow running a normal MicroPythonOS build (which works on many boards, including the LilyGo T-Display-S3) on an emulated esp32s3.

Thank you for all your work on QEMU!

@dzo dzo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I hadn't noticed this.

@dzo
dzo merged commit aaaff40 into a159x36:esp-develop-9.2 Apr 2, 2026
6 checks passed
ThomasFarstrike added a commit to ThomasFarstrike/retro-go that referenced this pull request Jun 9, 2026
The path VBE_setPalette -> SDL_SetColors converted Duke3D's 6-bit palette
values through an unnecessary 8-bit intermediate, creating an asymmetric
precision issue analogous to the QEMU st7789 backlight fix (a159x36/qemu#4):

  Old: r6/b6 -> 8-bit via (v<<2)|(v>>4) -> >>3 -> r5  (net: v6>>1, floor)
       g6    -> 8-bit via (v<<2)|(v>>4) -> >>2 -> g6  (net: identity, lossless)

For any palette entry with odd source values, R5=B5=floor(v/2)=0 while
G6=v remains non-zero — producing a pure-green pixel instead of near-black.
This is visible as a greenish cast in dark/shadowed areas.

Fix: add SDL_SetPalette565() which converts directly from the 6-bit source,
zeroing the green LSB to give it the same effective 5-bit precision as R/B:

  r5 = v6 >> 1
  g6 = (v6 >> 1) << 1   // 5-bit precision in the 6-bit RGB565 green field
  b5 = v6 >> 1

For neutral input (r=g=b=val): r5/31 == (g6>>1)/31 == b5/31 -> neutral gray.
At full brightness (val=63): r5=31, g6=62, b5=31 — green is 1/63 (~1.6%) shy
of maximum, which is perceptually indistinguishable.

Also removes the 1KB static SDL_Color fmt_swap[256] intermediate buffer and
the SDL_SetColors() call, reducing per-palette-update work by ~50%.
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.

2 participants