Skip to content

perf(vapor): store the GBA font as 1bpp and expand it at upload - #392

Open
lfkdsk wants to merge 1 commit into
pocket-stack:mainfrom
lfkdsk:fleet/vapor-gba-font-1bpp
Open

perf(vapor): store the GBA font as 1bpp and expand it at upload#392
lfkdsk wants to merge 1 commit into
pocket-stack:mainfrom
lfkdsk:fleet/vapor-gba-font-1bpp

Conversation

@lfkdsk

@lfkdsk lfkdsk commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

What

The GBA font table vp_font_tiles was emitted as 4bpp tiles (3040 B), which was 32.5% of the Todo ROM and 47.4% of the six-button ROM — larger than every code symbol combined. This change emits the font as 1bpp (760 B) and expands it into the 4bpp charblock inside upload_font at boot.

Measured

ROM before after delta
todo.gba 9356 B 7160 B −2196 B (−23.5%)
playdate-six-button.gba 6420 B 4224 B −2196 B (−34.2%)

Stable over 5 builds per side. The delta reconciles in the ELF symbol table: −2280 B of table, +84 B of expansion code. State RAM, overlay and reactive figures are unchanged.

Correctness

  • All 3040 bytes that reach the GBA font charblock are byte-identical to the old table, verified by booting the ROM in headless libmgba and dumping charblock 0 (SHA-256 955a983b…), not by re-implementing the expansion.
  • The existing GBA parity rig cannot see glyph pixels (it probes the screenblock at 0x6004000; glyphs live at 0x6000020), so this adds vapor/tests/gba-font.test.ts, which reads VRAM back from a booted ROM. Three runtime mutations (halfword order, ink/paper swap, row overrun) each make it fail while parity stays green.
  • GB, NES, ESP32 and Playdate generated C is byte-identical; GB/NES final ROMs are byte-identical. ESP32/Playdate final packages were not built locally (no SDK) and their embedded build IDs hash the changed shared vapor.h, so only generated-C identity is claimed for those two.
  • bun test vapor/tests/: 74 pass / 0 fail (was 71), including GBA, GB, NES and oracle parity.

Provenance

Produced by an autonomous fleet run: a Scout task measured the size baseline and proposed this candidate with a hand-patched prototype; a Builder implemented it; three independent cross-family reviews (different model families) rebuilt the ROMs, re-dumped VRAM and re-ran the mutations. The Scout report lives on the fork branch lfkdsk/pocketjs:fleet/scout-artifact-size; this PR carries only the implementation and its tests.

🤖 Generated with Claude Code

@lfkdsk
lfkdsk force-pushed the fleet/vapor-gba-font-1bpp branch from a0b5c3b to 1b452c1 Compare September 8, 2026 21:17
The GBA target expanded the 760 B 1bpp FONT8 bitmap into a 3040 B 4bpp
vp_font_tiles table at compile time, so every ROM carried 2280 B that the
runtime can rebuild. Emit the same 1bpp table ESP32 and Playdate already
use and expand it into VRAM inside upload_font, which already looped over
those halfwords.

todo.gba 9356 -> 7160 B (-2196, -23.47%), playdate-six-button.gba
6420 -> 4224 B (-2196, -34.21%), five identical measurement runs per side.
The saving reconciles in the symbol table: vp_font_tiles 3040 -> 760 B
minus 84 B of expansion code in main. GB, NES, ESP32 and Playdate
generated C is byte-identical and their ROMs compare equal.

All 3040 bytes reaching VRAM are unchanged, verified by dumping the font
charblock out of a booted ROM in headless libmgba rather than by
reimplementing the expansion in TS. That dump is the new
vapor/tests/gba-font.test.ts, which exists because GBA parity cannot see
this surface: its probe is the screenblock at 0x6004000, so it reads tile
indices and palette banks, never glyph pixels — with the two halfword
stores swapped, parity still passes 6/6 while the new test fails.

bun test vapor/tests/: 74 pass / 0 fail (71 baseline + 3), GBA, GB, NES
and oracle parity green.
@lfkdsk
lfkdsk force-pushed the fleet/vapor-gba-font-1bpp branch from 0683e71 to 0607a04 Compare September 8, 2026 21:20
@lfkdsk

lfkdsk commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current main (061c6be) and dropped the fork-only base commits, so the PR now contains only its own commit(s). bun test vapor/tests/ on the rebased branch matches main in this environment: everything passes except the NES parity build, which fails identically on unmodified main here (local ld65/cc65 library mismatch).

@lfkdsk
lfkdsk marked this pull request as ready for review September 8, 2026 23:07
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