implements PLN-0067
This commit is contained in:
parent
4d5818c244
commit
1256d33a72
@ -35,4 +35,4 @@
|
||||
{"type":"discussion","id":"DSC-0032","status":"done","ticket":"system-os-lifecycle-process-task-contract","title":"Agenda - SystemOS Lifecycle, Process and Task Contract","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","lifecycle","process","task","shell","firmware"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0041","file":"discussion/lessons/DSC-0032-system-os-lifecycle-process-task-contract/LSN-0041-systemos-lifecycle-authority.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]}
|
||||
{"type":"discussion","id":"DSC-0033","status":"done","ticket":"system-os-service-ownership-and-module-layout","title":"Agenda - SystemOS Service Ownership and Module Layout","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","services","module-layout","vm","window-manager","logging"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0042","file":"discussion/lessons/DSC-0033-system-os-service-ownership-and-module-layout/LSN-0042-systemos-service-ownership-boundary.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]}
|
||||
{"type":"discussion","id":"DSC-0036","status":"done","ticket":"prometeu-hub-ui-direction","title":"Agenda - Prometeu Hub UI Direction","created_at":"2026-05-15","updated_at":"2026-05-22","tags":["hub","ui","shell","system-apps","lifecycle","design-system"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0045","file":"discussion/lessons/DSC-0036-prometeu-hub-ui-direction/LSN-0045-hub-ui-slices-should-prove-os-boundaries.md","status":"done","created_at":"2026-05-22","updated_at":"2026-05-22"}]}
|
||||
{"type":"discussion","id":"DSC-0037","status":"in_progress","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[{"id":"AGD-0037","file":"AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md","status":"accepted","created_at":"2026-05-22","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0029","file":"DEC-0029-rgba8888-runtime-pixel-format-contract.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0037"}],"plans":[{"id":"PLN-0067","file":"PLN-0067-rgba8888-published-contracts-and-specs.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0068","file":"PLN-0068-rgba8888-color-type-hal-and-abi-surface.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0069","file":"PLN-0069-rgba8888-cpu-renderer-and-composition.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0070","file":"PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0071","file":"PLN-0071-rgba8888-host-presentation-path.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0072","file":"PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]}],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0037","status":"in_progress","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[{"id":"AGD-0037","file":"AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md","status":"accepted","created_at":"2026-05-22","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0029","file":"DEC-0029-rgba8888-runtime-pixel-format-contract.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0037"}],"plans":[{"id":"PLN-0067","file":"PLN-0067-rgba8888-published-contracts-and-specs.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0068","file":"PLN-0068-rgba8888-color-type-hal-and-abi-surface.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0069","file":"PLN-0069-rgba8888-cpu-renderer-and-composition.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0070","file":"PLN-0070-rgba8888-asset-palettes-tooling-and-fixtures.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0071","file":"PLN-0071-rgba8888-host-presentation-path.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]},{"id":"PLN-0072","file":"PLN-0072-rgba8888-residue-removal-and-end-to-end-validation.md","status":"open","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0029"]}],"lessons":[]}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
id: PLN-0067
|
||||
ticket: rgba8888-framebuffer-and-pixel-format-direction
|
||||
title: RGBA8888 Published Contracts and Specs
|
||||
status: open
|
||||
status: done
|
||||
created: 2026-05-23
|
||||
ref_decisions: [DEC-0029]
|
||||
tags: [gfx, framebuffer, rgb565, rgba8888, renderer, assets, host, backend]
|
||||
|
||||
@ -35,7 +35,7 @@ These are treated as VM values with stable layout semantics.
|
||||
| Type | Description |
|
||||
| ------- | --------------------------------- |
|
||||
| `vec2` | 2D vector (x, y) |
|
||||
| `color` | Packed color value |
|
||||
| `color` | Packed RGBA8888 color value |
|
||||
| `pixel` | Combination of position and color |
|
||||
|
||||
These values:
|
||||
@ -44,6 +44,9 @@ These values:
|
||||
- are copied by value;
|
||||
- do not require heap allocation by themselves.
|
||||
|
||||
The canonical `color` raw channel order is RGBA. RGB565 is not a public VM
|
||||
color contract.
|
||||
|
||||
### Heap values
|
||||
|
||||
Heap-resident entities are referenced indirectly through handles.
|
||||
|
||||
@ -29,13 +29,20 @@ It is an explicit 2D graphics device based on:
|
||||
|
||||
### Pixel format
|
||||
|
||||
- **RGB565**
|
||||
- 5 bits Red
|
||||
- 6 bits Green
|
||||
- 5 bits Blue
|
||||
- no alpha channel
|
||||
- **RGBA8888**
|
||||
- 8 bits Red
|
||||
- 8 bits Green
|
||||
- 8 bits Blue
|
||||
- 8 bits Alpha
|
||||
- canonical raw channel order: **RGBA**
|
||||
|
||||
Transparency is handled via **color key**.
|
||||
The framebuffer alpha channel may carry meaningful runtime output. The runtime
|
||||
MUST NOT force the published front buffer alpha channel to `255` as a blanket
|
||||
contract.
|
||||
|
||||
Color values in the runtime, HAL, host-facing framebuffer, and GFX ABI are
|
||||
logical RGBA8888 values. RGB565 is not a supported runtime framebuffer,
|
||||
palette, host presentation, or compatibility contract.
|
||||
|
||||
---
|
||||
|
||||
@ -232,16 +239,21 @@ Normative boundary:
|
||||
|
||||
---
|
||||
|
||||
## 12. Transparency (Color Key)
|
||||
## 12. Transparency
|
||||
|
||||
- One RGB565 value is reserved as TRANSPARENT_KEY
|
||||
- Pixels with this color are not drawn
|
||||
Transparency is represented by the alpha channel of the resolved RGBA8888
|
||||
color.
|
||||
|
||||
Palette indices are ordinary indices. The runtime MUST NOT reserve palette
|
||||
index `0` as a special transparent index. A palette entry may still be authored
|
||||
as transparent by setting its alpha channel to `0`, but that is ordinary palette
|
||||
data rather than a special index rule.
|
||||
|
||||
```
|
||||
if src == TRANSPARENT_KEY:
|
||||
if resolved_color.alpha == 0:
|
||||
skip
|
||||
else:
|
||||
draw
|
||||
draw_or_blend(resolved_color)
|
||||
```
|
||||
|
||||
|
||||
@ -259,8 +271,9 @@ Official modes:
|
||||
- `BLEND_HALF_MINUS`
|
||||
- `BLEND_FULL`
|
||||
|
||||
No continuous alpha.
|
||||
No arbitrary blending.
|
||||
Alpha is available through RGBA8888 colors. Discrete blend modes remain part of
|
||||
the classic GFX contract, and later optimization work may specialize opaque,
|
||||
masked, and alpha paths.
|
||||
|
||||
Everything is:
|
||||
|
||||
@ -283,12 +296,13 @@ Everything is:
|
||||
|
||||
By design:
|
||||
|
||||
- Continuous alpha
|
||||
- RGBA framebuffer
|
||||
- Shaders
|
||||
- Modern GPU pipeline
|
||||
- HDR
|
||||
- Gamma correction
|
||||
- RGB565 compatibility framebuffers
|
||||
- multi-format backend selection
|
||||
- render-thread ownership as part of this contract
|
||||
|
||||
---
|
||||
|
||||
@ -314,8 +328,7 @@ controls:
|
||||
|
||||
In v1, deferred `gfx.*` overlay/debug primitives are drained after both fades and therefore are not themselves part of scene or HUD fade application.
|
||||
|
||||
The fade is implemented without continuous per-pixel alpha and without floats.
|
||||
It uses a **discrete integer level** (0..31), which in practice produces an
|
||||
The fade uses a **discrete integer level** (0..31), which in practice produces an
|
||||
"almost continuous" visual result in Prometeu's `480x270` pixel-art framebuffer.
|
||||
|
||||
---
|
||||
@ -327,32 +340,32 @@ Each fade is represented by:
|
||||
- `fade_level: u8` in the range **[0..31]**
|
||||
- `0` → fully replaced by the fade color
|
||||
- `31` → fully visible (no fade)
|
||||
- `fade_color: RGB565`
|
||||
- `fade_color: RGBA8888`
|
||||
- color the image will be blended into
|
||||
|
||||
Registers:
|
||||
|
||||
- `SCENE_FADE_LEVEL` (0..31)
|
||||
- `SCENE_FADE_COLOR` (RGB565)
|
||||
- `SCENE_FADE_COLOR` (RGBA8888)
|
||||
- `HUD_FADE_LEVEL` (0..31)
|
||||
- `HUD_FADE_COLOR` (RGB565)
|
||||
- `HUD_FADE_COLOR` (RGBA8888)
|
||||
|
||||
Common cases:
|
||||
|
||||
- Fade-out: `fade_color = BLACK`
|
||||
- Flash/teleport: `fade_color = WHITE`
|
||||
- Special effects: any RGB565 color
|
||||
- Special effects: any RGBA8888 color
|
||||
|
||||
---
|
||||
|
||||
### 17.2 Fade Operation (Blending with Arbitrary Color)
|
||||
|
||||
For each RGB565 pixel `src` and fade color `fc`, the final pixel `dst` is calculated per channel.
|
||||
For each RGBA8888 pixel `src` and fade color `fc`, the final pixel `dst` is calculated per channel.
|
||||
|
||||
1) Extract components:
|
||||
|
||||
- `src_r5`, `src_g6`, `src_b5`
|
||||
- `fc_r5`, `fc_g6`, `fc_b5`
|
||||
- `src_r8`, `src_g8`, `src_b8`, `src_a8`
|
||||
- `fc_r8`, `fc_g8`, `fc_b8`, `fc_a8`
|
||||
|
||||
2) Apply integer blending:
|
||||
|
||||
@ -360,17 +373,18 @@ For each RGB565 pixel `src` and fade color `fc`, the final pixel `dst` is calcul
|
||||
src_weight = fade_level // 0..31
|
||||
fc_weight = 31 - fade_level
|
||||
|
||||
r5 = (src_r5 * src_weight + fc_r5 * fc_weight) / 31
|
||||
g6 = (src_g6 * src_weight + fc_g6 * fc_weight) / 31
|
||||
b5 = (src_b5 * src_weight + fc_b5 * fc_weight) / 31
|
||||
r8 = (src_r8 * src_weight + fc_r8 * fc_weight) / 31
|
||||
g8 = (src_g8 * src_weight + fc_g8 * fc_weight) / 31
|
||||
b8 = (src_b8 * src_weight + fc_b8 * fc_weight) / 31
|
||||
a8 = (src_a8 * src_weight + fc_a8 * fc_weight) / 31
|
||||
```
|
||||
- `src_r5`, `src_g6`, `src_b5`
|
||||
- `fc_r5`, `fc_g6`, `fc_b5`
|
||||
- `src_r8`, `src_g8`, `src_b8`, `src_a8`
|
||||
- `fc_r8`, `fc_g8`, `fc_b8`, `fc_a8`
|
||||
|
||||
3) Repack:
|
||||
|
||||
```
|
||||
dst = pack_rgb565(r5, g6, b5)
|
||||
dst = pack_rgba8888_rgba(r8, g8, b8, a8)
|
||||
```
|
||||
|
||||
|
||||
@ -425,8 +439,8 @@ Each pixel of a tile or sprite is:
|
||||
|
||||
Fixed rule:
|
||||
|
||||
- Index `0` = TRANSPARENT
|
||||
- Indices `1..15` = valid palette colors
|
||||
- Indices `0..15` are ordinary valid palette indices
|
||||
- Transparency comes from the alpha channel of the resolved palette entry
|
||||
|
||||
---
|
||||
|
||||
@ -437,13 +451,13 @@ Each **Tile Bank** contains:
|
||||
- **64 palettes** in runtime-facing v1
|
||||
- Each palette has:
|
||||
- **16 colors**
|
||||
- each color in **RGB565 (`u16`, little-endian in serialized assets)**
|
||||
- each color in **RGBA8888** with canonical RGBA channel order
|
||||
|
||||
Size:
|
||||
|
||||
- 1 palette = 16 × 2 bytes = **32 bytes**
|
||||
- 64 palettes = **2 KB per bank**
|
||||
- 16 banks = **32 KB maximum palettes**
|
||||
- 1 palette = 16 × 4 bytes = **64 bytes**
|
||||
- 64 palettes = **4 KB per bank**
|
||||
- 16 banks = **64 KB maximum palettes**
|
||||
|
||||
---
|
||||
|
||||
@ -496,22 +510,22 @@ Runtime-facing validity rule for v1:
|
||||
The pipeline works like this:
|
||||
|
||||
1. Read indexed pixel from tile (value 0..15)
|
||||
2. If index == 0 → transparent pixel
|
||||
3. Otherwise:
|
||||
2. Resolve:
|
||||
- real_color = palette[palette_id][index]
|
||||
4. Apply:
|
||||
3. Apply:
|
||||
- flip
|
||||
- discrete blend
|
||||
- alpha/skip behavior from the resolved RGBA8888 color
|
||||
- writing to back buffer
|
||||
|
||||
In other words:
|
||||
```
|
||||
pixel_index = tile_pixel(x,y)
|
||||
if pixel_index == 0:
|
||||
color = bank.palettes[palette_id][pixel_index]
|
||||
if color.alpha == 0:
|
||||
skip
|
||||
else:
|
||||
color = bank.palettes[palette_id][pixel_index]
|
||||
draw(color)
|
||||
draw_or_blend(color)
|
||||
```
|
||||
|
||||
---
|
||||
@ -578,7 +592,6 @@ Fault boundary:
|
||||
| `gfx.draw_disc` | `void` | no real operational failure path in v1 |
|
||||
| `gfx.draw_square` | `void` | no real operational failure path in v1 |
|
||||
| `gfx.draw_text` | `void` | no real operational failure path in v1 |
|
||||
| `gfx.clear_565` | `void` | no real operational failure path in v1 |
|
||||
| `composer.bind_scene` | `status:int` | status-returning API, but missing scene glyph dependencies are fatal runtime errors |
|
||||
| `composer.unbind_scene` | `status:int` | explicit orchestration-domain operational result |
|
||||
| `composer.set_camera` | `void` | no real operational failure path in v1 |
|
||||
|
||||
@ -116,7 +116,7 @@ Hardware differences:
|
||||
|
||||
The graphics system:
|
||||
|
||||
- operates on a logical framebuffer
|
||||
- operates on a logical RGBA8888 framebuffer
|
||||
- uses an indexed palette
|
||||
- does not depend on a specific GPU
|
||||
|
||||
@ -127,6 +127,10 @@ The platform layer:
|
||||
- **may overlay technical HUDs without modifying the logical framebuffer**
|
||||
- may transport the logical framebuffer into a host presentation surface where a host-only overlay layer is composed
|
||||
|
||||
The host presentation layer MUST treat RGBA8888 as the canonical logical
|
||||
framebuffer format. RGB565 conversion is not part of the normal host
|
||||
presentation contract.
|
||||
|
||||
Host presentation SHOULD be driven by published logical frames and explicit host-owned invalidation, not by perpetual redraw polling.
|
||||
|
||||
In particular:
|
||||
|
||||
@ -114,7 +114,7 @@ For `BankType::GLYPH`, the v1 runtime-facing contract is:
|
||||
|
||||
- `codec = NONE`
|
||||
- serialized pixels use packed `u4` palette indices
|
||||
- serialized palettes use `RGB565` (`u16`, little-endian)
|
||||
- serialized palettes use `RGBA8888` with canonical RGBA channel order
|
||||
- `palette_count = 64`
|
||||
- runtime materialization may expand pixel indices to one `u8` per pixel
|
||||
|
||||
@ -152,18 +152,25 @@ Validation rules for `GLYPH` v1:
|
||||
#### 4.1.2 Payload Layout
|
||||
|
||||
1. packed indexed pixels for the full sheet, using `ceil(width * height / 2)` bytes;
|
||||
2. palette table, using `palette_count * 16 * 2` bytes.
|
||||
2. palette table, using `palette_count * 16 * 4` bytes.
|
||||
|
||||
The tile-bank payload therefore separates serialized storage form from runtime memory form:
|
||||
|
||||
- serialized pixel plane: packed `4bpp`
|
||||
- decoded pixel plane: expanded `u8` indices, one entry per pixel
|
||||
- palette table: `64 * 16` colors in `RGB565`
|
||||
- palette table: `64 * 16` colors in RGBA8888 channel order
|
||||
|
||||
For `GLYPH` v1:
|
||||
|
||||
- `size` must match `ceil(width * height / 2) + (palette_count * 16 * 2)`
|
||||
- `decoded_size` must match `(width * height) + (palette_count * 16 * 2)`
|
||||
- `size` must match `ceil(width * height / 2) + (palette_count * 16 * 4)`
|
||||
- `decoded_size` must match `(width * height) + (palette_count * 16 * 4)`
|
||||
|
||||
RGB565 palette payloads are not compatible runtime input. Existing assets with
|
||||
two-byte RGB565 palette entries must be regenerated or converted by tooling
|
||||
before they are loaded by the runtime.
|
||||
|
||||
Palette indices are ordinary indices. Transparency is represented by the alpha
|
||||
channel of the resolved RGBA8888 palette entry, not by reserving index `0`.
|
||||
|
||||
### 4.2 `SCENE` asset contract in v1
|
||||
|
||||
|
||||
@ -220,6 +220,30 @@ For `asset.load`:
|
||||
- JSON-on-the-wire bank inspection payloads are not valid public ABI;
|
||||
- `bank.info` returns stack values, not textual structured payloads.
|
||||
|
||||
### GFX surface (`gfx`, v1)
|
||||
|
||||
The public GFX ABI uses format-neutral operation names. API and syscall names
|
||||
MUST NOT encode RGB565 or any other pixel format suffix.
|
||||
|
||||
Canonical operations in v1 include:
|
||||
|
||||
- `gfx.clear(color) -> void`
|
||||
- `gfx.fill_rect(x, y, w, h, color) -> void`
|
||||
- `gfx.draw_line(x0, y0, x1, y1, color) -> void`
|
||||
- `gfx.draw_circle(x, y, radius, color) -> void`
|
||||
- `gfx.draw_disc(x, y, radius, color) -> void`
|
||||
- `gfx.draw_square(x, y, size, color) -> void`
|
||||
- `gfx.draw_text(x, y, text, color) -> void`
|
||||
|
||||
Rules:
|
||||
|
||||
- `color` arguments are packed RGBA8888 values using RGBA channel order.
|
||||
- RGB565 raw values are not a public ABI contract.
|
||||
- `Gfx*565` syscall names and `gfx.*_565` canonical identities are not valid
|
||||
current ABI.
|
||||
- The runtime framebuffer exposed across the host boundary is RGBA8888, not
|
||||
`u16` RGB565.
|
||||
|
||||
### Composition surface (`composer`, v1)
|
||||
|
||||
The canonical frame-orchestration public ABI uses module `composer`.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user