79 lines
3.3 KiB
Markdown
79 lines
3.3 KiB
Markdown
---
|
|
id: LSN-0046
|
|
ticket: rgba8888-framebuffer-and-pixel-format-direction
|
|
title: Pixel Format Contracts Must Move as One Surface
|
|
created: 2026-05-23
|
|
tags: [gfx, framebuffer, rgba8888, abi, assets, host]
|
|
decision: DEC-0029
|
|
---
|
|
|
|
## Context
|
|
|
|
The runtime migrated its graphics contract from RGB565 to RGBA8888. The
|
|
important discovery was that RGB565 was not only a renderer storage detail. It
|
|
had become a cross-cutting contract spanning VM values, syscalls, HAL types,
|
|
renderer buffers, asset palette bytes, host presentation, tests, and specs.
|
|
|
|
Treating the change as a local buffer replacement would have left contradictory
|
|
contracts behind. The successful migration split the work into small plans, but
|
|
each plan still respected one global rule: a pixel format is a published
|
|
surface, not an implementation token.
|
|
|
|
## Key Decisions
|
|
|
|
### RGBA8888 Runtime Pixel Format Contract
|
|
|
|
**What:** RGBA8888 became the single logical color and physical framebuffer
|
|
contract. RGB565 compatibility surfaces were removed instead of deprecated as
|
|
canonical aliases.
|
|
|
|
**Why:** Keeping RGB565 as compatibility would have preserved the old coupling
|
|
between logical color, framebuffer storage, asset palette encoding, and host
|
|
presentation. A single RGBA8888 contract made the runtime easier to reason
|
|
about and aligned with alpha-capable UI and modern host presentation.
|
|
|
|
**Trade-offs:** The migration intentionally broke existing RGB565 assets and
|
|
tests. It also doubled framebuffer byte width. The payoff was removing support
|
|
for two simultaneous color models and making alpha an ordinary property of
|
|
color instead of a special case.
|
|
|
|
## Patterns and Algorithms
|
|
|
|
Move published contracts before code. Specs, ABI docs, and public docs were
|
|
updated first so implementation work had a stable target.
|
|
|
|
Keep API names format-neutral when the runtime supports only one format.
|
|
Names such as `GfxClear565` create permanent compatibility residue. The
|
|
canonical surface should be `GfxClear`; RGBA8888 is the contract behind it.
|
|
|
|
Use the alpha channel as data, not a magic index. Palette indices are ordinary
|
|
indices. Transparency is represented by the RGBA alpha channel of the resolved
|
|
palette entry rather than by reserving palette index `0`.
|
|
|
|
Validate with residue scans. The final pass searched for RGB565, `Gfx*565`,
|
|
RGB565 palette sizing, host conversion helpers, and `u16` framebuffer surfaces.
|
|
Remaining hits had to be negative documentation or unrelated `u16` usage.
|
|
|
|
## Pitfalls
|
|
|
|
Pixel format names leak into places that look unrelated: generator fixtures,
|
|
cartridge payload size calculations, syscall metadata, host copy utilities, and
|
|
test assembly snippets.
|
|
|
|
Endian assumptions are easy to hide when using `u32`. The contract must say
|
|
RGBA channel order explicitly, and host presentation code must unpack channels
|
|
by shifts instead of relying on native memory layout.
|
|
|
|
Compatibility helpers are useful only as short-lived scaffolding. If they are
|
|
left in normal paths, they become a second contract.
|
|
|
|
## Takeaways
|
|
|
|
- A framebuffer format is a runtime-wide contract once it reaches ABI, assets,
|
|
host presentation, or tests.
|
|
- Format-suffixed public APIs should be removed when the format is no longer a
|
|
selectable backend.
|
|
- Alpha should be modeled as color data, not as a reserved palette index.
|
|
- A staged migration can still enforce one final contract when each plan has a
|
|
residue scan and acceptance criteria.
|