prometeu-runtime/discussion/lessons/DSC-0037-rgba8888-framebuffer-and-pixel-format-direction/LSN-0046-pixel-format-contracts-must-move-as-one-surface.md
2026-05-23 22:17:40 +01:00

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.